@evolu/common 8.4.0 → 8.5.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.
Files changed (74) hide show
  1. package/dist/src/Array.d.ts +24 -0
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +27 -1
  4. package/dist/src/Assert.d.ts.map +1 -1
  5. package/dist/src/Assert.js +1 -0
  6. package/dist/src/LeakDetector.d.ts.map +1 -1
  7. package/dist/src/LeakDetector.js +4 -1
  8. package/dist/src/Lookup.js +1 -0
  9. package/dist/src/Platform.js +1 -0
  10. package/dist/src/Relation.js +3 -3
  11. package/dist/src/Resource.d.ts.map +1 -1
  12. package/dist/src/Resource.js +9 -3
  13. package/dist/src/Result.d.ts.map +1 -1
  14. package/dist/src/Result.js +3 -5
  15. package/dist/src/Sqlite.d.ts.map +1 -1
  16. package/dist/src/Sqlite.js +9 -7
  17. package/dist/src/Store.d.ts.map +1 -1
  18. package/dist/src/Store.js +3 -1
  19. package/dist/src/String.d.ts.map +1 -1
  20. package/dist/src/String.js +1 -1
  21. package/dist/src/Task.d.ts +122 -60
  22. package/dist/src/Task.d.ts.map +1 -1
  23. package/dist/src/Task.js +40 -53
  24. package/dist/src/Test.d.ts.map +1 -1
  25. package/dist/src/Test.js +1 -0
  26. package/dist/src/Time.d.ts.map +1 -1
  27. package/dist/src/Time.js +9 -2
  28. package/dist/src/Type.d.ts +146 -9
  29. package/dist/src/Type.d.ts.map +1 -1
  30. package/dist/src/Type.js +10 -7
  31. package/dist/src/WebSocket.d.ts.map +1 -1
  32. package/dist/src/WebSocket.js +8 -0
  33. package/dist/src/Worker.js +1 -1
  34. package/dist/src/local-first/Db.js +3 -2
  35. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  36. package/dist/src/local-first/Evolu.js +1 -0
  37. package/dist/src/local-first/Owner.d.ts +8 -7
  38. package/dist/src/local-first/Owner.d.ts.map +1 -1
  39. package/dist/src/local-first/Owner.js +4 -4
  40. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  41. package/dist/src/local-first/Protocol.js +30 -24
  42. package/dist/src/local-first/Query.d.ts.map +1 -1
  43. package/dist/src/local-first/Query.js +2 -1
  44. package/dist/src/local-first/Relay.js +1 -1
  45. package/dist/src/local-first/Shared.d.ts.map +1 -1
  46. package/dist/src/local-first/Shared.js +4 -2
  47. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  48. package/dist/src/local-first/Timestamp.js +1 -1
  49. package/package.json +1 -1
  50. package/src/Array.ts +28 -1
  51. package/src/Assert.ts +1 -0
  52. package/src/LeakDetector.ts +4 -3
  53. package/src/Lookup.ts +1 -0
  54. package/src/Platform.ts +1 -0
  55. package/src/Relation.ts +3 -3
  56. package/src/Resource.ts +9 -3
  57. package/src/Result.ts +5 -5
  58. package/src/Sqlite.ts +9 -7
  59. package/src/Store.ts +3 -1
  60. package/src/String.ts +1 -1
  61. package/src/Task.ts +133 -82
  62. package/src/Test.ts +1 -0
  63. package/src/Time.ts +9 -2
  64. package/src/Type.ts +173 -29
  65. package/src/WebSocket.ts +8 -0
  66. package/src/Worker.ts +1 -1
  67. package/src/local-first/Db.ts +2 -1
  68. package/src/local-first/Evolu.ts +1 -0
  69. package/src/local-first/Owner.ts +8 -7
  70. package/src/local-first/Protocol.ts +40 -30
  71. package/src/local-first/Query.ts +6 -3
  72. package/src/local-first/Relay.ts +1 -1
  73. package/src/local-first/Shared.ts +4 -2
  74. package/src/local-first/Timestamp.ts +1 -1
package/src/Time.ts CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  import { assert } from "./Assert.ts";
8
8
  import type { Brand } from "./Brand.ts";
9
+ import { exhaustiveCheck } from "./Function.ts";
9
10
  import type { yieldNow } from "./Task.ts";
