@livestore/adapter-cloudflare 0.4.0-dev.8 → 0.4.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.
@@ -11,13 +11,15 @@ class CloudflarePreparedStatement {
11
11
  }
12
12
  execute = (bindValues, options) => {
13
13
  try {
14
- const cursor = this.sqlStorage.exec(this.sql, ...(bindValues ? Object.values(bindValues) : []));
14
+ if (isTransactionControlStatement(this.sql) === true)
15
+ return;
16
+ const cursor = this.sqlStorage.exec(this.sql, ...(bindValues !== undefined ? Object.values(bindValues) : []));
15
17
  // Count affected rows by iterating through cursor
16
18
  let changedCount = 0;
17
19
  for (const _row of cursor) {
18
20
  changedCount++;
19
21
  }
20
- if (options?.onRowsChanged) {
22
+ if (options?.onRowsChanged !== undefined) {
21
23
  options.onRowsChanged(changedCount);
22
24
  }
23
25
  }
@@ -31,7 +33,7 @@ class CloudflarePreparedStatement {
31
33
  };
32
34
  select = (bindValues) => {
33
35
  try {
34
- const cursor = this.sqlStorage.exec(this.sql, ...(bindValues ? Object.values(bindValues) : []));
36
+ const cursor = this.sqlStorage.exec(this.sql, ...(bindValues !== undefined ? Object.values(bindValues) : []));
35
37
  const results = [];
36
38
  for (const row of cursor) {
37
39
  results.push(row);
@@ -51,14 +53,12 @@ class CloudflarePreparedStatement {
51
53
  };
52
54
  }
53
55
  export const makeSqliteDb = (input) => Effect.gen(function* () {
54
- // console.log('makeSqliteDb', input)
55
56
  if (input._tag === 'in-memory') {
56
57
  return makeSqliteDb_({
57
58
  sqlStorage: input.db,
58
59
  metadata: {
59
60
  _tag: 'file',
60
61
  dbPointer: 0,
61
- // persistenceInfo: { fileName: ':memory:' },
62
62
  persistenceInfo: { fileName: 'cf' },
63
63
  input,
64
64
  configureDb: input.configureDb,
@@ -71,7 +71,6 @@ export const makeSqliteDb = (input) => Effect.gen(function* () {
71
71
  metadata: {
72
72
  _tag: 'file',
73
73
  dbPointer: 0,
74
- // persistenceInfo: { fileName: `${input.directory}/${input.databaseName}` },
75
74
  persistenceInfo: { fileName: 'cf' },
76
75
  input,
77
76
  configureDb: input.configureDb,
@@ -87,7 +86,7 @@ export const makeSqliteDb_ = ({ sqlStorage, metadata, }) => {
87
86
  metadata,
88
87
  debug: {
89
88
  // Setting initially to root but will be set to correct value shortly after
90
- head: EventSequenceNumber.ROOT,
89
+ head: EventSequenceNumber.Client.ROOT,
91
90
  },
92
91
  prepare: (queryStr) => {
93
92
  try {
@@ -126,17 +125,13 @@ export const makeSqliteDb_ = ({ sqlStorage, metadata, }) => {
126
125
  }),
127
126
  destroy: () => {
128
127
  sqliteDb.close();
129
- // metadata.deleteDb()
130
128
  throw new SqliteError({
131
129
  code: -1,
132
130
  cause: 'Database destroy not supported with public SqlStorage API',
133
131
  });
134
- // if (metadata._tag === 'opfs') {
135
- // metadata.vfs.resetAccessHandle(metadata.fileName)
136
- // }
137
132
  },
138
133
  close: () => {
139
- if (isClosed) {
134
+ if (isClosed === true) {
140
135
  return;
141
136
  }
142
137
  for (const stmt of preparedStmts) {
@@ -191,4 +186,38 @@ export const makeSqliteDb_ = ({ sqlStorage, metadata, }) => {
191
186
  metadata.configureDb(sqliteDb);
192
187
  return sqliteDb;
193
188
  };
189
+ /**
190
+ * CF DO SQLite rejects SQL-level transaction control and requires `storage.transactionSync()` instead.
191
+ * The current adapter only detects and suppresses those SQL statements. It does not yet translate the
192
+ * caller's transaction intent into a shared Durable Object storage transaction.
193
+ *
194
+ * ## Consistency implications
195
+ *
196
+ * `LeaderSyncProcessor.materializeEventsBatch()` wraps both `dbState` and `dbEventlog` in
197
+ * `BEGIN`/`COMMIT` to keep them consistent. Because this adapter drops those statements,
198
+ * eventlog INSERTs are auto-committed individually while `dbState` (VFS-backed) still has
199
+ * real transaction boundaries. If a batch partially fails, earlier eventlog rows survive
200
+ * while `dbState` rolls back.
201
+ *
202
+ * This is safe because:
203
+ * - The eventlog is append-only and idempotent — replaying already-inserted events is a no-op.
204
+ * - State is always rebuildable from the eventlog on cold start (`recreateDb`).
205
+ * - A Durable Object is single-threaded, so no concurrent reader can observe the
206
+ * intermediate inconsistency.
207
+ *
208
+ * Uses prefix matching to cover all SQLite variants:
209
+ * - `BEGIN [DEFERRED | IMMEDIATE | EXCLUSIVE] [TRANSACTION]`
210
+ * - `COMMIT [TRANSACTION]` / `END [TRANSACTION]`
211
+ * - `ROLLBACK [TRANSACTION] [TO [SAVEPOINT] name]`
212
+ * - `SAVEPOINT name` / `RELEASE [SAVEPOINT] name`
213
+ */
214
+ const isTransactionControlStatement = (sql) => {
215
+ const upper = sql.trim().toUpperCase();
216
+ return (upper.startsWith('BEGIN') === true ||
217
+ upper.startsWith('COMMIT') === true ||
218
+ upper.startsWith('END') === true ||
219
+ upper.startsWith('ROLLBACK') === true ||
220
+ upper.startsWith('SAVEPOINT') === true ||
221
+ upper.startsWith('RELEASE') === true);
222
+ };
194
223
  //# sourceMappingURL=make-sqlite-db.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"make-sqlite-db.js","sourceRoot":"","sources":["../src/make-sqlite-db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"make-sqlite-db.js","sourceRoot":"","sources":["../src/make-sqlite-db.ts"],"names":[],"mappings":"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"}
package/dist/mod.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import './polyfill.ts';
2
2
  export type { ClientDoWithRpcCallback } from '@livestore/common-cf';
3
+ export { type CreateStoreDoOptions, createStoreDo, createStoreDoPromise, type Env } from './create-store-do.ts';
3
4
  export { makeAdapter } from './make-adapter.ts';
4
- export { type CreateStoreDoOptions, createStoreDo, createStoreDoPromise, type Env, type MakeDurableObjectClass, type MakeDurableObjectClassOptions, } from './make-client-durable-object.ts';
5
5
  //# sourceMappingURL=mod.d.ts.map
package/dist/mod.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EACL,KAAK,oBAAoB,EACzB,aAAa,EACb,oBAAoB,EACpB,KAAK,GAAG,EACR,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,GACnC,MAAM,iCAAiC,CAAA"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AACnE,OAAO,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,oBAAoB,EAAE,KAAK,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAC/G,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
package/dist/mod.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import "./polyfill.js";
2
+ export { createStoreDo, createStoreDoPromise } from "./create-store-do.js";
2
3
  export { makeAdapter } from "./make-adapter.js";
3
- export { createStoreDo, createStoreDoPromise, } from "./make-client-durable-object.js";
4
4
  //# sourceMappingURL=mod.js.map
package/dist/mod.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAGtB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAEL,aAAa,EACb,oBAAoB,GAIrB,MAAM,iCAAiC,CAAA"}
1
+ {"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAGtB,OAAO,EAA6B,aAAa,EAAE,oBAAoB,EAAY,MAAM,sBAAsB,CAAA;AAC/G,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,16 @@
1
1
  {
2
2
  "name": "@livestore/adapter-cloudflare",
3
- "version": "0.4.0-dev.8",
3
+ "version": "0.4.0",
4
+ "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/livestorejs/livestore.git"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "package.json",
12
+ "src"
13
+ ],
4
14
  "type": "module",
5
15
  "sideEffects": [
6
16
  "./src/polyfill.ts",
@@ -10,26 +20,59 @@
10
20
  ".": "./dist/mod.js",
11
21
  "./polyfill": "./dist/polyfill.js"
12
22
  },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
13
26
  "dependencies": {
14
- "@cloudflare/workers-types": "4.20250823.0",
15
- "@livestore/common": "0.4.0-dev.8",
16
- "@livestore/common-cf": "0.4.0-dev.8",
17
- "@livestore/sync-cf": "0.4.0-dev.8",
18
- "@livestore/sqlite-wasm": "0.4.0-dev.8",
19
- "@livestore/livestore": "0.4.0-dev.8",
20
- "@livestore/utils": "0.4.0-dev.8"
27
+ "@cloudflare/workers-types": "4.20251118.0",
28
+ "@livestore/common": "^0.4.0",
29
+ "@livestore/common-cf": "^0.4.0",
30
+ "@livestore/livestore": "^0.4.0",
31
+ "@livestore/sqlite-wasm": "^0.4.0",
32
+ "@livestore/sync-cf": "^0.4.0",
33
+ "@livestore/utils": "^0.4.0"
21
34
  },
22
35
  "devDependencies": {
23
- "wrangler": "4.32.0"
36
+ "wrangler": "4.42.2"
24
37
  },
25
- "files": [
26
- "package.json",
27
- "src",
28
- "dist"
29
- ],
30
- "license": "Apache-2.0",
31
- "publishConfig": {
32
- "access": "public"
38
+ "peerDependencies": {
39
+ "@effect/ai": "^0.35.0",
40
+ "@effect/cli": "^0.75.1",
41
+ "@effect/cluster": "^0.58.2",
42
+ "@effect/experimental": "^0.60.0",
43
+ "@effect/opentelemetry": "^0.63.0",
44
+ "@effect/platform": "^0.96.1",
45
+ "@effect/platform-browser": "^0.76.0",
46
+ "@effect/platform-bun": "^0.89.0",
47
+ "@effect/platform-node": "^0.106.0",
48
+ "@effect/printer": "^0.49.0",
49
+ "@effect/printer-ansi": "^0.49.0",
50
+ "@effect/rpc": "^0.75.1",
51
+ "@effect/sql": "^0.51.1",
52
+ "@effect/typeclass": "^0.40.0",
53
+ "@effect/vitest": "^0.29.0",
54
+ "@opentelemetry/api": "^1.9.0",
55
+ "@opentelemetry/resources": "^2.2.0",
56
+ "@standard-schema/spec": "^1.1.0",
57
+ "effect": "^3.21.2"
58
+ },
59
+ "$genie": {
60
+ "source": "package.json.genie.ts",
61
+ "warning": "DO NOT EDIT - changes will be overwritten",
62
+ "workspaceClosureDirs": [
63
+ "packages/@livestore/adapter-cloudflare",
64
+ "packages/@livestore/adapter-web",
65
+ "packages/@livestore/common",
66
+ "packages/@livestore/common-cf",
67
+ "packages/@livestore/devtools-web-common",
68
+ "packages/@livestore/livestore",
69
+ "packages/@livestore/sqlite-wasm",
70
+ "packages/@livestore/sync-cf",
71
+ "packages/@livestore/utils",
72
+ "packages/@livestore/utils-dev",
73
+ "packages/@livestore/wa-sqlite",
74
+ "packages/@livestore/webmesh"
75
+ ]
33
76
  },
34
77
  "scripts": {
35
78
  "test": "echo No tests yet"
package/src/WebSocket.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { Schedule, Scope } from '@livestore/utils/effect'
2
- import { Effect, Exit, identity, WebSocket } from '@livestore/utils/effect'
3
- import type * as CfWorker from './cf-types.ts'
1
+ import type { CfTypes } from '@livestore/common-cf'
2
+ import { Effect, Exit, identity, type Schedule, type Scope } from '@livestore/utils/effect'
3
+ import { WebSocket } from '@livestore/utils/effect/browser'
4
4
 
5
5
  // TODO refactor using Effect socket implementation
6
6
  // https://github.com/Effect-TS/effect/blob/main/packages%2Fexperimental%2Fsrc%2FDevTools%2FClient.ts#L113
@@ -18,23 +18,27 @@ export const makeWebSocket = ({
18
18
  durableObject,
19
19
  }: {
20
20
  /** CF Sync Backend DO with `/sync` endpoint */
21
- durableObject: CfWorker.DurableObjectStub
21
+ durableObject: CfTypes.DurableObjectStub
22
22
  url: URL
23
23
  reconnect?: Schedule.Schedule<unknown> | false
24
- }): Effect.Effect<CfWorker.WebSocket, WebSocket.WebSocketError, Scope.Scope> =>
24
+ }): Effect.Effect<CfTypes.WebSocket, WebSocket.WebSocketError, Scope.Scope> =>
25
25
  Effect.gen(function* () {
26
26
  // yield* validateUrl(url)
27
27
 
28
28
  const socket = yield* Effect.tryPromise({
29
29
  try: () =>
30
- durableObject.fetch(url, { headers: { Upgrade: 'websocket' } }).then((res: any) => {
31
- if (!res.webSocket) {
30
+ // NOTE: .toString() required due to type mismatch between standard URL and CF's URL types
31
+ durableObject.fetch(url.toString(), { headers: { Upgrade: 'websocket' } }).then((res: any) => {
32
+ if (res.webSocket == null) {
32
33
  throw new Error('WebSocket upgrade failed')
33
34
  }
34
- return res.webSocket as CfWorker.WebSocket
35
+ return res.webSocket as CfTypes.WebSocket
35
36
  }),
36
37
  catch: (cause) => new WebSocket.WebSocketError({ cause }),
37
- }).pipe(reconnect ? Effect.retry(reconnect) : identity, Effect.withSpan('make-websocket-durable-object'))
38
+ }).pipe(
39
+ reconnect !== undefined && reconnect !== false ? Effect.retry(reconnect) : identity,
40
+ Effect.withSpan('make-websocket-durable-object'),
41
+ )
38
42
 
39
43
  socket.accept()
40
44
 
@@ -53,15 +57,16 @@ export const makeWebSocket = ({
53
57
  */
54
58
  yield* Effect.addFinalizer(
55
59
  Effect.fn(function* (exit) {
56
- try {
57
- if (Exit.isFailure(exit)) {
58
- socket.close(3000)
59
- } else {
60
- socket.close(1000)
61
- }
62
- } catch (error) {
63
- yield* Effect.die(new WebSocket.WebSocketError({ cause: error }))
64
- }
60
+ yield* Effect.try({
61
+ try: () => {
62
+ if (Exit.isFailure(exit) === true) {
63
+ socket.close(3000)
64
+ } else {
65
+ socket.close(1000)
66
+ }
67
+ },
68
+ catch: (error) => new WebSocket.WebSocketError({ cause: error }),
69
+ }).pipe(Effect.orDie)
65
70
  }),
66
71
  )
67
72
 
@@ -0,0 +1,173 @@
1
+ import { LogConfig, type SyncOptions } from '@livestore/common'
2
+ import type { CfTypes, HelperTypes } from '@livestore/common-cf'
3
+ import { createStore, type LiveStoreSchema, provideOtel } from '@livestore/livestore'
4
+ import type * as CfSyncBackend from '@livestore/sync-cf/cf-worker'
5
+ import { makeDoRpcSync } from '@livestore/sync-cf/client'
6
+ import { Effect, Logger, Scope } from '@livestore/utils/effect'
7
+
8
+ import { makeAdapter } from './make-adapter.ts'
9
+
10
+ export type Env = {
11
+ SYNC_BACKEND_DO: CfTypes.DurableObjectNamespace<CfSyncBackend.SyncBackendRpcInterface>
12
+ }
13
+
14
+ export type CreateStoreDoOptions<TSchema extends LiveStoreSchema, TEnv, TState> = {
15
+ /** LiveStore schema that defines state, migrations, and validators. */
16
+ schema: TSchema
17
+ /** Logical identifier for the store instance persisted inside the Durable Object. */
18
+ storeId: string
19
+ /** Unique identifier for the client that owns the Durable Object instance. */
20
+ clientId: string
21
+ /** Identifier for the LiveStore session running inside the Durable Object. */
22
+ sessionId: string
23
+ /** Runtime details about the Durable Object this store runs inside. Needed for sync backend to call back to this instance. */
24
+ durableObject: {
25
+ /** Durable Object state handle (e.g. `this.ctx`). */
26
+ ctx: TState
27
+ /** Environment bindings associated with the Durable Object. */
28
+ env: TEnv
29
+ /** Binding name Cloudflare uses to reach this Durable Object from other workers. */
30
+ bindingName: HelperTypes.ExtractDurableObjectKeys<NoInfer<TEnv>>
31
+ }
32
+ /** RPC stub pointing at the sync backend Durable Object used for replication. */
33
+ syncBackendStub: CfTypes.DurableObjectStub<CfSyncBackend.SyncBackendRpcInterface>
34
+ /**
35
+ * Enables live pull mode to receive sync updates via Durable Object RPC callbacks.
36
+ *
37
+ * @default false
38
+ */
39
+ livePull?: boolean
40
+ /**
41
+ * Clears existing Durable Object persistence before bootstrapping the store.
42
+ *
43
+ * Note: Only use this for development purposes.
44
+ */
45
+ resetPersistence?: boolean
46
+ /**
47
+ * Controls how initial sync behaves when the store boots.
48
+ *
49
+ * @default { _tag: 'Blocking', timeout: 500 }
50
+ */
51
+ initialSyncOptions?: SyncOptions['initialSyncOptions']
52
+ } & LogConfig.WithLoggerOptions
53
+
54
+ /**
55
+ * Creates a LiveStore instance inside a Cloudflare Durable Object.
56
+ *
57
+ * This function bootstraps a full LiveStore client within a Durable Object, enabling
58
+ * persistent state management with automatic sync to a sync backend. Use this when you
59
+ * need server-side LiveStore instances that can communicate with other clients.
60
+ *
61
+ * Returns an Effect that resolves to a Store instance. For a Promise-based API,
62
+ * use `createStoreDoPromise` instead.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * import { createStoreDo } from '@livestore/adapter-cloudflare'
67
+ * import { schema } from './schema'
68
+ *
69
+ * export class MyDurableObject extends DurableObject {
70
+ * store: Store | undefined
71
+ *
72
+ * async fetch(request: Request) {
73
+ * if (!this.store) {
74
+ * this.store = await createStoreDo({
75
+ * schema,
76
+ * storeId: 'my-store',
77
+ * clientId: this.ctx.id.toString(),
78
+ * sessionId: 'do-session',
79
+ * durableObject: {
80
+ * ctx: this.ctx,
81
+ * env: this.env,
82
+ * bindingName: 'MY_DO',
83
+ * },
84
+ * syncBackendStub: this.env.SYNC_BACKEND_DO.get(syncBackendId),
85
+ * }).pipe(Effect.runPromise)
86
+ * }
87
+ * // Use this.store...
88
+ * }
89
+ * }
90
+ * ```
91
+ *
92
+ * @see https://livestore.dev/docs/reference/adapters/cloudflare for setup guide
93
+ */
94
+ // TODO Also support in Cloudflare workers outside of a durable object context.
95
+ export const createStoreDo = <
96
+ TSchema extends LiveStoreSchema,
97
+ TEnv,
98
+ TState extends CfTypes.DurableObjectState = CfTypes.DurableObjectState,
99
+ >({
100
+ schema,
101
+ storeId,
102
+ clientId,
103
+ sessionId,
104
+ durableObject,
105
+ syncBackendStub,
106
+ livePull = false,
107
+ resetPersistence = false,
108
+ initialSyncOptions = { _tag: 'Blocking', timeout: 500 },
109
+ }: CreateStoreDoOptions<TSchema, TEnv, TState>) =>
110
+ Effect.gen(function* () {
111
+ const { ctx, bindingName } = durableObject
112
+ const storage = ctx.storage
113
+ const durableObjectId = ctx.id.toString()
114
+ const scope = yield* Scope.make()
115
+
116
+ const adapter = makeAdapter({
117
+ clientId,
118
+ sessionId,
119
+ storage,
120
+ resetPersistence,
121
+ syncOptions: {
122
+ backend: makeDoRpcSync({
123
+ syncBackendStub,
124
+ durableObjectContext: { bindingName, durableObjectId },
125
+ }),
126
+ livePull, // Uses DO RPC callbacks for reactive pull
127
+ initialSyncOptions,
128
+ },
129
+ })
130
+
131
+ return yield* createStore({ schema, adapter, storeId }).pipe(Scope.extend(scope), provideOtel({}))
132
+ })
133
+
134
+ /**
135
+ * Promise-based wrapper around `createStoreDo` for simpler async/await usage.
136
+ *
137
+ * Equivalent to calling `createStoreDo(options).pipe(Effect.runPromise)` with
138
+ * logging configured automatically.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * import { createStoreDoPromise } from '@livestore/adapter-cloudflare'
143
+ *
144
+ * export class MyDurableObject extends DurableObject {
145
+ * async fetch(request: Request) {
146
+ * const store = await createStoreDoPromise({
147
+ * schema,
148
+ * storeId: 'my-store',
149
+ * clientId: this.ctx.id.toString(),
150
+ * sessionId: 'do-session',
151
+ * durableObject: { ctx: this.ctx, env: this.env, bindingName: 'MY_DO' },
152
+ * syncBackendStub: this.env.SYNC_BACKEND_DO.get(syncBackendId),
153
+ * })
154
+ * // Use store...
155
+ * }
156
+ * }
157
+ * ```
158
+ */
159
+ export const createStoreDoPromise = <
160
+ TSchema extends LiveStoreSchema,
161
+ TEnv,
162
+ TState extends CfTypes.DurableObjectState = CfTypes.DurableObjectState,
163
+ >(
164
+ options: CreateStoreDoOptions<TSchema, TEnv, TState>,
165
+ ) =>
166
+ createStoreDo(options).pipe(
167
+ LogConfig.withLoggerConfig(options, {
168
+ threadName: 'DoClient',
169
+ defaultLogger: Logger.consoleWithThread('DoClient'),
170
+ }),
171
+ Effect.tapCauseLogPretty,
172
+ Effect.runPromise,
173
+ )