@livestore/adapter-cloudflare 0.4.0-dev.9 → 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
+ export { type CreateStoreDoOptions, createStoreDo, createStoreDoPromise, type Env } from './create-store-do.ts';
4
4
  export { makeAdapter } from './make-adapter.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,EACL,KAAK,oBAAoB,EACzB,aAAa,EACb,oBAAoB,EACpB,KAAK,GAAG,GACT,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,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
+ export { createStoreDo, createStoreDoPromise } from "./create-store-do.js";
3
3
  export { makeAdapter } from "./make-adapter.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,EAEL,aAAa,EACb,oBAAoB,GAErB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,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.9",
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.20250923.0",
15
- "@livestore/common": "0.4.0-dev.9",
16
- "@livestore/livestore": "0.4.0-dev.9",
17
- "@livestore/sqlite-wasm": "0.4.0-dev.9",
18
- "@livestore/sync-cf": "0.4.0-dev.9",
19
- "@livestore/utils": "0.4.0-dev.9",
20
- "@livestore/common-cf": "0.4.0-dev.9"
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.38.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
 
@@ -1,13 +1,14 @@
1
- import type { HelperTypes } from '@livestore/common-cf'
1
+ import { LogConfig, type SyncOptions } from '@livestore/common'
2
+ import type { CfTypes, HelperTypes } from '@livestore/common-cf'
2
3
  import { createStore, type LiveStoreSchema, provideOtel } from '@livestore/livestore'
3
4
  import type * as CfSyncBackend from '@livestore/sync-cf/cf-worker'
4
5
  import { makeDoRpcSync } from '@livestore/sync-cf/client'
5
- import { Effect, Logger, LogLevel, Scope } from '@livestore/utils/effect'
6
- import type * as CfWorker from './cf-types.ts'
6
+ import { Effect, Logger, Scope } from '@livestore/utils/effect'
7
+
7
8
  import { makeAdapter } from './make-adapter.ts'
8
9
 
9
10
  export type Env = {
10
- SYNC_BACKEND_DO: CfWorker.DurableObjectNamespace<CfSyncBackend.SyncBackendRpcInterface>
11
+ SYNC_BACKEND_DO: CfTypes.DurableObjectNamespace<CfSyncBackend.SyncBackendRpcInterface>
11
12
  }
12
13
 
13
14
  export type CreateStoreDoOptions<TSchema extends LiveStoreSchema, TEnv, TState> = {
@@ -29,7 +30,7 @@ export type CreateStoreDoOptions<TSchema extends LiveStoreSchema, TEnv, TState>
29
30
  bindingName: HelperTypes.ExtractDurableObjectKeys<NoInfer<TEnv>>
30
31
  }
31
32
  /** RPC stub pointing at the sync backend Durable Object used for replication. */
32
- syncBackendStub: CfWorker.DurableObjectStub<CfSyncBackend.SyncBackendRpcInterface>
33
+ syncBackendStub: CfTypes.DurableObjectStub<CfSyncBackend.SyncBackendRpcInterface>
33
34
  /**
34
35
  * Enables live pull mode to receive sync updates via Durable Object RPC callbacks.
35
36
  *
@@ -42,13 +43,59 @@ export type CreateStoreDoOptions<TSchema extends LiveStoreSchema, TEnv, TState>
42
43
  * Note: Only use this for development purposes.
43
44
  */
44
45
  resetPersistence?: boolean
45
- }
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
46
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
+ */
47
94
  // TODO Also support in Cloudflare workers outside of a durable object context.
48
95
  export const createStoreDo = <
49
96
  TSchema extends LiveStoreSchema,
50
97
  TEnv,
51
- TState extends CfWorker.DurableObjectState = CfWorker.DurableObjectState,
98
+ TState extends CfTypes.DurableObjectState = CfTypes.DurableObjectState,
52
99
  >({
53
100
  schema,
54
101
  storeId,
@@ -58,6 +105,7 @@ export const createStoreDo = <
58
105
  syncBackendStub,
59
106
  livePull = false,
60
107
  resetPersistence = false,
108
+ initialSyncOptions = { _tag: 'Blocking', timeout: 500 },
61
109
  }: CreateStoreDoOptions<TSchema, TEnv, TState>) =>
62
110
  Effect.gen(function* () {
63
111
  const { ctx, bindingName } = durableObject
@@ -76,23 +124,50 @@ export const createStoreDo = <
76
124
  durableObjectContext: { bindingName, durableObjectId },
77
125
  }),
78
126
  livePull, // Uses DO RPC callbacks for reactive pull
79
- initialSyncOptions: { _tag: 'Blocking', timeout: 500 },
127
+ initialSyncOptions,
80
128
  },
81
129
  })
82
130
 
83
131
  return yield* createStore({ schema, adapter, storeId }).pipe(Scope.extend(scope), provideOtel({}))
84
132
  })
85
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
+ */
86
159
  export const createStoreDoPromise = <
87
160
  TSchema extends LiveStoreSchema,
88
161
  TEnv,
89
- TState extends CfWorker.DurableObjectState = CfWorker.DurableObjectState,
162
+ TState extends CfTypes.DurableObjectState = CfTypes.DurableObjectState,
90
163
  >(
91
164
  options: CreateStoreDoOptions<TSchema, TEnv, TState>,
92
165
  ) =>
93
166
  createStoreDo(options).pipe(
94
- Logger.withMinimumLogLevel(LogLevel.Debug),
95
- Effect.provide(Logger.consoleWithThread('DoClient')),
167
+ LogConfig.withLoggerConfig(options, {
168
+ threadName: 'DoClient',
169
+ defaultLogger: Logger.consoleWithThread('DoClient'),
170
+ }),
96
171
  Effect.tapCauseLogPretty,
97
172
  Effect.runPromise,
98
173
  )