10
11
  import {
11
12
  brand,
@@ -239,6 +240,10 @@ export const testCreateTime = (options?: {
239
240
  case "microtask":
240
241
  queueMicrotask(incrementNow);
241
242
  break;
243
+ case undefined:
244
+ break;
245
+ default:
246
+ exhaustiveCheck(autoIncrement);
242
247
  }
243
248
  return result;
244
249
  };
@@ -564,8 +569,10 @@ const durationUnits = {
564
569
  m: 60000,
565
570
  h: 3600000,
566
571
  d: 86400000,
567
- w: 604800000, // 7 days
568
- y: 31536000000, // 365 days
572
+ // 7 days
573
+ w: 604800000,
574
+ // 365 days
575
+ y: 31536000000,
569
576
  } as const;
570
577
 
571
578
  /**
package/src/Type.ts CHANGED
@@ -432,9 +432,10 @@ import { sha256 } from "@noble/hashes/sha2.js";
432
432
  import * as bip39 from "@scure/bip39";
433
433
  import { wordlist } from "@scure/bip39/wordlists/english.js";
434
434
  import type { StandardSchemaV1 } from "@standard-schema/spec";
435
- import type {
436
- AtLeastTwoReadonlyArray,
437
- NonEmptyReadonlyArray,
435
+ import {
436
+ createMutableArray,
437
+ type AtLeastTwoReadonlyArray,
438
+ type NonEmptyReadonlyArray,
438
439
  } from "./Array.ts";
439
440
  import { assert, assertNonNullable } from "./Assert.ts";
440
441
  import type { Brand } from "./Brand.ts";
@@ -1349,9 +1350,8 @@ type ValidateFormatErrorByTypeByLocale<
1349
1350
  ? unknown
1350
1351
  : never;
1351
1352
 
1352
- /* eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style --
1353
- This mapped validation type is cheaper than the equivalent Record. Changes are
1354
- measured by `pnpm bench:type`. */
1353
+ // This mapped validation type is cheaper than the equivalent Record. Changes
1354
+ // are measured by `pnpm bench:type`.
1355
1355
  type NoNonStringKeys<Value> = {
1356
1356
  readonly [Key in Exclude<keyof Value, string>]: never;
1357
1357
  };
@@ -1891,6 +1891,7 @@ export function createType<
1891
1891
  parent: ValidateParent<ParentType>,
1892
1892
  fromParent: (
1893
1893
  value: ParentType["Output"],
1894
+ // oxlint-disable-next-line typescript/no-unnecessary-type-arguments -- Explicit defaults in recursive Type declarations are benchmarked to avoid extra compiler work.
1894
1895
  ) => Result<ParentType["Output"], never>,
1895
1896
  ): Type<
1896
1897
  Name,
@@ -2179,12 +2180,58 @@ export function transform<
2179
2180
  operations: {
2180
2181
  readonly from: (
2181
2182
  value: ParentType["Output"],
2183
+ // oxlint-disable-next-line typescript/no-unnecessary-type-arguments -- Explicit defaults in recursive Type declarations are benchmarked to avoid extra compiler work.
2182
2184
  ) => Result<OutputType["Input"], never>;
2183
2185
  readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
2184
2186
  },
2185
2187
  ): TransformType<ParentType, OutputType, Name, never, ToOutput>;
2186
2188
 
2187
- /** Creates a fallible transformed Type with its own error formatter. */
2189
+ /**
2190
+ * Creates a fallible transformed Type with its own error formatter.
2191
+ *
2192
+ * ### Example
2193
+ *
2194
+ * ```ts
2195
+ * import {
2196
+ * Boolean,
2197
+ * String,
2198
+ * err,
2199
+ * ok,
2200
+ * transform,
2201
+ * type Result,
2202
+ * type TypeError,
2203
+ * } from "@evolu/common";
2204
+ *
2205
+ * interface BooleanFromStringError extends TypeError<"BooleanFromString"> {
2206
+ * readonly value: string;
2207
+ * }
2208
+ *
2209
+ * const BooleanFromString = transform(
2210
+ * "BooleanFromString",
2211
+ * String,
2212
+ * Boolean,
2213
+ * {
2214
+ * from: (value): Result<boolean, BooleanFromStringError> =>
2215
+ * value === "true"
2216
+ * ? ok(true)
2217
+ * : value === "false"
2218
+ * ? ok(false)
2219
+ * : err({ type: "BooleanFromString", value }),
2220
+ * to: (value) => (value ? "true" : "false"),
2221
+ * },
2222
+ * () => 'Expected "true" or "false".',
2223
+ * );
2224
+ *
2225
+ * expectOk(BooleanFromString.fromUnknown("true"), true);
2226
+ * expect(BooleanFromString.to(false)).toBe("false");
2227
+ *
2228
+ * const invalid = BooleanFromString.fromUnknown("yes");
2229
+ * expectErr(invalid, { type: "BooleanFromString", value: "yes" });
2230
+ * expect(BooleanFromString.formatError(invalid.error)).toBe(
2231
+ * 'Expected "true" or "false".',
2232
+ * );
2233
+ * ```
2234
+ */
2188
2235
  export function transform<
