@spooky-sync/client-solid 0.0.1-canary.5 → 0.0.1-canary.50

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.
@@ -0,0 +1,264 @@
1
+ ---
2
+ name: sp00ky-solid
3
+ description: >-
4
+ SolidJS integration for the Sp00ky reactive local-first SurrealDB framework.
5
+ Use when setting up Sp00kyProvider, using useQuery for reactive data, building
6
+ queries with QueryBuilder in SolidJS components, handling mutations, auth,
7
+ file uploads/downloads, or working with Sp00ky types like Model and RecordId.
8
+ metadata:
9
+ author: sp00ky-sync
10
+ version: "0.0.1"
11
+ ---
12
+
13
+ # Sp00ky SolidJS Client
14
+
15
+ `@spooky-sync/client-solid` provides SolidJS bindings for the Sp00ky framework. It wraps `@spooky-sync/core` with a context provider, reactive `useQuery` hook, and file operation hooks.
16
+
17
+ ## Setup
18
+
19
+ ```tsx
20
+ import { Sp00kyProvider } from '@spooky-sync/client-solid';
21
+ import { schema } from './generated/schema';
22
+ import schemaSurql from './generated/schema.surql?raw';
23
+
24
+ function App() {
25
+ return (
26
+ <Sp00kyProvider
27
+ config={{
28
+ database: {
29
+ endpoint: 'ws://localhost:8000',
30
+ namespace: 'my_ns',
31
+ database: 'my_db',
32
+ store: 'indexeddb',
33
+ },
34
+ schema,
35
+ schemaSurql,
36
+ logLevel: 'info',
37
+ }}
38
+ fallback={<div>Loading database...</div>}
39
+ onReady={(db) => console.log('DB ready')}
40
+ onError={(err) => console.error('DB failed', err)}
41
+ >
42
+ <MyApp />
43
+ </Sp00kyProvider>
44
+ );
45
+ }
46
+ ```
47
+
48
+ ### Sp00kyProvider Props
49
+
50
+ | Prop | Type | Description |
51
+ |------|------|-------------|
52
+ | `config` | `SyncedDbConfig<S>` | Same as `Sp00kyConfig` from core |
53
+ | `fallback` | `JSX.Element` | Shown while the database is initializing |
54
+ | `onReady` | `(db: SyncedDb<S>) => void` | Called when initialization succeeds |
55
+ | `onError` | `(error: Error) => void` | Called if initialization fails |
56
+ | `children` | `JSX.Element` | App content, rendered after init |
57
+
58
+ ## useQuery
59
+
60
+ The primary hook for reactive data fetching. Queries automatically re-subscribe when inputs change.
61
+
62
+ ### Context-based usage (recommended)
63
+
64
+ ```tsx
65
+ import { useQuery } from '@spooky-sync/client-solid';
66
+ import { QueryBuilder } from '@spooky-sync/query-builder';
67
+ import { schema } from './generated/schema';
68
+
69
+ function PostList() {
70
+ const db = useDb();
71
+
72
+ // Static query
73
+ const posts = useQuery(
74
+ db.query('post').orderBy('createdAt', 'desc').limit(20).build()
75
+ );
76
+
77
+ return (
78
+ <Show when={!posts.isLoading()} fallback={<div>Loading...</div>}>
79
+ <For each={posts.data()}>
80
+ {(post) => <div>{post.title}</div>}
81
+ </For>
82
+ </Show>
83
+ );
84
+ }
85
+ ```
86
+
87
+ ### Reactive queries (function form)
88
+
89
+ Wrap the query in a function to make it reactive to signal changes:
90
+
91
+ ```tsx
92
+ function UserPosts(props: { userId: string }) {
93
+ const db = useDb();
94
+
95
+ // Query re-runs when props.userId changes
96
+ const posts = useQuery(
97
+ () => db.query('post')
98
+ .where({ author: props.userId })
99
+ .related('author')
100
+ .build()
101
+ );
102
+
103
+ return <For each={posts.data()}>{(post) => <div>{post.title}</div>}</For>;
104
+ }
105
+ ```
106
+
107
+ ### Conditional queries
108
+
109
+ Use the `enabled` option to conditionally run queries:
110
+
111
+ ```tsx
112
+ const [userId, setUserId] = createSignal<string | null>(null);
113
+
114
+ const user = useQuery(
115
+ () => userId()
116
+ ? db.query('user').where({ id: userId()! }).one().build()
117
+ : undefined,
118
+ { enabled: () => userId() !== null }
119
+ );
120
+ ```
121
+
122
+ ### Return value
123
+
124
+ | Property | Type | Description |
125
+ |----------|------|-------------|
126
+ | `data` | `() => T \| undefined` | Reactive accessor for query results |
127
+ | `error` | `() => Error \| undefined` | Reactive accessor for errors |
128
+ | `isLoading` | `() => boolean` | `true` until first data arrives |
129
+
130
+ ### Explicit db overload
131
+
132
+ You can also pass the `SyncedDb` instance directly (legacy):
133
+
134
+ ```tsx
135
+ const posts = useQuery(db, db.query('post').build());
136
+ ```
137
+
138
+ ## useDb
139
+
140
+ Access the `SyncedDb` instance from context:
141
+
142
+ ```tsx
143
+ import { useDb } from '@spooky-sync/client-solid';
144
+
145
+ function MyComponent() {
146
+ const db = useDb();
147
+ // db.query(), db.create(), db.update(), db.delete(), db.auth, etc.
148
+ }
149
+ ```
150
+
151
+ ## Mutations
152
+
153
+ Use the `SyncedDb` instance (from `useDb()`) for mutations:
154
+
155
+ ```tsx
156
+ const db = useDb();
157
+
158
+ // Create
159
+ await db.create('post:abc', { title: 'Hello', body: 'World', author: 'user:alice' });
160
+
161
+ // Update
162
+ await db.update('post', 'post:abc', { title: 'Updated' });
163
+
164
+ // Update with debounce
165
+ await db.update('post', 'post:abc', { body: newText }, {
166
+ debounced: { key: 'recordId_x_fields', delay: 300 },
167
+ });
168
+
169
+ // Delete
170
+ await db.delete('post', 'post:abc');
171
+ ```
172
+
173
+ ## Authentication
174
+
175
+ ```tsx
176
+ const db = useDb();
177
+
178
+ await db.auth.signUp('user_access', { email, password, name });
179
+ await db.auth.signIn('user_access', { email, password });
180
+ await db.auth.signOut();
181
+
182
+ // Subscribe to auth state
183
+ const unsub = db.auth.subscribe((userId) => { ... });
184
+ ```
185
+
186
+ ## File Upload & Download
187
+
188
+ See [references/file-hooks.md](references/file-hooks.md) for details.
189
+
190
+ ```tsx
191
+ import { useFileUpload, useDownloadFile } from '@spooky-sync/client-solid';
192
+
193
+ // Upload
194
+ const { upload, isUploading, error } = useFileUpload('avatars');
195
+ await upload('alice/photo.png', file);
196
+
197
+ // Download (reactive)
198
+ const { url, isLoading } = useDownloadFile('avatars', () => user()?.avatarPath);
199
+ ```
200
+
201
+ ## Backend Runs
202
+
203
+ Use `db.run()` to trigger server-side operations via the outbox pattern. See the `sp00ky-core` skill for full details on `db.run()` and how it works.
204
+
205
+ ### Basic Usage
206
+
207
+ ```tsx
208
+ const db = useDb();
209
+ await db.run('api', '/spookify', { id: threadId });
210
+ ```
211
+
212
+ ### Entity Linking with `assignedTo`
213
+
214
+ Pass `assignedTo` to link the job to an entity. This enables permission scoping and lets you query job status via relationships:
215
+
216
+ ```tsx
217
+ const db = useDb();
218
+
219
+ // Trigger backend run linked to a thread
220
+ await db.run('api', '/spookify', { id: threadData.id }, {
221
+ assignedTo: threadData.id, // Links the job record to this thread
222
+ });
223
+ ```
224
+
225
+ ### Tracking Job Status Reactively
226
+
227
+ Use `.related()` to include jobs in your query, then reactively track their status:
228
+
229
+ ```tsx
230
+ // Query a thread with its latest spookify job
231
+ const threadResult = useQuery(() =>
232
+ db.query('thread')
233
+ .where({ id: `thread:${threadId}` })
234
+ .related('jobs', (q) =>
235
+ q.where({ path: '/spookify' }).orderBy('created_at', 'desc').limit(1)
236
+ )
237
+ .one()
238
+ .build()
239
+ );
240
+
241
+ const thread = () => threadResult.data();
242
+
243
+ // Check if a job is in progress
244
+ const isJobLoading = () =>
245
+ ['pending', 'processing'].includes(thread()?.jobs?.[0]?.status ?? '');
246
+
247
+ // Use in UI
248
+ <Show when={isJobLoading()}>
249
+ <span>Processing...</span>
250
+ </Show>
251
+ ```
252
+
253
+ The job's `status` field transitions through: `pending` → `processing` → `success` | `failed`. Since the job record syncs reactively, your UI updates automatically as the backend processes the job.
254
+
255
+ ## Key Re-exports
256
+
257
+ The package re-exports commonly needed types:
258
+
259
+ ```typescript
260
+ import { RecordId, Uuid } from '@spooky-sync/client-solid';
261
+ import type {
262
+ Model, GenericModel, QueryResult, TableModel, TableNames, GetTable,
263
+ } from '@spooky-sync/client-solid';
264
+ ```
@@ -0,0 +1,112 @@
1
+ # File Hooks Reference
2
+
3
+ ## useFileUpload
4
+
5
+ Upload, download, and manage files in a SurrealDB bucket.
6
+
7
+ ### Signatures
8
+
9
+ ```typescript
10
+ // Context-based (inside Sp00kyProvider)
11
+ useFileUpload<S>(bucketName: BucketNames<S>): FileUploadResult;
12
+
13
+ // Explicit db
14
+ useFileUpload<S>(db: SyncedDb<S>, bucketName: BucketNames<S>): FileUploadResult;
15
+ ```
16
+
17
+ ### Return Value
18
+
19
+ ```typescript
20
+ interface FileUploadResult {
21
+ isUploading: () => boolean;
22
+ error: () => Error | null;
23
+ clearError: () => void;
24
+ upload: (path: string, file: File | Blob) => Promise<void>;
25
+ download: (path: string) => Promise<string | null>; // Returns object URL
26
+ remove: (path: string) => Promise<void>;
27
+ exists: (path: string) => Promise<boolean>;
28
+ }
29
+ ```
30
+
31
+ ### Validation
32
+
33
+ If the bucket has `maxSize` or `allowedExtensions` configured in the schema, the hook validates files before upload and sets `error()` on failure.
34
+
35
+ ### Example
36
+
37
+ ```tsx
38
+ function AvatarUpload() {
39
+ const { upload, isUploading, error, clearError } = useFileUpload('avatars');
40
+
41
+ const handleFile = async (e: Event) => {
42
+ const file = (e.target as HTMLInputElement).files?.[0];
43
+ if (file) {
44
+ await upload(`user/${userId()}/avatar.png`, file);
45
+ }
46
+ };
47
+
48
+ return (
49
+ <div>
50
+ <input type="file" onChange={handleFile} disabled={isUploading()} />
51
+ <Show when={error()}>
52
+ <p class="error">{error()!.message}</p>
53
+ <button onClick={clearError}>Dismiss</button>
54
+ </Show>
55
+ </div>
56
+ );
57
+ }
58
+ ```
59
+
60
+ ## useDownloadFile
61
+
62
+ Reactively download a file from a bucket. Re-fetches when the path changes.
63
+
64
+ ### Signatures
65
+
66
+ ```typescript
67
+ // Context-based
68
+ useDownloadFile<S>(
69
+ bucketName: BucketNames<S>,
70
+ path: Accessor<string | null | undefined>,
71
+ options?: { cache?: boolean },
72
+ ): UseDownloadFileResult;
73
+
74
+ // Explicit db
75
+ useDownloadFile<S>(
76
+ db: SyncedDb<S>,
77
+ bucketName: BucketNames<S>,
78
+ path: Accessor<string | null | undefined>,
79
+ options?: { cache?: boolean },
80
+ ): UseDownloadFileResult;
81
+ ```
82
+
83
+ ### Return Value
84
+
85
+ ```typescript
86
+ interface UseDownloadFileResult {
87
+ url: Accessor<string | null>; // Object URL for the file
88
+ isLoading: Accessor<boolean>;
89
+ error: Accessor<Error | null>;
90
+ refetch: () => void; // Force re-download (evicts cache)
91
+ }
92
+ ```
93
+
94
+ ### Caching
95
+
96
+ By default, downloads are cached by `bucket:path` key with reference counting. Object URLs are revoked when no component references them. Set `cache: false` to disable.
97
+
98
+ ### Example
99
+
100
+ ```tsx
101
+ function Avatar(props: { path: string | null }) {
102
+ const { url, isLoading } = useDownloadFile('avatars', () => props.path);
103
+
104
+ return (
105
+ <Show when={!isLoading()} fallback={<Spinner />}>
106
+ <Show when={url()}>
107
+ <img src={url()!} alt="Avatar" />
108
+ </Show>
109
+ </Show>
110
+ );
111
+ }
112
+ ```
@@ -1,6 +1,6 @@
1
1
  export { SurrealDBWasmFactory } from './surrealdb-wasm-factory';
