Skip to content

Commit a90b889

Browse files
committed
Updates Node.js and refactors core utilities
Upgrades the minimum Node.js version from 22 to 24 (current LTS), allowing for the use of modern JavaScript features like `Promise.withResolvers`. This change also includes significant internal refactoring: - Consolidates `Task` and array utility modules. - Adopts `import type` extensively for better tree-shaking and optimized bundle sizes. - Enhances type safety with explicit annotations and assertions. - Removes the deprecated `erasableSyntaxOnly` TypeScript configuration option.
1 parent b80fd81 commit a90b889

11 files changed

Lines changed: 268 additions & 243 deletions

File tree

.changeset/gentle-pumas-eat.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@
99
"@evolu/relay": major
1010
---
1111

12+
# Update Node.js requirement
13+
1214
Updated minimum Node.js version from 22 to 24 (current LTS)

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
lts/*
1+
v24

packages/common/src/Task.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1-
import { isNonEmptyArray, shiftArray } from "./Array.js";
2-
import { Result, err, ok } from "./Result.js";
1+
import { isNonEmptyArray, shiftFromArray } from "./Array.js";
2+
import { err, ok, type Result } from "./Result.js";
33
import { Duration, durationToNonNegativeInt } from "./Time.js";
44
import { NonNegativeInt, PositiveInt } from "./Type.js";
55

6+
7+
declare global {
8+
interface PromiseConstructor {
9+
withResolvers<T>(): {
10+
promise: Promise<T>;
11+
resolve: (value: T | PromiseLike<T>) => void;
12+
reject: (reason?: unknown) => void;
13+
};
14+
}
15+
}
16+
617
/**
718
* `Task` is a function that creates and returns an optionally cancellable
819
* Promise using {@link Result}.
@@ -144,6 +155,8 @@ import { NonNegativeInt, PositiveInt } from "./Type.js";
144155
* dependencies and `TaskContext` for execution context like cancellation. Usage
145156
* follows the pattern: deps → arguments → execution context.
146157
*/
158+
159+
147160
export interface Task<T, E> {
148161
/**
149162
* Invoke the Task.
@@ -236,7 +249,11 @@ const combineSignal = (
236249
internalSignal: AbortSignal,
237250
): AbortSignal =>
238251
context?.signal
239-
? AbortSignal.any([context.signal, internalSignal])
252+
? (
253+
AbortSignal as unknown as {
254+
any: (signals: Iterable<AbortSignal>) => AbortSignal;
255+
}
256+
).any([context.signal, internalSignal])
240257
: internalSignal;
241258

242259
/**
@@ -652,7 +669,7 @@ export const createSemaphore = (maxConcurrent: PositiveInt): Semaphore => {
652669

653670
const release = (): void => {
654671
if (isNonEmptyArray(waitingQueue)) {
655-
shiftArray(waitingQueue)();
672+
shiftFromArray(waitingQueue)();
656673
} else {
657674
availablePermits++;
658675
}
@@ -689,7 +706,7 @@ export const createSemaphore = (maxConcurrent: PositiveInt): Semaphore => {
689706

690707
// Release all waiting tasks so they can continue and check isDisposed
691708
while (isNonEmptyArray(waitingQueue)) {
692-
shiftArray(waitingQueue)();
709+
shiftFromArray(waitingQueue)();
693710
}
694711
},
695712
};

packages/common/src/WebSocket.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { constVoid } from "./Function.js";
22
import { err, ok, Result } from "./Result.js";
3-
import { retry, RetryError, RetryOptions } from "./OldTask.js";
3+
import { retry, RetryError, type RetryOptions } from "./Task.js";
44
import { maxPositiveInt } from "./Type.js";
55

66
/** WebSocket with auto-reconnect and offline support. */

packages/common/src/local-first/Evolu.ts

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,74 @@ import { pack } from "msgpackr";
22
import { dedupeArray, isNonEmptyArray } from "../Array.js";
33
import { assert, assertNonEmptyReadonlyArray } from "../Assert.js";
44
import { createCallbacks } from "../Callbacks.js";
5-
import { ConsoleDep, createConsole } from "../Console.js";
6-
import { createRandomBytes, RandomBytesDep } from "../Crypto.js";
5+
import { createConsole, type ConsoleDep } from "../Console.js";
6+
import { createRandomBytes, type RandomBytesDep } from "../Crypto.js";
77
import { eqArrayNumber } from "../Eq.js";
8-
import { FlushSyncDep, ReloadAppDep } from "../Platform.js";
8+
import type { FlushSyncDep, ReloadAppDep } from "../Platform.js";
99
import {
1010
createDisposableDep,
11-
DisposableDep,
12-
DisposableStackDep,
11+
type DisposableDep,
12+
type DisposableStackDep,
1313
} from "../Resources.js";
14-
import { err, ok, Result } from "../Result.js";
14+
import { err, ok, type Result } from "../Result.js";
1515
import {
16-
isSqlMutation,
17-
SafeSql,
1816
SqliteBoolean,
17+
isSqlMutation,
1918
sqliteBooleanToBoolean,
20-
SqliteQuery,
19+
type SafeSql,
20+
type SqliteQuery,
2121
} from "../Sqlite.js";
22-
import { createStore, ReadonlyStore, Store, StoreSubscribe } from "../Store.js";
22+
import { createStore, type ReadonlyStore, type Store, type StoreSubscribe } from "../Store.js";
2323
import {
2424
createId,
25-
Id,
26-
InferErrors,
27-
InferInput,
28-
ObjectType,
29-
SimpleName,
30-
ValidMutationSize,
31-
ValidMutationSizeError,
25+
type Id,
26+
type InferErrors,
27+
type InferInput,
28+
type ObjectType,
29+
type SimpleName,
30+
type ValidMutationSize,
31+
type ValidMutationSizeError,
3232
} from "../Type.js";
33-
import { IntentionalNever } from "../Types.js";
34-
import { CreateMessageChannelDep } from "../Worker.js";
35-
import { EvoluError } from "./Error.js";
33+
import type { IntentionalNever } from "../Types.js";
34+
import type { CreateMessageChannelDep } from "../Worker.js";
35+
import type { EvoluError } from "./Error.js";
3636
import {
37-
AppOwner,
3837
createOwnerWebSocketTransport,
39-
OwnerId,
40-
OwnerTransport,
38+
type AppOwner,
39+
type OwnerId,
40+
type OwnerTransport,
4141
} from "./Owner.js";
4242
import {
4343
createSubscribedQueries,
4444
emptyRows,
45-
Queries,
46-
QueriesToQueryRowsPromises,
47-
Query,
48-
QueryRows,
49-
QueryRowsMap,
50-
Row,
5145
serializeQuery,
52-
SubscribedQueries,
46+
type Queries,
47+
type QueriesToQueryRowsPromises,
48+
type Query,
49+
type QueryRows,
50+
type QueryRowsMap,
51+
type Row,
52+
type SubscribedQueries,
5353
} from "./Query.js";
5454
import {
55-
CreateQuery,
56-
EvoluSchema,
57-
IndexesConfig,
5855
insertable,
5956
kysely,
60-
Mutation,
61-
MutationChange,
62-
MutationKind,
63-
MutationMapping,
64-
MutationOptions,
65-
SystemColumns,
6657
updateable,
6758
upsertable,
68-
ValidateSchema,
59+
type CreateQuery,
60+
type EvoluSchema,
61+
type IndexesConfig,
62+
type Mutation,
63+
type MutationChange,
64+
type MutationKind,
65+
type MutationMapping,
66+
type MutationOptions,
67+
type SystemColumns,
68+
type ValidateSchema,
6969
} from "./Schema.js";
70-
import { SharedWorkerDep } from "./SharedWorker.js";
70+
import type { SharedWorkerDep } from "./SharedWorker.js";
7171
import { DbChange } from "./Storage.js";
72-
import { SyncOwner } from "./Sync.js";
72+
import type { SyncOwner } from "./Sync.js";
7373

7474
export interface EvoluConfig {
7575
/**
@@ -80,7 +80,7 @@ export interface EvoluConfig {
8080
* storage, ensuring that database files are separated and invisible to each
8181
* other.
8282
*
83-
* ## Example
83+
* ### Example
8484
*
8585
* ```ts
8686
* // name: SimpleName.orThrow("MyApp")
@@ -116,7 +116,7 @@ export interface EvoluConfig {
116116
*
117117
* `{ type: "WebSocket", url: "wss://free.evoluhq.com" }`.
118118
*
119-
* ## Example
119+
* ### Example
120120
*
121121
* ```ts
122122
* // Single WebSocket relay
@@ -154,7 +154,7 @@ export interface EvoluConfig {
154154
* For device-specific settings and account management state, we can use a
155155
* separate local-only Evolu instance via `transports: []`.
156156
*
157-
* ## Example
157+
* ### Example
158158
*
159159
* ```ts
160160
* const ConfigId = id("Config");
@@ -201,7 +201,7 @@ export interface EvoluConfig {
201201
*
202202
* https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-indexes-indexes-c4e175f3c346
203203
*
204-
* ## Example
204+
* ### Example
205205
*
206206
* ```ts
207207
* const evolu = createEvolu(evoluReactDeps)(Schema, {
@@ -231,7 +231,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
231231
/**
232232
* Subscribe to {@link EvoluError} changes.
233233
*
234-
* ## Example
234+
* ### Example
235235
*
236236
* ```ts
237237
* const unsubscribe = evolu.subscribeError(() => {
@@ -257,7 +257,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
257257
* For mutations, use {@link Evolu.insert}, {@link Evolu.update}, or
258258
* {@link Evolu.upsert}.
259259
*
260-
* ## Example
260+
* ### Example
261261
*
262262
* ```ts
263263
* const allTodos = evolu.createQuery((db) =>
@@ -286,7 +286,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
286286
* To subscribe a query for automatic updates, use
287287
* {@link Evolu.subscribeQuery}.
288288
*
289-
* ## Example
289+
* ### Example
290290
*
291291
* ```ts
292292
* const allTodos = evolu.createQuery((db) =>
@@ -304,7 +304,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
304304
* {@link QueryRows} promises. It's like `queries.map(loadQuery)` but with
305305
* proper types for returned promises.
306306
*
307-
* ## Example
307+
* ### Example
308308
*
309309
* ```ts
310310
* evolu.loadQueries([allTodos, todoById(1)]);
@@ -317,7 +317,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
317317
/**
318318
* Subscribe to {@link Query} {@link QueryRows} changes.
319319
*
320-
* ## Example
320+
* ### Example
321321
*
322322
* ```ts
323323
* const unsubscribe = evolu.subscribeQuery(allTodos)(() => {
@@ -330,7 +330,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
330330
/**
331331
* Get {@link QueryRows}.
332332
*
333-
* ## Example
333+
* ### Example
334334
*
335335
* ```ts
336336
* const unsubscribe = evolu.subscribeQuery(allTodos)(() => {
@@ -346,7 +346,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
346346
* Note: With web-only deps, this promise will not resolve during SSR because
347347
* there is no AppOwner on the server.
348348
*
349-
* ## Example
349+
* ### Example
350350
*
351351
* ```ts
352352
* const owner = await evolu.appOwner;
@@ -370,7 +370,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
370370
* predictably merged without conflicts. Explicit mutations also allow Evolu
371371
* to automatically update {@link SystemColumns}.
372372
*
373-
* ## Example
373+
* ### Example
374374
*
375375
* ```ts
376376
* const result = evolu.insert("todo", {
@@ -415,7 +415,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
415415
* predictably merged without conflicts. Explicit mutations also allow Evolu
416416
* to automatically update {@link SystemColumns}.
417417
*
418-
* ## Example
418+
* ### Example
419419
*
420420
* ```ts
421421
* const result = evolu.update("todo", {
@@ -468,7 +468,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
468468
* predictably merged without conflicts. Explicit mutations also allow Evolu
469469
* to automatically update {@link SystemColumns}.
470470
*
471-
* ## Example
471+
* ### Example
472472
*
473473
* ```ts
474474
* // Use deterministic ID for stable upserts across devices
@@ -554,7 +554,7 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends Disposable {
554554
* Transport are automatically deduplicated and reference-counted, so multiple
555555
* owners using the same transport will share a single connection.
556556
*
557-
* ## Example
557+
* ### Example
558558
*
559559
* ```ts
560560
* // Use an owner (starts syncing).
@@ -592,7 +592,7 @@ export interface ErrorStoreDep {
592592
* Shared error store for all Evolu instances. Subscribe once to handle errors
593593
* globally across all instances.
594594
*
595-
* ## Example
595+
* ### Example
596596
*
597597
* ```ts
598598
* deps.evoluError.subscribe(() => {

0 commit comments

Comments
 (0)