2189
2236
  Name extends TypeName,
2190
2237
  ParentType extends ConcreteTypeNode,
@@ -2473,7 +2520,7 @@ function getTerminalRuntimeNode<Value>(
2473
2520
  ): RuntimeOperation<Value>;
2474
2521
  function getTerminalRuntimeNode(node: RuntimeTypeNode): RuntimeTypeNode;
2475
2522
  function getTerminalRuntimeNode(node: { readonly parent?: unknown }): unknown {
2476
- while (node.parent) node = node.parent;
2523
+ while (node.parent != null) node = node.parent;
2477
2524
 
2478
2525
  return node;
2479
2526
  }
@@ -2949,7 +2996,30 @@ export function objectTag<Name extends keyof ObjectTagOutputByName>(
2949
2996
  ObjectTagOutputByName[Name]
2950
2997
  >;
2951
2998
 
2952
- /** Creates an object-tag Type by refining an existing object Type. */
2999
+ /**
3000
+ * Creates an object-tag Type by refining an existing object Type.
3001
+ *
3002
+ * ### Example
3003
+ *
3004
+ * ```ts
3005
+ * import { instanceOf, objectTag } from "@evolu/common";
3006
+ *
3007
+ * class TaggedValue {
3008
+ * readonly [globalThis.Symbol.toStringTag] = "TaggedValue";
3009
+ * }
3010
+ *
3011
+ * const TaggedValueType = objectTag(
3012
+ * "TaggedValue",
3013
+ * instanceOf(TaggedValue),
3014
+ * );
3015
+ * const value = new TaggedValue();
3016
+ * const result = TaggedValueType.fromUnknown(value);
3017
+ *
3018
+ * expectOk(result, value);
3019
+ * expectTypeOf(result.value).toExtend<TaggedValue>();
3020
+ * expect(TaggedValueType.expected).toBe("TaggedValue");
3021
+ * ```
3022
+ */
2953
3023
  export function objectTag<
2954
3024
  Name extends TypeName,
2955
3025
  OutputType extends ConcreteTypeNode & { readonly Output: object },
@@ -4145,6 +4215,7 @@ export interface TemplateLiteralType<
4145
4215
  TypeOfError<"String"> | TemplateLiteralParseError<Parts>,
4146
4216
  never,
4147
4217
  TemplateLiteralStringOutput<Parts>,
4218
+ // oxlint-disable-next-line typescript/no-unnecessary-type-arguments -- TemplateLiteralType explicitly documents every Type invariant, including identity encoding.
4148
4219
  true
4149
4220
  > {
4150
4221
  readonly [templateLiteralSyntaxSymbol]: true;
@@ -4650,6 +4721,7 @@ export function brand<
4650
4721
  >(
4651
4722
  name: ValidateConcreteTypeName<Name>,
4652
4723
  parent: ValidateParent<ParentType>,
4724
+ // oxlint-disable-next-line typescript/no-unnecessary-type-arguments -- Explicit defaults in recursive Type declarations are benchmarked to avoid extra compiler work.
4653
4725
  validate?: (value: ParentType["Output"]) => Result<void, never>,
4654
4726
  ): BrandType<ParentType, Name, never>;
4655
4727
 
@@ -5378,7 +5450,7 @@ export interface RegexError<
5378
5450
  */
5379
5451
  export const UrlSafeString = /*#__PURE__*/ regex(
5380
5452
  "UrlSafeString",
5381
- /^[A-Za-z0-9_-]+$/,
5453
+ /^[A-Za-z0-9_-]+$/u,
5382
5454
  )(String);
5383
5455
  export type UrlSafeString = typeof UrlSafeString.Output;
5384
5456
 
@@ -5401,7 +5473,7 @@ const uint8ArrayToBase64UrlString = (bytes: Uint8Array): string => {
5401
5473
  ).join("");
5402
5474
  const base64 = globalThis.btoa(binaryString);
5403
5475
 
5404
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
5476
+ return base64.replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
5405
5477
  };
5406
5478
 
5407
5479
  const base64UrlStringToUint8Array = (value: string): Uint8Array => {
@@ -5414,7 +5486,7 @@ const base64UrlStringToUint8Array = (value: string): Uint8Array => {
5414
5486
  return globalThis.Uint8Array.fromBase64(value, base64UrlOptions);
5415
5487
  }
5416
5488
 
5417
- let base64 = value.replace(/-/g, "+").replace(/_/g, "/");
5489
+ let base64 = value.replaceAll("-", "+").replaceAll("_", "/");
5418
5490
  while (base64.length % 4 !== 0) base64 += "=";
5419
5491
 
5420
5492
  const binaryString = globalThis.atob(base64);
@@ -5756,6 +5828,7 @@ export interface TableId<Table extends TypeName> extends Type<
5756
5828
  TableIdError<Table> | InferErrors<typeof String>,
5757
5829
  ChildCustomFrom<typeof String, Id & Brand<Table>, TableIdError<Table>>,
5758
5830
  CanonicalInputForChild<typeof String, Id & Brand<Table>>,
5831
+ // oxlint-disable-next-line typescript/no-unnecessary-type-arguments -- TableId must track its parent Type's identity encoding instead of hard-coding Type's default.
5759
5832
  IdentityEncodingOf<typeof String>
5760
5833
  > {
5761
5834
  readonly table: Table;
@@ -5877,7 +5950,7 @@ export const Int64String = /*#__PURE__*/ brand(
5877
5950
 
5878
5951
  if (
5879
5952
  value.length > (negative ? 20 : 19) ||
5880
- !/^(?:0|-?[1-9]\d*)$/.test(value)
5953
+ !/^(?:0|-?[1-9]\d*)$/u.test(value)
5881
5954
  ) {
5882
5955
  return err<Int64StringError>({ type: "Int64String", value });
5883
5956
  }
@@ -6607,7 +6680,7 @@ export const DecimalString = /*#__PURE__*/ brand(
6607
6680
  "DecimalString",
6608
6681
  String,
6609
6682
  (value) =>
6610
- /^(?:0|-?(?:[1-9]\d*|(?:0|[1-9]\d*)\.\d*[1-9]))$/.test(value)
6683
+ /^(?:0|-?(?:[1-9]\d*|(?:0|[1-9]\d*)\.\d*[1-9]))$/u.test(value)
6611
6684
  ? ok()
6612
6685
  : err<DecimalStringError>({ type: "DecimalString", value }),
6613
6686
  (error) =>
@@ -7494,7 +7567,7 @@ const copyArrayPrefix = (
7494
7567
  value: ReadonlyArray<unknown>,
7495
7568
  endIndex: number,
7496
7569
  ): Array<unknown> => {
7497
- const output = new Array<unknown>(value.length);
7570
+ const output = createMutableArray<unknown>(value.length);
7498
7571
 
7499
7572
  for (let index = 0; index < endIndex; index++) {
7500
7573
  output[index] = value[index];
@@ -8911,7 +8984,7 @@ export const record = <
8911
8984
  encodeKey === identity && encodeValue === identity
8912
8985
  ? identity
8913
8986
  : (input: Readonly<Record<string, unknown>>) => {
8914
- const output = createMutableRecord<string, unknown>();
8987
+ const output = createMutableRecord();
8915
8988
  let changed = false;
8916
8989
 
8917
8990
  for (const inputKey of globalThis.Object.keys(input)) {
@@ -9269,7 +9342,7 @@ const validateRecordEntries = (
9269
9342
  > => {
9270
9343
  let issues:
9271
9344
  Array<RecordIssue<TypeError, TypeError, RecordStructuralIssue>> | undefined;
9272
- const output = createMutableRecord<string, unknown>();
9345
+ const output = createMutableRecord();
9273
9346
  const inputKeyByOutputKey = createMutableRecord<string, string | symbol>();
9274
9347
  let changed = false;
9275
9348
 
@@ -9543,7 +9616,32 @@ export function object<const Props extends ObjectProps>(
9543
9616
  : [ValidationFailure<ObjectValidationError<Props>>]
9544
9617
  ): StrictObjectType<Props>;
9545
9618
 
9546
- /** Creates an Object Type with additional record properties. */
9619
+ /**
9620
+ * Creates an Object Type with additional record properties.
9621
+ *
9622
+ * ### Example
9623
+ *
9624
+ * ```ts
9625
+ * import { String, object, record } from "@evolu/common";
9626
+ *
9627
+ * const RequestHeaders = object(
9628
+ * { authorization: String },
9629
+ * record(String, String),
9630
+ * );
9631
+ * const result = RequestHeaders.fromUnknown({
9632
+ * authorization: "Bearer token",
9633
+ * "x-request-id": "request-1",
9634
+ * });
9635
+ *
9636
+ * expectOk(result, {
9637
+ * authorization: "Bearer token",
9638
+ * "x-request-id": "request-1",
9639
+ * });
9640
+ * expectTypeOf(result.value["x-request-id"]).toEqualTypeOf<
9641
+ * string | undefined
9642
+ * >();
9643
+ * ```
9644
+ */
9547
9645
  export function object<
9548
9646
  const Props extends ObjectProps,
9549
9647
  const Rest extends RecordTypeNode & ConcreteTypeNode,
@@ -10831,6 +10929,35 @@ export type UnknownResult = typeof UnknownResult.Output;
10831
10929
  * ### Example
10832
10930
  *
10833
10931
  * ```ts
10932
+ * import { String, discriminatedUnion, typed } from "@evolu/common";
10933
+ *
10934
+ * const Loading = typed("Loading");
10935
+ * const Loaded = typed("Loaded", { value: String });
10936
+ * const State = discriminatedUnion(Loading, Loaded);
10937
+ *
10938
+ * expectOk(State.fromUnknown({ type: "Loading" }), { type: "Loading" });
10939
+ * expectOk(State.fromUnknown({ type: "Loaded", value: "Evolu" }), {
10940
+ * type: "Loaded",
10941
+ * value: "Evolu",
10942
+ * });
10943
+ * expect(Loading.is({ type: "Loading", progress: 1 })).toBe(false);
10944
+ * expectTypeOf<typeof Loading.Output>().toExtend<{
10945
+ * readonly type: "Loading";
10946
+ * }>();
10947
+ * ```
10948
+ *
10949
+ * @group Discriminated unions
10950
+ */
10951
+ export function typed<const Tag extends TypeName>(
10952
+ tag: ValidateTypedTag<Tag>,
10953
+ ): TypedType<Tag>;
10954
+
10955
+ /**
10956
+ * Creates a Tagged Object Type with declared properties.
10957
+ *
10958
+ * ### Example
10959
+ *
10960
+ * ```ts
10834
10961
  * import { String, typed } from "@evolu/common";
10835
10962
  *
10836
10963
  * const Pending = typed("Pending", {
@@ -10842,14 +10969,7 @@ export type UnknownResult = typeof UnknownResult.Output;
10842
10969
  * label: "Waiting",
10843
10970
  * });
10844
10971
  * ```
10845
- *
10846
- * @group Discriminated unions
10847
10972
  */
10848
- export function typed<const Tag extends TypeName>(
10849
- tag: ValidateTypedTag<Tag>,
10850
- ): TypedType<Tag>;
10851
-
10852
- /** Creates a Tagged Object Type with declared properties. */
10853
10973
  export function typed<
10854
10974
  const Tag extends TypeName,
10855
10975
  const Props extends ObjectProps,
@@ -10861,7 +10981,29 @@ export function typed<
10861
10981
  : [ValidationFailure<TypedValidationError<Props>>]
10862
10982
  ): TypedType<Tag, Props>;
10863
10983
 
10864
- /** Creates a Tagged Object Type with additional record properties. */
10984
+ /**
10985
+ * Creates a Tagged Object Type with additional record properties.
10986
+ *
10987
+ * ### Example
10988
+ *
10989
+ * ```ts
10990
+ * import { String, record, typed } from "@evolu/common";
10991
+ *
10992
+ * const Open = typed("Open", { label: String }, record(String, String));
10993
+ * const result = Open.fromUnknown({
10994
+ * type: "Open",
10995
+ * label: "Ready",
10996
+ * note: "Connected",
10997
+ * });
10998
+ *
10999
+ * expectOk(result, {
11000
+ * type: "Open",
11001
+ * label: "Ready",
11002
+ * note: "Connected",
11003
+ * });
11004
+ * expectTypeOf(result.value.note).toEqualTypeOf<string | undefined>();
11005
+ * ```
11006
+ */
10865
11007
  export function typed<
10866
11008
  const Tag extends TypeName,
10867
11009
  const Props extends ObjectProps,
@@ -11242,19 +11384,19 @@ export function discriminatedUnion(
11242
11384
  return err({
11243
11385
  type: "DiscriminatedUnion",
11244
11386
  reason: { kind: "PropertyAccess", key, reason: "Inherited" },
11245
- } satisfies DiscriminatedUnionPropertyAccessError<string>);
11387
+ } satisfies DiscriminatedUnionPropertyAccessError);
11246
11388
  }
11247
11389
  discriminator = undefined;
11248
11390
  } else if (!("value" in descriptor)) {
11249
11391
  return err({
11250
11392
  type: "DiscriminatedUnion",
11251
11393
  reason: { kind: "PropertyAccess", key, reason: "Accessor" },
11252
- } satisfies DiscriminatedUnionPropertyAccessError<string>);
11394
+ } satisfies DiscriminatedUnionPropertyAccessError);
11253
11395
  } else if (!descriptor.enumerable) {
11254
11396
  return err({
11255
11397
  type: "DiscriminatedUnion",
11256
11398
  reason: { kind: "PropertyAccess", key, reason: "NonEnumerable" },
11257
- } satisfies DiscriminatedUnionPropertyAccessError<string>);
11399
+ } satisfies DiscriminatedUnionPropertyAccessError);
11258
11400
  } else {
11259
11401
  discriminator = descriptor.value;
11260
11402
  }
@@ -12260,6 +12402,7 @@ const validateJsonValue = (
12260
12402
  }
12261
12403
  if (typeof value === "number") {
12262
12404
  if (!globalThis.Number.isFinite(value)) {
12405
+ // oxlint-disable-next-line unicorn/no-lonely-if -- Keep issue construction separate from the finite-number guard.
12263
12406
  if (
12264
12407
  addIssue({
12265
12408
  kind: "NonFiniteNumber",
@@ -12521,6 +12664,7 @@ const stringifyJsonValue = (value: JsonValue): Json => {
12521
12664
  continue;
12522
12665
  }
12523
12666
 
12667
+ // oxlint-disable-next-line typescript/switch-exhaustiveness-check -- JsonValue excludes the additional runtime types reported by tsgolint.
12524
12668
  switch (typeof value) {
12525
12669
  case "string":
12526
12670
  chunks.push(globalThis.JSON.stringify(value));
package/src/WebSocket.ts CHANGED
@@ -235,9 +235,13 @@ export const createWebSocket: CreateWebSocket =
235
235
  const closeSocket = () => {
236
236
  if (!socket) return;
237
237
 
238
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
238
239
  socket.onopen = null;
240
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
239
241
  socket.onclose = null;
242
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
240
243
  socket.onmessage = null;
244
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
241
245
  socket.onerror = null;
242
246
 
243
247
  if (
@@ -266,11 +270,13 @@ export const createWebSocket: CreateWebSocket =
266
270
 
267
271
  let isOpen = false;
268
272
 
273
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
269
274
  socket.onopen = () => {
270
275
  isOpen = true;
271
276
  onOpen?.();
272
277
  };
273
278
 
279
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
274
280
  socket.onclose = (event) => {
275
281
  onClose?.(event);
276
282
  if (shouldRetryOnClose(event)) {
@@ -280,10 +286,12 @@ export const createWebSocket: CreateWebSocket =
280
286
  }
281
287
  };
282
288
 
289
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
283
290
  socket.onmessage = (event: MessageEvent<string | ArrayBuffer | Blob>) => {
284
291
  onMessage?.(event.data);
285
292
  };
286
293
 
294
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- This adapter owns and clears one handler.
287
295
  socket.onerror = (event) => {
288
296
  const error: WebSocketConnectionError | WebSocketConnectError = isOpen
289
297
  ? { type: "WebSocketConnectionError", event }
package/src/Worker.ts CHANGED
@@ -432,7 +432,7 @@ export const createBroadcastChannel: CreateBroadcastChannel = <
432
432
  const dispatches = broadcastChannelDispatchesByName.get(name);
433
433
  assert(dispatches, "Expected broadcast channel dispatches");
434
434
 
435
- for (const otherDispatch of [...dispatches]) {
435
+ for (const otherDispatch of dispatches) {
436
436
  if (otherDispatch === dispatch) continue;
437
437
 
438
438
  scheduleWorkerTask(() => {
@@ -924,7 +924,8 @@ const applyMessages =
924
924
  */
925
925
  updateOwnerUsage(deps)(
926
926
  ownerIdBytes,
927
- onePositiveInt, // Placeholder until proper tracking implemented
927
+ // Placeholder until proper tracking implemented
928
+ onePositiveInt,
928
929
  firstTimestamp,
929
930
  lastTimestamp,
930
931
  );
@@ -1248,6 +1248,7 @@ export const createEvolu =
1248
1248
  console.info("disposeEvolu");
1249
1249
  });
1250
1250
 
1251
+ // oxlint-disable-next-line react/rules-of-hooks -- useOwner manages sync ownership and is not a React Hook.
1251
1252
  if (isNonEmptyArray(transports)) useOwner(appOwner);
1252
1253
 
1253
1254
  run.signal.throwIfAborted();
@@ -11,15 +11,15 @@
11
11
  *
12
12
  * Individual changes in an append-only local-first history can only be marked
13
13
  * as deleted. An entire owner, however, can be removed from devices and relays
14
- * together with all of its data. The AppOwner must remain because it coordinates
15
- * the deletion of other owners across devices.
14
+ * together with all of its data. The AppOwner must remain because it
15
+ * coordinates the deletion of other owners across devices.
16
16
  *
17
17
  * Choose an owner by how its data should live and be shared:
18
18
  *
19
19
  * - {@link AppOwner} coordinates sync and persists for the lifetime of the app
20
20
  * identity.
21
- * - {@link ShardOwner} partitions application data so it can be synced and
22
- * deleted independently.
21
+ * - {@link ShardOwner} partitions application data so it can be synced and deleted
22
+ * independently.
23
23
  * - {@link SharedOwner} grants collaborative read and write access.
24
24
  * - {@link SharedReadonlyOwner} grants read-only access to shared data.
25
25
  *
@@ -62,8 +62,8 @@ import { TimestampBytes } from "./Timestamp.ts";
62
62
  /**
63
63
  * {@link Owner} without a {@link OwnerWriteKey}.
64
64
  *
65
- * @see {@link createSharedReadonlyOwner}
66
65
  * @group Core
66
+ * @see {@link createSharedReadonlyOwner}
67
67
  */
68
68
  export interface ReadonlyOwner {
69
69
  readonly id: OwnerId;
@@ -427,9 +427,9 @@ export type OwnerTransport = OwnerWebSocketTransport;
427
427
  * Legitimate clients will be properly configured with valid credentials, so
428
428
  * automatic retry is OK.
429
429
  *
430
+ * @group Transport
430
431
  * @see {@link createOwnerWebSocketTransport}
431
432
  * @see {@link parseOwnerIdFromOwnerWebSocketTransportUrl}
432
- * @group Transport
433
433
  */
434
434
  export interface OwnerWebSocketTransport extends Typed<"WebSocket"> {
435
435
  readonly url: string;
@@ -553,7 +553,8 @@ export interface OwnerUsage {
553
553
  *
554
554
  * Measures only {@link EncryptedDbChange} data and excludes {@link Storage}
555
555
  * implementation overhead such as indexes and skip-list columns. This makes
556
- * the measurement consistent across storage implementations and suitable for:
556
+ * the measurement consistent across storage implementations and suitable
557
+ * for:
557
558
  *
558
559
  * - **Predictable measurement** - same data = same byte count across all
559
560
  * instances