2
2
 
3
- import { Surreal } from 'surrealdb';
3
+ import type { Surreal } from 'surrealdb';
4
4
  import type { CacheStrategy } from '../types';
5
5
 
6
6
  /**
@@ -1,9 +1,11 @@
1
- import { Diagnostic, Surreal, applyDiagnostics } from 'surrealdb';
1
+ import type { Diagnostic} from 'surrealdb';
2
+ import { Surreal, applyDiagnostics } from 'surrealdb';
2
3
  import { createWasmEngines } from '@surrealdb/wasm';
3
4
  import type { CacheStrategy } from '../types';
4
5
 
5
6
  const printDiagnostic = ({ key, type, phase, ...other }: Diagnostic) => {
6
7
  if (phase === 'progress' || phase === 'after') {
8
+ // oxlint-disable-next-line no-console -- intentional diagnostic logging
7
9
  console.log(`[SurrealDB_WASM] [${key}] ${type}:${phase}\n${JSON.stringify(other, null, 2)}`);
8
10
  }
9
11
  };
@@ -11,6 +13,7 @@ const printDiagnostic = ({ key, type, phase, ...other }: Diagnostic) => {
11
13
  /**
12
14
  * SurrealDB WASM client factory for different storage strategies
13
15
  */
16
+ // oxlint-disable-next-line no-extraneous-class -- factory pattern groups related static methods
14
17
  export class SurrealDBWasmFactory {
15
18
  /**
16
19
  * Creates a SurrealDB WASM instance with the specified storage strategy
package/src/index.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import type { SyncedDbConfig } from './types';
2
2
  import {
3
- SpookyClient,
4
- AuthService,
5
- BucketHandle,
6
- type SpookyQueryResultPromise,
7
- UpdateOptions,
8
- RunOptions,
3
+ Sp00kyClient,
4
+ type Sp00kyQueryResultPromise,
5
+ type AuthService,
6
+ type BucketHandle,
7
+ type UpdateOptions,
8
+ type RunOptions,
9
9
  } from '@spooky-sync/core';
10
10
 
11
- import {
11
+ import type {
12
12
  GetTable,
13
13
  QueryBuilder,
14
14
  SchemaStructure,
@@ -25,19 +25,26 @@ import {
25
25
  RoutePayload,
26
26
  BucketNames,
27
27
  BucketDefinitionSchema,
28
+ QueryModifier,
29
+ QueryModifierBuilder,
30
+ QueryInfo,
31
+ RelationshipsMetadata,
32
+ RelationshipDefinition,
33
+ InferRelatedModelFromMetadata,
34
+ GetCardinality,
28
35
  } from '@spooky-sync/query-builder';
29
36
 
30
- import { RecordId, Uuid, Surreal } from 'surrealdb';
37
+ import { RecordId, Uuid, type Surreal } from 'surrealdb';
31
38
  export { RecordId, Uuid };
32
39
  export type { Model, GenericModel, GenericSchema, ModelPayload } from './lib/models';
33
40
  export { useQuery } from './lib/use-query';
34
41
  export { useFileUpload, type FileUploadResult } from './lib/use-file-upload';
35
42
  export { useDownloadFile, type UseDownloadFileOptions, type UseDownloadFileResult } from './lib/use-download-file';
36
- export { SpookyProvider, type SpookyProviderProps } from './lib/SpookyProvider';
43
+ export { Sp00kyProvider, type Sp00kyProviderProps } from './lib/Sp00kyProvider';
37
44
  export { useDb } from './lib/context';
38
45
 
39
46
  // export { AuthEventTypes } from "@spooky-sync/core"; // TODO: Verify if AuthEventTypes exists in core
40
- export type {};
47
+
41
48
 
42
49
  // Re-export query builder types for convenience
43
50
  export type {
@@ -52,7 +59,7 @@ export type {
52
59
  TableModel,
53
60
  TableNames,
54
61
  QueryResult,
55
- } from '@spooky-sync/query-builder';
62
+ };
56
63
 
57
64
  export type RelationshipField<
58
65
  Schema extends SchemaStructure,
@@ -94,30 +101,30 @@ export type WithRelatedMany<Field extends string, RelatedFields extends RelatedF
94
101
  };
95
102
 
96
103
  /**
97
- * SyncedDb - A thin wrapper around spooky-ts for Solid.js integration
98
- * Delegates all logic to the underlying spooky-ts instance
104
+ * SyncedDb - A thin wrapper around sp00ky-ts for Solid.js integration
105
+ * Delegates all logic to the underlying sp00ky-ts instance
99
106
  */
100
107
  export class SyncedDb<S extends SchemaStructure> {
101
108
  private config: SyncedDbConfig<S>;
102
- private spooky: SpookyClient<S> | null = null;
109
+ private sp00ky: Sp00kyClient<S> | null = null;
103
110
  private _initialized = false;
104
111
 
105
112
  constructor(config: SyncedDbConfig<S>) {
106
113
  this.config = config;
107
114
  }
108
115
 
109
- public getSpooky(): SpookyClient<S> {
110
- if (!this.spooky) throw new Error('SyncedDb not initialized');
111
- return this.spooky;
116
+ public getSp00ky(): Sp00kyClient<S> {
117
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
118
+ return this.sp00ky;
112
119
  }
113
120
 
114
121
  /**
115
- * Initialize the spooky-ts instance
122
+ * Initialize the sp00ky-ts instance
116
123
  */
117
124
  async init(): Promise<void> {
118
125
  if (this._initialized) return;
119
- this.spooky = new SpookyClient<S>(this.config);
120
- await this.spooky.init();
126
+ this.sp00ky = new Sp00kyClient<S>(this.config);
127
+ await this.sp00ky.init();
121
128
  this._initialized = true;
122
129
  }
123
130
 
@@ -125,8 +132,8 @@ export class SyncedDb<S extends SchemaStructure> {
125
132
  * Create a new record in the database
126
133
  */
127
134
  async create(id: string, payload: Record<string, unknown>): Promise<void> {
128
- if (!this.spooky) throw new Error('SyncedDb not initialized');
129
- await this.spooky.create(id, payload as Record<string, unknown>);
135
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
136
+ await this.sp00ky.create(id, payload as Record<string, unknown>);
130
137
  }
131
138
 
132
139
  /**
@@ -138,8 +145,8 @@ export class SyncedDb<S extends SchemaStructure> {
138
145
  payload: Partial<TableModel<GetTable<S, TName>>>,
139
146
  options?: UpdateOptions
140
147
  ): Promise<void> {
141
- if (!this.spooky) throw new Error('SyncedDb not initialized');
142
- await this.spooky.update(
148
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
149
+ await this.sp00ky.update(
143
150
  tableName as string,
144
151
  recordId,
145
152
  payload as Record<string, unknown>,
@@ -154,10 +161,10 @@ export class SyncedDb<S extends SchemaStructure> {
154
161
  tableName: TName,
155
162
  selector: string | InnerQuery<GetTable<S, TName>, boolean>
156
163
  ): Promise<void> {
157
- if (!this.spooky) throw new Error('SyncedDb not initialized');
164
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
158
165
  if (typeof selector !== 'string')
159
166
  throw new Error('Only string ID selectors are supported currently with core');
160
- await this.spooky.delete(tableName as string, selector);
167
+ await this.sp00ky.delete(tableName as string, selector);
161
168
  }
162
169
 
163
170
  /**
@@ -165,9 +172,9 @@ export class SyncedDb<S extends SchemaStructure> {
165
172
  */
166
173
  public query<TName extends TableNames<S>>(
167
174
  table: TName
168
- ): QueryBuilder<S, TName, SpookyQueryResultPromise, {}, false> {
169
- if (!this.spooky) throw new Error('SyncedDb not initialized');
170
- return this.spooky.query(table, {});
175
+ ): QueryBuilder<S, TName, Sp00kyQueryResultPromise, {}, false> {
176
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
177
+ return this.sp00ky.query(table, {});
171
178
  }
172
179
 
173
180
  /**
@@ -182,17 +189,17 @@ export class SyncedDb<S extends SchemaStructure> {
182
189
  payload: RoutePayload<S, B, R>,
183
190
  options?: RunOptions,
184
191
  ): Promise<void> {
185
- if (!this.spooky) throw new Error('SyncedDb not initialized');
186
- await this.spooky.run(backend, path, payload, options);
192
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
193
+ await this.sp00ky.run(backend, path, payload, options);
187
194
  }
188
195
 
189
196
  /**
190
197
  * Authenticate with the database
191
198
  */
192
199
  public async authenticate(token: string): Promise<RecordId<string>> {
193
- const result = await this.spooky?.authenticate(token);
194
- // SpookyClient.authenticate returns whatever remote.authenticate returns (boolean or token usually?)
195
- // Wait, checked SpookyClient: return this.remote.getClient().authenticate(token);
200
+ await this.sp00ky?.authenticate(token);
201
+ // Sp00kyClient.authenticate returns whatever remote.authenticate returns (boolean or token usually?)
202
+ // Wait, checked Sp00kyClient: return this.remote.getClient().authenticate(token);
196
203
  // SurrealDB authenticate returns void? or token?
197
204
  // Assuming void or token.
198
205
  return new RecordId('user', 'me'); // Placeholder or actual?
@@ -210,54 +217,54 @@ export class SyncedDb<S extends SchemaStructure> {
210
217
  * Sign out, clear session and local storage
211
218
  */
212
219
  public async signOut(): Promise<void> {
213
- if (!this.spooky) throw new Error('SyncedDb not initialized');
214
- await this.spooky.auth.signOut();
220
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
221
+ await this.sp00ky.auth.signOut();
215
222
  }
216
223
 
217
224
  /**
218
225
  * Execute a function with direct access to the remote database connection
219
226
  */
220
227
  public async useRemote<T>(fn: (db: Surreal) => T | Promise<T>): Promise<T> {
221
- if (!this.spooky) throw new Error('SyncedDb not initialized');
222
- return await this.spooky.useRemote(fn);
228
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
229
+ return await this.sp00ky.useRemote(fn);
223
230
  }
224
231
  /**
225
232
  * Access the remote database service directly
226
233
  */
227
- get remote(): SpookyClient<S>['remoteClient'] {
228
- if (!this.spooky) throw new Error('SyncedDb not initialized');
229
- return this.spooky.remoteClient;
234
+ get remote(): Sp00kyClient<S>['remoteClient'] {
235
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
236
+ return this.sp00ky.remoteClient;
230
237
  }
231
238
 
232
239
  /**
233
240
  * Access the local database service directly
234
241
  */
235
- get local(): SpookyClient<S>['localClient'] {
236
- if (!this.spooky) throw new Error('SyncedDb not initialized');
237
- return this.spooky.localClient;
242
+ get local(): Sp00kyClient<S>['localClient'] {
243
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
244
+ return this.sp00ky.localClient;
238
245
  }
239
246
 
240
247
  /**
241
248
  * Access the auth service
242
249
  */
243
250
  get auth(): AuthService<S> {
244
- if (!this.spooky) throw new Error('SyncedDb not initialized');
245
- return this.spooky.auth;
251
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
252
+ return this.sp00ky.auth;
246
253
  }
247
254
 
248
255
  get pendingMutationCount(): number {
249
- if (!this.spooky) throw new Error('SyncedDb not initialized');
250
- return this.spooky.pendingMutationCount;
256
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
257
+ return this.sp00ky.pendingMutationCount;
251
258
  }
252
259
 
253
260
  subscribeToPendingMutations(cb: (count: number) => void): () => void {
254
- if (!this.spooky) throw new Error('SyncedDb not initialized');
255
- return this.spooky.subscribeToPendingMutations(cb);
261
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
262
+ return this.sp00ky.subscribeToPendingMutations(cb);
256
263
  }
257
264
 
258
265
  bucket<B extends BucketNames<S>>(name: B): BucketHandle {
259
- if (!this.spooky) throw new Error('SyncedDb not initialized');
260
- return this.spooky.bucket(name);
266
+ if (!this.sp00ky) throw new Error('SyncedDb not initialized');
267
+ return this.sp00ky.bucket(name);
261
268
  }
262
269
 
263
270
  getBucketConfig(name: string): BucketDefinitionSchema | undefined {
@@ -1,10 +1,11 @@
1
- import { createSignal, onMount, createComponent, createMemo, JSX, mergeProps } from 'solid-js';
1
+ import type { JSX} from 'solid-js';
2
+ import { createSignal, onMount, createComponent, createMemo, mergeProps } from 'solid-js';
2
3
  import type { SchemaStructure } from '@spooky/query-builder';
3
4
  import type { SyncedDbConfig } from '../types';
4
5
  import { SyncedDb } from '../index';
5
- import { SpookyContext } from './context';
6
+ import { Sp00kyContext } from './context';
6
7
 
7
- export interface SpookyProviderProps<S extends SchemaStructure> {
8
+ export interface Sp00kyProviderProps<S extends SchemaStructure> {
8
9
  config: SyncedDbConfig<S>;
9
10
  fallback?: JSX.Element;
10
11
  onError?: (error: Error) => void;
@@ -12,8 +13,8 @@ export interface SpookyProviderProps<S extends SchemaStructure> {
12
13
  children: JSX.Element;
13
14
  }
14
15
 
15
- export function SpookyProvider<S extends SchemaStructure>(
16
- props: SpookyProviderProps<S>
16
+ export function Sp00kyProvider<S extends SchemaStructure>(
17
+ props: Sp00kyProviderProps<S>
17
18
  ): JSX.Element {
18
19
  const merged = mergeProps(
19
20
  {
@@ -35,7 +36,8 @@ export function SpookyProvider<S extends SchemaStructure>(
35
36
  if (merged.onError) {
36
37
  merged.onError(error);
37
38
  } else {
38
- console.error('SpookyProvider: Failed to initialize database', error);
39
+ // oxlint-disable-next-line no-console
40
+ console.error('Sp00kyProvider: Failed to initialize database', error);
39
41
  }
40
42
  }
41
43
  });
@@ -43,7 +45,7 @@ export function SpookyProvider<S extends SchemaStructure>(
43
45
  const content = createMemo(() => {
44
46
  const instance = db();
45
47
  if (!instance) return merged.fallback;
46
- return createComponent(SpookyContext.Provider, {
48
+ return createComponent(Sp00kyContext.Provider, {
47
49
  value: instance,
48
50
  get children() {
49
51
  return merged.children;