mpb-localkit 1.3.4 → 1.3.7
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.
- package/README.md +5 -5
- package/dist/cli/index.js +13 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +5 -5
- package/dist/core/index.js.map +1 -1
- package/dist/react/index.js +3 -3
- package/dist/react/index.js.map +1 -1
- package/dist/svelte/index.d.ts +2 -2
- package/dist/svelte/index.js +3 -3
- package/dist/svelte/index.js.map +1 -1
- package/package.json +2 -2
package/dist/react/index.js
CHANGED
|
@@ -6,9 +6,9 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
6
6
|
|
|
7
7
|
// src/core/query.ts
|
|
8
8
|
var localkitKeys = {
|
|
9
|
-
all: ["
|
|
10
|
-
collection: (name) => ["
|
|
11
|
-
collectionQuery: (name, opts) => ["
|
|
9
|
+
all: ["offlinekit"],
|
|
10
|
+
collection: (name) => ["offlinekit", name],
|
|
11
|
+
collectionQuery: (name, opts) => ["offlinekit", name, JSON.stringify(opts)]
|
|
12
12
|
};
|
|
13
13
|
function subscribeToCollection(collection, queryClient) {
|
|
14
14
|
const queryKey = localkitKeys.collection(collection.name);
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/query.ts","../../src/react/useCollection.ts","../../src/core/storage/query.ts","../../src/react/useCollectionStore.ts","../../src/react/useAuth.ts","../../src/react/useSync.ts","../../src/react/provider.tsx"],"names":["useQueryClient","useQuery","useMutation","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { QueryOptions } from './storage/query.js'\nimport type { WithMeta } from './schema/types.js'\nimport type { Collection } from './client/collection.js'\n\n/** Minimal QueryClient interface — avoids a hard dep on @tanstack/query-core */\ninterface MinimalQueryClient {\n invalidateQueries(opts: { queryKey: readonly unknown[] }): Promise<void>\n}\n\nexport const localkitKeys = {\n all: ['localkit'] as const,\n collection: (name: string) => ['localkit', name] as const,\n collectionQuery: (name: string, opts: unknown) =>\n ['localkit', name, JSON.stringify(opts)] as const,\n}\n\nexport function collectionQueryOptions<T>(\n collection: Collection<T>,\n queryOptions?: QueryOptions<T>,\n): {\n queryKey: readonly unknown[]\n queryFn: () => Promise<WithMeta<T>[]>\n} {\n const queryKey = queryOptions\n ? localkitKeys.collectionQuery(collection.name, queryOptions)\n : localkitKeys.collection(collection.name)\n\n return {\n queryKey,\n queryFn: () => collection.findMany(queryOptions),\n }\n}\n\nexport function subscribeToCollection<T>(\n collection: Collection<T>,\n queryClient: MinimalQueryClient,\n): () => void {\n const queryKey = localkitKeys.collection(collection.name)\n\n if (!('subscribe' in collection)) {\n return () => {}\n }\n\n const obs = collection as Collection<T> & {\n subscribe(listener: () => void): () => void\n }\n\n return obs.subscribe(() => {\n void queryClient.invalidateQueries({ queryKey })\n })\n}\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport { localkitKeys } from '../core/query.js'\nimport type { QueryOptions } from '../core/storage/query.js'\nimport type { WithMeta } from '../core/schema/types.js'\nimport type { UseCollectionResult } from './types.js'\n\n/**\n * React hook for reading and mutating an LocalKit collection.\n * Uses @tanstack/react-query for caching and reactivity.\n *\n * @example\n * const { data: brews, create } = useCollection(app.brews)\n * const { data: ipas } = useCollection(app.brews, { where: { style: 'IPA' } })\n */\nexport function useCollection<T>(\n collection: ObservableCollection<T>,\n options?: QueryOptions<T>,\n): UseCollectionResult<T> {\n const queryClient = useQueryClient()\n const queryKey = options\n ? localkitKeys.collectionQuery(collection.name, options)\n : localkitKeys.collection(collection.name)\n\n const query = useQuery({\n queryKey,\n queryFn: () => collection.findMany(options),\n })\n\n const invalidate = () =>\n queryClient.invalidateQueries({ queryKey: localkitKeys.collection(collection.name) })\n\n const createMutation = useMutation({\n mutationFn: (input: T) => collection.create(input),\n onSuccess: invalidate,\n })\n\n const updateMutation = useMutation({\n mutationFn: ({ id, input }: { id: string; input: Partial<T> }) =>\n collection.update(id, input),\n onSuccess: invalidate,\n })\n\n const deleteMutation = useMutation({\n mutationFn: (id: string) => collection.delete(id),\n onSuccess: invalidate,\n })\n\n return {\n data: (query.data ?? []) as WithMeta<T>[],\n isLoading: query.isLoading,\n error: query.error as Error | null,\n create: (input: T) => createMutation.mutateAsync(input),\n update: (id: string, input: Partial<T>) => updateMutation.mutateAsync({ id, input }),\n remove: (id: string) => deleteMutation.mutateAsync(id),\n }\n}\n","export interface QueryOptions<T> {\n where?: WhereClause<T>\n sort?: Partial<Record<keyof T, 'asc' | 'desc'>>\n limit?: number\n offset?: number\n}\n\nexport type WhereClause<T> = {\n [K in keyof T]?: T[K] | { $gt?: T[K]; $lt?: T[K]; $gte?: T[K]; $lte?: T[K]; $in?: T[K][] }\n}\n\ntype FieldCondition<V> = { $gt?: V; $lt?: V; $gte?: V; $lte?: V; $in?: V[] }\n\nfunction isCondition<V>(value: unknown): value is FieldCondition<V> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const keys = Object.keys(value)\n return keys.some(k => k === '$gt' || k === '$lt' || k === '$gte' || k === '$lte' || k === '$in')\n}\n\nexport function matchesWhere<T>(doc: T, where: WhereClause<T>): boolean {\n for (const key of Object.keys(where) as Array<keyof T>) {\n const condition = where[key]\n const docValue = doc[key]\n\n if (isCondition<T[typeof key]>(condition)) {\n if (condition.$gt != null && !(docValue > condition.$gt)) return false\n if (condition.$lt != null && !(docValue < condition.$lt)) return false\n if (condition.$gte != null && !(docValue >= condition.$gte)) return false\n if (condition.$lte != null && !(docValue <= condition.$lte)) return false\n if (condition.$in !== undefined && !condition.$in.includes(docValue)) return false\n } else {\n if (docValue !== condition) return false\n }\n }\n return true\n}\n\nexport function applySort<T>(docs: T[], sort: Partial<Record<keyof T, 'asc' | 'desc'>>): T[] {\n const entries = Object.entries(sort) as Array<[keyof T, 'asc' | 'desc']>\n if (entries.length === 0) return docs\n\n return [...docs].sort((a, b) => {\n for (const [field, direction] of entries) {\n const av = a[field]\n const bv = b[field]\n if (av === bv) continue\n const cmp = av < bv ? -1 : 1\n return direction === 'asc' ? cmp : -cmp\n }\n return 0\n })\n}\n\nexport function applyQuery<T>(docs: T[], options: QueryOptions<T>): T[] {\n let result = docs\n\n if (options.where) {\n const where = options.where\n result = result.filter(doc => matchesWhere(doc, where))\n }\n\n if (options.sort) {\n result = applySort(result, options.sort)\n }\n\n const offset = options.offset ?? 0\n if (offset > 0) {\n result = result.slice(offset)\n }\n\n if (options.limit !== undefined) {\n result = result.slice(0, options.limit)\n }\n\n return result\n}\n","import { useSyncExternalStore, useMemo } from 'react'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport type { QueryOptions } from '../core/storage/query.js'\nimport { applyQuery } from '../core/storage/query.js'\nimport type { WithMeta } from '../core/schema/types.js'\n\n/**\n * Zero-dependency React hook for reading an OfflineKit collection.\n * Uses React's built-in useSyncExternalStore for reactivity — no TanStack Query required.\n * Returns a read-only array that updates automatically when documents change.\n *\n * For mutations, use collection.create/update/delete directly.\n *\n * @example\n * const todos = useCollectionStore(app.todos)\n * const ipas = useCollectionStore(app.brews, { where: { style: 'IPA' } })\n */\nexport function useCollectionStore<T>(\n collection: ObservableCollection<T>,\n options?: QueryOptions<T>,\n): ReadonlyArray<WithMeta<T>> {\n const snapshot = useSyncExternalStore(\n collection.subscribe,\n collection.getSnapshot,\n (): ReadonlyArray<WithMeta<T>> => [],\n )\n\n // Serialize options to a stable string so inline object literals don't break memoization.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const optionsKey = options !== undefined ? JSON.stringify(options) : undefined\n\n return useMemo(() => {\n if (!options) return snapshot as unknown as WithMeta<T>[]\n return applyQuery([...snapshot] as WithMeta<T>[], options) as WithMeta<T>[]\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [snapshot, optionsKey])\n}\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport type { AuthAdapter } from '../core/auth/types.js'\nimport type { UseAuthResult } from './types.js'\n\nconst AUTH_KEY = ['localkit', 'auth'] as const\n\n/**\n * React hook for LocalKit auth (signUp, signIn, signOut).\n * Uses @tanstack/react-query for state management.\n *\n * @example\n * const { user, signIn } = useAuth(app.auth)\n */\nexport function useAuth(auth: AuthAdapter): UseAuthResult {\n const queryClient = useQueryClient()\n\n const query = useQuery({\n queryKey: AUTH_KEY,\n queryFn: () => Promise.resolve(auth.currentUser()),\n })\n\n const invalidateAuth = () => queryClient.invalidateQueries({ queryKey: AUTH_KEY })\n\n const signUpMut = useMutation({\n mutationFn: (credentials: { email: string; password: string }) => auth.signUp(credentials),\n onSuccess: invalidateAuth,\n })\n\n const signInMut = useMutation({\n mutationFn: (credentials: { email: string; password: string }) => auth.signIn(credentials),\n onSuccess: invalidateAuth,\n })\n\n const signOutMut = useMutation({\n mutationFn: () => auth.signOut(),\n onSuccess: invalidateAuth,\n })\n\n return {\n user: query.data ?? null,\n isLoading: query.isLoading,\n error: (query.error ?? signUpMut.error ?? signInMut.error ?? signOutMut.error) as Error | null,\n signUp: (credentials) => signUpMut.mutateAsync(credentials).then(() => {}),\n signIn: (credentials) => signInMut.mutateAsync(credentials).then(() => {}),\n signOut: () => signOutMut.mutateAsync().then(() => {}),\n }\n}\n","import { useCallback, useEffect } from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { SyncEngine } from '../core/sync/engine.js'\nimport type { SyncStore } from '../core/client/events.js'\nimport type { SyncAPI } from '../core/client/types.js'\nimport type { UseSyncResult } from './types.js'\n\nconst SYNC_KEY = ['localkit', 'sync'] as const\n\ninterface AppWithSync {\n sync: SyncAPI\n syncStore: SyncStore\n}\n\nfunction isAppWithSync(source: SyncEngine | AppWithSync): source is AppWithSync {\n return 'syncStore' in source\n}\n\n/**\n * React hook for observing and triggering LocalKit sync.\n * Accepts either a raw SyncEngine or an App instance (created by createApp).\n *\n * @example\n * const { status, lastSyncAt, sync } = useSync(app)\n * const { status, lastSyncAt, sync } = useSync(syncEngine)\n */\nexport function useSync(source: SyncEngine | AppWithSync): UseSyncResult {\n const queryClient = useQueryClient()\n const isApp = isAppWithSync(source)\n\n const query = useQuery({\n queryKey: SYNC_KEY,\n queryFn: () => {\n if (isApp) {\n const s = (source as AppWithSync).syncStore.getSnapshot()\n return Promise.resolve({ status: s.status, lastSyncAt: s.lastSyncAt ?? 0 })\n }\n const engine = source as SyncEngine\n return Promise.resolve({ status: engine.getStatus(), lastSyncAt: engine.getLastSyncAt() })\n },\n })\n\n useEffect(() => {\n if (isApp) {\n const appSource = source as AppWithSync\n return appSource.syncStore.subscribe(() => {\n const s = appSource.syncStore.getSnapshot()\n queryClient.setQueryData(SYNC_KEY, { status: s.status, lastSyncAt: s.lastSyncAt ?? 0 })\n })\n } else {\n const engine = source as SyncEngine\n const onStart = () =>\n queryClient.setQueryData(SYNC_KEY, { status: 'syncing', lastSyncAt: engine.getLastSyncAt() })\n const onComplete = () =>\n queryClient.setQueryData(SYNC_KEY, { status: 'idle', lastSyncAt: engine.getLastSyncAt() })\n const onError = () =>\n queryClient.setQueryData(SYNC_KEY, { status: engine.getStatus(), lastSyncAt: engine.getLastSyncAt() })\n\n engine.on('sync:start', onStart)\n engine.on('sync:complete', onComplete)\n engine.on('sync:error', onError)\n\n return () => {\n engine.off('sync:start', onStart)\n engine.off('sync:complete', onComplete)\n engine.off('sync:error', onError)\n }\n }\n }, [source, queryClient, isApp])\n\n const sync = useCallback(async (): Promise<void> => {\n if (isApp) {\n const appSource = source as AppWithSync\n await appSource.sync.push()\n await appSource.sync.pull()\n } else {\n await (source as SyncEngine).sync()\n }\n await queryClient.invalidateQueries({ queryKey: SYNC_KEY })\n }, [source, queryClient, isApp])\n\n return {\n status: query.data?.status ?? 'idle',\n lastSyncAt: query.data?.lastSyncAt ?? 0,\n sync,\n }\n}\n","import { useEffect, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport { subscribeToCollection } from '../core/query.js'\n\ninterface LocalKitProviderProps {\n children: ReactNode\n queryClient?: QueryClient\n collections?: ObservableCollection<unknown>[]\n}\n\nexport function LocalKitProvider({\n children,\n queryClient,\n collections = [],\n}: LocalKitProviderProps) {\n const [defaultClient] = useState(() => new QueryClient())\n const client = queryClient ?? defaultClient\n\n useEffect(() => {\n const unsubs = collections.map(col => subscribeToCollection(col, client))\n return () => {\n for (const unsub of unsubs) unsub()\n }\n }, [client, collections])\n\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/query.ts","../../src/react/useCollection.ts","../../src/core/storage/query.ts","../../src/react/useCollectionStore.ts","../../src/react/useAuth.ts","../../src/react/useSync.ts","../../src/react/provider.tsx"],"names":["useQueryClient","useQuery","useMutation","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { QueryOptions } from './storage/query.js'\nimport type { WithMeta } from './schema/types.js'\nimport type { Collection } from './client/collection.js'\n\n/** Minimal QueryClient interface — avoids a hard dep on @tanstack/query-core */\ninterface MinimalQueryClient {\n invalidateQueries(opts: { queryKey: readonly unknown[] }): Promise<void>\n}\n\nexport const localkitKeys = {\n all: ['offlinekit'] as const,\n collection: (name: string) => ['offlinekit', name] as const,\n collectionQuery: (name: string, opts: unknown) =>\n ['offlinekit', name, JSON.stringify(opts)] as const,\n}\n\nexport function collectionQueryOptions<T>(\n collection: Collection<T>,\n queryOptions?: QueryOptions<T>,\n): {\n queryKey: readonly unknown[]\n queryFn: () => Promise<WithMeta<T>[]>\n} {\n const queryKey = queryOptions\n ? localkitKeys.collectionQuery(collection.name, queryOptions)\n : localkitKeys.collection(collection.name)\n\n return {\n queryKey,\n queryFn: () => collection.findMany(queryOptions),\n }\n}\n\nexport function subscribeToCollection<T>(\n collection: Collection<T>,\n queryClient: MinimalQueryClient,\n): () => void {\n const queryKey = localkitKeys.collection(collection.name)\n\n if (!('subscribe' in collection)) {\n return () => {}\n }\n\n const obs = collection as Collection<T> & {\n subscribe(listener: () => void): () => void\n }\n\n return obs.subscribe(() => {\n void queryClient.invalidateQueries({ queryKey })\n })\n}\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport { localkitKeys } from '../core/query.js'\nimport type { QueryOptions } from '../core/storage/query.js'\nimport type { WithMeta } from '../core/schema/types.js'\nimport type { UseCollectionResult } from './types.js'\n\n/**\n * React hook for reading and mutating an LocalKit collection.\n * Uses @tanstack/react-query for caching and reactivity.\n *\n * @example\n * const { data: brews, create } = useCollection(app.brews)\n * const { data: ipas } = useCollection(app.brews, { where: { style: 'IPA' } })\n */\nexport function useCollection<T>(\n collection: ObservableCollection<T>,\n options?: QueryOptions<T>,\n): UseCollectionResult<T> {\n const queryClient = useQueryClient()\n const queryKey = options\n ? localkitKeys.collectionQuery(collection.name, options)\n : localkitKeys.collection(collection.name)\n\n const query = useQuery({\n queryKey,\n queryFn: () => collection.findMany(options),\n })\n\n const invalidate = () =>\n queryClient.invalidateQueries({ queryKey: localkitKeys.collection(collection.name) })\n\n const createMutation = useMutation({\n mutationFn: (input: T) => collection.create(input),\n onSuccess: invalidate,\n })\n\n const updateMutation = useMutation({\n mutationFn: ({ id, input }: { id: string; input: Partial<T> }) =>\n collection.update(id, input),\n onSuccess: invalidate,\n })\n\n const deleteMutation = useMutation({\n mutationFn: (id: string) => collection.delete(id),\n onSuccess: invalidate,\n })\n\n return {\n data: (query.data ?? []) as WithMeta<T>[],\n isLoading: query.isLoading,\n error: query.error as Error | null,\n create: (input: T) => createMutation.mutateAsync(input),\n update: (id: string, input: Partial<T>) => updateMutation.mutateAsync({ id, input }),\n remove: (id: string) => deleteMutation.mutateAsync(id),\n }\n}\n","export interface QueryOptions<T> {\n where?: WhereClause<T>\n sort?: Partial<Record<keyof T, 'asc' | 'desc'>>\n limit?: number\n offset?: number\n}\n\nexport type WhereClause<T> = {\n [K in keyof T]?: T[K] | { $gt?: T[K]; $lt?: T[K]; $gte?: T[K]; $lte?: T[K]; $in?: T[K][] }\n}\n\ntype FieldCondition<V> = { $gt?: V; $lt?: V; $gte?: V; $lte?: V; $in?: V[] }\n\nfunction isCondition<V>(value: unknown): value is FieldCondition<V> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const keys = Object.keys(value)\n return keys.some(k => k === '$gt' || k === '$lt' || k === '$gte' || k === '$lte' || k === '$in')\n}\n\nexport function matchesWhere<T>(doc: T, where: WhereClause<T>): boolean {\n for (const key of Object.keys(where) as Array<keyof T>) {\n const condition = where[key]\n const docValue = doc[key]\n\n if (isCondition<T[typeof key]>(condition)) {\n if (condition.$gt != null && !(docValue > condition.$gt)) return false\n if (condition.$lt != null && !(docValue < condition.$lt)) return false\n if (condition.$gte != null && !(docValue >= condition.$gte)) return false\n if (condition.$lte != null && !(docValue <= condition.$lte)) return false\n if (condition.$in !== undefined && !condition.$in.includes(docValue)) return false\n } else {\n if (docValue !== condition) return false\n }\n }\n return true\n}\n\nexport function applySort<T>(docs: T[], sort: Partial<Record<keyof T, 'asc' | 'desc'>>): T[] {\n const entries = Object.entries(sort) as Array<[keyof T, 'asc' | 'desc']>\n if (entries.length === 0) return docs\n\n return [...docs].sort((a, b) => {\n for (const [field, direction] of entries) {\n const av = a[field]\n const bv = b[field]\n if (av === bv) continue\n const cmp = av < bv ? -1 : 1\n return direction === 'asc' ? cmp : -cmp\n }\n return 0\n })\n}\n\nexport function applyQuery<T>(docs: T[], options: QueryOptions<T>): T[] {\n let result = docs\n\n if (options.where) {\n const where = options.where\n result = result.filter(doc => matchesWhere(doc, where))\n }\n\n if (options.sort) {\n result = applySort(result, options.sort)\n }\n\n const offset = options.offset ?? 0\n if (offset > 0) {\n result = result.slice(offset)\n }\n\n if (options.limit !== undefined) {\n result = result.slice(0, options.limit)\n }\n\n return result\n}\n","import { useSyncExternalStore, useMemo } from 'react'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport type { QueryOptions } from '../core/storage/query.js'\nimport { applyQuery } from '../core/storage/query.js'\nimport type { WithMeta } from '../core/schema/types.js'\n\n/**\n * Zero-dependency React hook for reading an OfflineKit collection.\n * Uses React's built-in useSyncExternalStore for reactivity — no TanStack Query required.\n * Returns a read-only array that updates automatically when documents change.\n *\n * For mutations, use collection.create/update/delete directly.\n *\n * @example\n * const todos = useCollectionStore(app.todos)\n * const ipas = useCollectionStore(app.brews, { where: { style: 'IPA' } })\n */\nexport function useCollectionStore<T>(\n collection: ObservableCollection<T>,\n options?: QueryOptions<T>,\n): ReadonlyArray<WithMeta<T>> {\n const snapshot = useSyncExternalStore(\n collection.subscribe,\n collection.getSnapshot,\n (): ReadonlyArray<WithMeta<T>> => [],\n )\n\n // Serialize options to a stable string so inline object literals don't break memoization.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const optionsKey = options !== undefined ? JSON.stringify(options) : undefined\n\n return useMemo(() => {\n if (!options) return snapshot as unknown as WithMeta<T>[]\n return applyQuery([...snapshot] as WithMeta<T>[], options) as WithMeta<T>[]\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [snapshot, optionsKey])\n}\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport type { AuthAdapter } from '../core/auth/types.js'\nimport type { UseAuthResult } from './types.js'\n\nconst AUTH_KEY = ['localkit', 'auth'] as const\n\n/**\n * React hook for LocalKit auth (signUp, signIn, signOut).\n * Uses @tanstack/react-query for state management.\n *\n * @example\n * const { user, signIn } = useAuth(app.auth)\n */\nexport function useAuth(auth: AuthAdapter): UseAuthResult {\n const queryClient = useQueryClient()\n\n const query = useQuery({\n queryKey: AUTH_KEY,\n queryFn: () => Promise.resolve(auth.currentUser()),\n })\n\n const invalidateAuth = () => queryClient.invalidateQueries({ queryKey: AUTH_KEY })\n\n const signUpMut = useMutation({\n mutationFn: (credentials: { email: string; password: string }) => auth.signUp(credentials),\n onSuccess: invalidateAuth,\n })\n\n const signInMut = useMutation({\n mutationFn: (credentials: { email: string; password: string }) => auth.signIn(credentials),\n onSuccess: invalidateAuth,\n })\n\n const signOutMut = useMutation({\n mutationFn: () => auth.signOut(),\n onSuccess: invalidateAuth,\n })\n\n return {\n user: query.data ?? null,\n isLoading: query.isLoading,\n error: (query.error ?? signUpMut.error ?? signInMut.error ?? signOutMut.error) as Error | null,\n signUp: (credentials) => signUpMut.mutateAsync(credentials).then(() => {}),\n signIn: (credentials) => signInMut.mutateAsync(credentials).then(() => {}),\n signOut: () => signOutMut.mutateAsync().then(() => {}),\n }\n}\n","import { useCallback, useEffect } from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { SyncEngine } from '../core/sync/engine.js'\nimport type { SyncStore } from '../core/client/events.js'\nimport type { SyncAPI } from '../core/client/types.js'\nimport type { UseSyncResult } from './types.js'\n\nconst SYNC_KEY = ['localkit', 'sync'] as const\n\ninterface AppWithSync {\n sync: SyncAPI\n syncStore: SyncStore\n}\n\nfunction isAppWithSync(source: SyncEngine | AppWithSync): source is AppWithSync {\n return 'syncStore' in source\n}\n\n/**\n * React hook for observing and triggering LocalKit sync.\n * Accepts either a raw SyncEngine or an App instance (created by createApp).\n *\n * @example\n * const { status, lastSyncAt, sync } = useSync(app)\n * const { status, lastSyncAt, sync } = useSync(syncEngine)\n */\nexport function useSync(source: SyncEngine | AppWithSync): UseSyncResult {\n const queryClient = useQueryClient()\n const isApp = isAppWithSync(source)\n\n const query = useQuery({\n queryKey: SYNC_KEY,\n queryFn: () => {\n if (isApp) {\n const s = (source as AppWithSync).syncStore.getSnapshot()\n return Promise.resolve({ status: s.status, lastSyncAt: s.lastSyncAt ?? 0 })\n }\n const engine = source as SyncEngine\n return Promise.resolve({ status: engine.getStatus(), lastSyncAt: engine.getLastSyncAt() })\n },\n })\n\n useEffect(() => {\n if (isApp) {\n const appSource = source as AppWithSync\n return appSource.syncStore.subscribe(() => {\n const s = appSource.syncStore.getSnapshot()\n queryClient.setQueryData(SYNC_KEY, { status: s.status, lastSyncAt: s.lastSyncAt ?? 0 })\n })\n } else {\n const engine = source as SyncEngine\n const onStart = () =>\n queryClient.setQueryData(SYNC_KEY, { status: 'syncing', lastSyncAt: engine.getLastSyncAt() })\n const onComplete = () =>\n queryClient.setQueryData(SYNC_KEY, { status: 'idle', lastSyncAt: engine.getLastSyncAt() })\n const onError = () =>\n queryClient.setQueryData(SYNC_KEY, { status: engine.getStatus(), lastSyncAt: engine.getLastSyncAt() })\n\n engine.on('sync:start', onStart)\n engine.on('sync:complete', onComplete)\n engine.on('sync:error', onError)\n\n return () => {\n engine.off('sync:start', onStart)\n engine.off('sync:complete', onComplete)\n engine.off('sync:error', onError)\n }\n }\n }, [source, queryClient, isApp])\n\n const sync = useCallback(async (): Promise<void> => {\n if (isApp) {\n const appSource = source as AppWithSync\n await appSource.sync.push()\n await appSource.sync.pull()\n } else {\n await (source as SyncEngine).sync()\n }\n await queryClient.invalidateQueries({ queryKey: SYNC_KEY })\n }, [source, queryClient, isApp])\n\n return {\n status: query.data?.status ?? 'idle',\n lastSyncAt: query.data?.lastSyncAt ?? 0,\n sync,\n }\n}\n","import { useEffect, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport { subscribeToCollection } from '../core/query.js'\n\ninterface LocalKitProviderProps {\n children: ReactNode\n queryClient?: QueryClient\n collections?: ObservableCollection<unknown>[]\n}\n\nexport function LocalKitProvider({\n children,\n queryClient,\n collections = [],\n}: LocalKitProviderProps) {\n const [defaultClient] = useState(() => new QueryClient())\n const client = queryClient ?? defaultClient\n\n useEffect(() => {\n const unsubs = collections.map(col => subscribeToCollection(col, client))\n return () => {\n for (const unsub of unsubs) unsub()\n }\n }, [client, collections])\n\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>\n}\n"]}
|
package/dist/svelte/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { U as User, W as WithMeta, S as SyncStatus, O as ObservableCollection, Q as QueryOptions, d as SyncEngine } from '../collection-CBG-_MiM.js';
|
|
2
2
|
import { A as AuthStore$1 } from '../events-hGI5qde5.js';
|
|
3
|
-
export { c as collectionQueryOptions, l as localkitKeys, s as subscribeToCollection } from '../query-
|
|
3
|
+
export { c as collectionQueryOptions, l as localkitKeys, s as subscribeToCollection } from '../query-D2jbktTG.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
interface CollectionStore<T> {
|
|
@@ -27,7 +27,7 @@ interface SyncStore {
|
|
|
27
27
|
* For full TanStack Query integration, install @tanstack/svelte-query and use
|
|
28
28
|
* `collectionQueryOptions()` with `createQuery()` instead:
|
|
29
29
|
* @example
|
|
30
|
-
* import { collectionQueryOptions } from 'localkit/svelte'
|
|
30
|
+
* import { collectionQueryOptions } from 'mpb-localkit/svelte'
|
|
31
31
|
* import { createQuery } from '@tanstack/svelte-query'
|
|
32
32
|
* const query = createQuery(collectionQueryOptions(app.todos, { where: { done: false } }))
|
|
33
33
|
* // $query.data — reactively updated, cache-backed array
|
package/dist/svelte/index.js
CHANGED
|
@@ -123,9 +123,9 @@ function createSyncStore(engine) {
|
|
|
123
123
|
|
|
124
124
|
// src/core/query.ts
|
|
125
125
|
var localkitKeys = {
|
|
126
|
-
all: ["
|
|
127
|
-
collection: (name) => ["
|
|
128
|
-
collectionQuery: (name, opts) => ["
|
|
126
|
+
all: ["offlinekit"],
|
|
127
|
+
collection: (name) => ["offlinekit", name],
|
|
128
|
+
collectionQuery: (name, opts) => ["offlinekit", name, JSON.stringify(opts)]
|
|
129
129
|
};
|
|
130
130
|
function collectionQueryOptions(collection, queryOptions) {
|
|
131
131
|
const queryKey = queryOptions ? localkitKeys.collectionQuery(collection.name, queryOptions) : localkitKeys.collection(collection.name);
|
package/dist/svelte/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/storage/query.ts","../../src/svelte/stores.ts","../../src/core/query.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export interface QueryOptions<T> {\n where?: WhereClause<T>\n sort?: Partial<Record<keyof T, 'asc' | 'desc'>>\n limit?: number\n offset?: number\n}\n\nexport type WhereClause<T> = {\n [K in keyof T]?: T[K] | { $gt?: T[K]; $lt?: T[K]; $gte?: T[K]; $lte?: T[K]; $in?: T[K][] }\n}\n\ntype FieldCondition<V> = { $gt?: V; $lt?: V; $gte?: V; $lte?: V; $in?: V[] }\n\nfunction isCondition<V>(value: unknown): value is FieldCondition<V> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const keys = Object.keys(value)\n return keys.some(k => k === '$gt' || k === '$lt' || k === '$gte' || k === '$lte' || k === '$in')\n}\n\nexport function matchesWhere<T>(doc: T, where: WhereClause<T>): boolean {\n for (const key of Object.keys(where) as Array<keyof T>) {\n const condition = where[key]\n const docValue = doc[key]\n\n if (isCondition<T[typeof key]>(condition)) {\n if (condition.$gt != null && !(docValue > condition.$gt)) return false\n if (condition.$lt != null && !(docValue < condition.$lt)) return false\n if (condition.$gte != null && !(docValue >= condition.$gte)) return false\n if (condition.$lte != null && !(docValue <= condition.$lte)) return false\n if (condition.$in !== undefined && !condition.$in.includes(docValue)) return false\n } else {\n if (docValue !== condition) return false\n }\n }\n return true\n}\n\nexport function applySort<T>(docs: T[], sort: Partial<Record<keyof T, 'asc' | 'desc'>>): T[] {\n const entries = Object.entries(sort) as Array<[keyof T, 'asc' | 'desc']>\n if (entries.length === 0) return docs\n\n return [...docs].sort((a, b) => {\n for (const [field, direction] of entries) {\n const av = a[field]\n const bv = b[field]\n if (av === bv) continue\n const cmp = av < bv ? -1 : 1\n return direction === 'asc' ? cmp : -cmp\n }\n return 0\n })\n}\n\nexport function applyQuery<T>(docs: T[], options: QueryOptions<T>): T[] {\n let result = docs\n\n if (options.where) {\n const where = options.where\n result = result.filter(doc => matchesWhere(doc, where))\n }\n\n if (options.sort) {\n result = applySort(result, options.sort)\n }\n\n const offset = options.offset ?? 0\n if (offset > 0) {\n result = result.slice(offset)\n }\n\n if (options.limit !== undefined) {\n result = result.slice(0, options.limit)\n }\n\n return result\n}\n","import type { WithMeta } from '../core/schema/types.js'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport type { AuthStore as AuthStoreObservable } from '../core/client/events.js'\nimport type { SyncEngine } from '../core/sync/engine.js'\nimport type { SyncStatus } from '../core/sync/types.js'\nimport type { QueryOptions } from '../core/storage/query.js'\nimport { applyQuery } from '../core/storage/query.js'\nimport type { CollectionStore, AuthStore, SyncStore } from './types.js'\n\n/**\n * Wraps an ObservableCollection into a Svelte-compatible readable store.\n * The store value is updated whenever the collection changes.\n * Supports optional query filtering (where, sort, limit, offset).\n *\n * For full TanStack Query integration, install @tanstack/svelte-query and use\n * `collectionQueryOptions()` with `createQuery()` instead:\n * @example\n * import { collectionQueryOptions } from 'localkit/svelte'\n * import { createQuery } from '@tanstack/svelte-query'\n * const query = createQuery(collectionQueryOptions(app.todos, { where: { done: false } }))\n * // $query.data — reactively updated, cache-backed array\n *\n * @example\n * const todos = createCollectionStore(app.todos, { where: { done: false }, sort: { title: 'asc' } })\n * // In Svelte: $todos — reactively updated filtered array\n */\nexport function createCollectionStore<T>(\n collection: ObservableCollection<T>,\n queryOptions?: QueryOptions<T>,\n): CollectionStore<T> {\n const getFiltered = (): WithMeta<T>[] => {\n const snapshot = [...collection.getSnapshot()] as WithMeta<T>[]\n return queryOptions ? applyQuery(snapshot, queryOptions) as WithMeta<T>[] : snapshot\n }\n\n return {\n subscribe(run: (value: WithMeta<T>[]) => void): () => void {\n // Emit current filtered snapshot immediately\n run(getFiltered())\n\n // Subscribe to collection changes; re-emit filtered snapshot on each notification\n const unsub = collection.subscribe(() => {\n run(getFiltered())\n })\n\n return unsub\n },\n }\n}\n\n/**\n * Wraps an AuthStore observable into a Svelte-compatible readable store.\n * Reflects the current user and loading state, updating automatically\n * when the auth state changes (sign-in, sign-out, etc.).\n *\n * @example\n * const auth = createAuthStore(app.auth)\n * // In Svelte: $auth.user\n */\nexport function createAuthStore(auth: AuthStoreObservable): AuthStore {\n return {\n subscribe(run) {\n const snap = auth.getSnapshot()\n run({ user: snap.user, isLoading: snap.isLoading })\n return auth.subscribe(() => {\n const s = auth.getSnapshot()\n run({ user: s.user, isLoading: s.isLoading })\n })\n },\n }\n}\n\n/**\n * Wraps a SyncEngine into a Svelte-compatible readable store.\n * Reflects sync status and last sync timestamp.\n *\n * @example\n * const sync = createSyncStore(app.sync)\n * // In Svelte: $sync.status\n */\nexport function createSyncStore(engine: SyncEngine): SyncStore {\n type SyncState = { status: SyncStatus; lastSyncAt: number }\n\n let current: SyncState = {\n status: engine.getStatus(),\n lastSyncAt: engine.getLastSyncAt(),\n }\n\n const subs = new Set<(value: SyncState) => void>()\n\n const notify = (): void => {\n for (const run of subs) run(current)\n }\n\n const onStart = (): void => {\n current = { ...current, status: 'syncing' }\n notify()\n }\n\n const onComplete = (): void => {\n current = { status: 'idle', lastSyncAt: engine.getLastSyncAt() }\n notify()\n }\n\n const onError = (): void => {\n current = { ...current, status: engine.getStatus() }\n notify()\n }\n\n engine.on('sync:start', onStart)\n engine.on('sync:complete', onComplete)\n engine.on('sync:error', onError)\n\n return {\n subscribe(run: (value: SyncState) => void): () => void {\n subs.add(run)\n run(current)\n return () => {\n subs.delete(run)\n if (subs.size === 0) {\n engine.off('sync:start', onStart)\n engine.off('sync:complete', onComplete)\n engine.off('sync:error', onError)\n }\n }\n },\n }\n}\n","import type { QueryOptions } from './storage/query.js'\nimport type { WithMeta } from './schema/types.js'\nimport type { Collection } from './client/collection.js'\n\n/** Minimal QueryClient interface — avoids a hard dep on @tanstack/query-core */\ninterface MinimalQueryClient {\n invalidateQueries(opts: { queryKey: readonly unknown[] }): Promise<void>\n}\n\nexport const localkitKeys = {\n all: ['localkit'] as const,\n collection: (name: string) => ['localkit', name] as const,\n collectionQuery: (name: string, opts: unknown) =>\n ['localkit', name, JSON.stringify(opts)] as const,\n}\n\nexport function collectionQueryOptions<T>(\n collection: Collection<T>,\n queryOptions?: QueryOptions<T>,\n): {\n queryKey: readonly unknown[]\n queryFn: () => Promise<WithMeta<T>[]>\n} {\n const queryKey = queryOptions\n ? localkitKeys.collectionQuery(collection.name, queryOptions)\n : localkitKeys.collection(collection.name)\n\n return {\n queryKey,\n queryFn: () => collection.findMany(queryOptions),\n }\n}\n\nexport function subscribeToCollection<T>(\n collection: Collection<T>,\n queryClient: MinimalQueryClient,\n): () => void {\n const queryKey = localkitKeys.collection(collection.name)\n\n if (!('subscribe' in collection)) {\n return () => {}\n }\n\n const obs = collection as Collection<T> & {\n subscribe(listener: () => void): () => void\n }\n\n return obs.subscribe(() => {\n void queryClient.invalidateQueries({ queryKey })\n })\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/storage/query.ts","../../src/svelte/stores.ts","../../src/core/query.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export interface QueryOptions<T> {\n where?: WhereClause<T>\n sort?: Partial<Record<keyof T, 'asc' | 'desc'>>\n limit?: number\n offset?: number\n}\n\nexport type WhereClause<T> = {\n [K in keyof T]?: T[K] | { $gt?: T[K]; $lt?: T[K]; $gte?: T[K]; $lte?: T[K]; $in?: T[K][] }\n}\n\ntype FieldCondition<V> = { $gt?: V; $lt?: V; $gte?: V; $lte?: V; $in?: V[] }\n\nfunction isCondition<V>(value: unknown): value is FieldCondition<V> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const keys = Object.keys(value)\n return keys.some(k => k === '$gt' || k === '$lt' || k === '$gte' || k === '$lte' || k === '$in')\n}\n\nexport function matchesWhere<T>(doc: T, where: WhereClause<T>): boolean {\n for (const key of Object.keys(where) as Array<keyof T>) {\n const condition = where[key]\n const docValue = doc[key]\n\n if (isCondition<T[typeof key]>(condition)) {\n if (condition.$gt != null && !(docValue > condition.$gt)) return false\n if (condition.$lt != null && !(docValue < condition.$lt)) return false\n if (condition.$gte != null && !(docValue >= condition.$gte)) return false\n if (condition.$lte != null && !(docValue <= condition.$lte)) return false\n if (condition.$in !== undefined && !condition.$in.includes(docValue)) return false\n } else {\n if (docValue !== condition) return false\n }\n }\n return true\n}\n\nexport function applySort<T>(docs: T[], sort: Partial<Record<keyof T, 'asc' | 'desc'>>): T[] {\n const entries = Object.entries(sort) as Array<[keyof T, 'asc' | 'desc']>\n if (entries.length === 0) return docs\n\n return [...docs].sort((a, b) => {\n for (const [field, direction] of entries) {\n const av = a[field]\n const bv = b[field]\n if (av === bv) continue\n const cmp = av < bv ? -1 : 1\n return direction === 'asc' ? cmp : -cmp\n }\n return 0\n })\n}\n\nexport function applyQuery<T>(docs: T[], options: QueryOptions<T>): T[] {\n let result = docs\n\n if (options.where) {\n const where = options.where\n result = result.filter(doc => matchesWhere(doc, where))\n }\n\n if (options.sort) {\n result = applySort(result, options.sort)\n }\n\n const offset = options.offset ?? 0\n if (offset > 0) {\n result = result.slice(offset)\n }\n\n if (options.limit !== undefined) {\n result = result.slice(0, options.limit)\n }\n\n return result\n}\n","import type { WithMeta } from '../core/schema/types.js'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport type { AuthStore as AuthStoreObservable } from '../core/client/events.js'\nimport type { SyncEngine } from '../core/sync/engine.js'\nimport type { SyncStatus } from '../core/sync/types.js'\nimport type { QueryOptions } from '../core/storage/query.js'\nimport { applyQuery } from '../core/storage/query.js'\nimport type { CollectionStore, AuthStore, SyncStore } from './types.js'\n\n/**\n * Wraps an ObservableCollection into a Svelte-compatible readable store.\n * The store value is updated whenever the collection changes.\n * Supports optional query filtering (where, sort, limit, offset).\n *\n * For full TanStack Query integration, install @tanstack/svelte-query and use\n * `collectionQueryOptions()` with `createQuery()` instead:\n * @example\n * import { collectionQueryOptions } from 'mpb-localkit/svelte'\n * import { createQuery } from '@tanstack/svelte-query'\n * const query = createQuery(collectionQueryOptions(app.todos, { where: { done: false } }))\n * // $query.data — reactively updated, cache-backed array\n *\n * @example\n * const todos = createCollectionStore(app.todos, { where: { done: false }, sort: { title: 'asc' } })\n * // In Svelte: $todos — reactively updated filtered array\n */\nexport function createCollectionStore<T>(\n collection: ObservableCollection<T>,\n queryOptions?: QueryOptions<T>,\n): CollectionStore<T> {\n const getFiltered = (): WithMeta<T>[] => {\n const snapshot = [...collection.getSnapshot()] as WithMeta<T>[]\n return queryOptions ? applyQuery(snapshot, queryOptions) as WithMeta<T>[] : snapshot\n }\n\n return {\n subscribe(run: (value: WithMeta<T>[]) => void): () => void {\n // Emit current filtered snapshot immediately\n run(getFiltered())\n\n // Subscribe to collection changes; re-emit filtered snapshot on each notification\n const unsub = collection.subscribe(() => {\n run(getFiltered())\n })\n\n return unsub\n },\n }\n}\n\n/**\n * Wraps an AuthStore observable into a Svelte-compatible readable store.\n * Reflects the current user and loading state, updating automatically\n * when the auth state changes (sign-in, sign-out, etc.).\n *\n * @example\n * const auth = createAuthStore(app.auth)\n * // In Svelte: $auth.user\n */\nexport function createAuthStore(auth: AuthStoreObservable): AuthStore {\n return {\n subscribe(run) {\n const snap = auth.getSnapshot()\n run({ user: snap.user, isLoading: snap.isLoading })\n return auth.subscribe(() => {\n const s = auth.getSnapshot()\n run({ user: s.user, isLoading: s.isLoading })\n })\n },\n }\n}\n\n/**\n * Wraps a SyncEngine into a Svelte-compatible readable store.\n * Reflects sync status and last sync timestamp.\n *\n * @example\n * const sync = createSyncStore(app.sync)\n * // In Svelte: $sync.status\n */\nexport function createSyncStore(engine: SyncEngine): SyncStore {\n type SyncState = { status: SyncStatus; lastSyncAt: number }\n\n let current: SyncState = {\n status: engine.getStatus(),\n lastSyncAt: engine.getLastSyncAt(),\n }\n\n const subs = new Set<(value: SyncState) => void>()\n\n const notify = (): void => {\n for (const run of subs) run(current)\n }\n\n const onStart = (): void => {\n current = { ...current, status: 'syncing' }\n notify()\n }\n\n const onComplete = (): void => {\n current = { status: 'idle', lastSyncAt: engine.getLastSyncAt() }\n notify()\n }\n\n const onError = (): void => {\n current = { ...current, status: engine.getStatus() }\n notify()\n }\n\n engine.on('sync:start', onStart)\n engine.on('sync:complete', onComplete)\n engine.on('sync:error', onError)\n\n return {\n subscribe(run: (value: SyncState) => void): () => void {\n subs.add(run)\n run(current)\n return () => {\n subs.delete(run)\n if (subs.size === 0) {\n engine.off('sync:start', onStart)\n engine.off('sync:complete', onComplete)\n engine.off('sync:error', onError)\n }\n }\n },\n }\n}\n","import type { QueryOptions } from './storage/query.js'\nimport type { WithMeta } from './schema/types.js'\nimport type { Collection } from './client/collection.js'\n\n/** Minimal QueryClient interface — avoids a hard dep on @tanstack/query-core */\ninterface MinimalQueryClient {\n invalidateQueries(opts: { queryKey: readonly unknown[] }): Promise<void>\n}\n\nexport const localkitKeys = {\n all: ['offlinekit'] as const,\n collection: (name: string) => ['offlinekit', name] as const,\n collectionQuery: (name: string, opts: unknown) =>\n ['offlinekit', name, JSON.stringify(opts)] as const,\n}\n\nexport function collectionQueryOptions<T>(\n collection: Collection<T>,\n queryOptions?: QueryOptions<T>,\n): {\n queryKey: readonly unknown[]\n queryFn: () => Promise<WithMeta<T>[]>\n} {\n const queryKey = queryOptions\n ? localkitKeys.collectionQuery(collection.name, queryOptions)\n : localkitKeys.collection(collection.name)\n\n return {\n queryKey,\n queryFn: () => collection.findMany(queryOptions),\n }\n}\n\nexport function subscribeToCollection<T>(\n collection: Collection<T>,\n queryClient: MinimalQueryClient,\n): () => void {\n const queryKey = localkitKeys.collection(collection.name)\n\n if (!('subscribe' in collection)) {\n return () => {}\n }\n\n const obs = collection as Collection<T> & {\n subscribe(listener: () => void): () => void\n }\n\n return obs.subscribe(() => {\n void queryClient.invalidateQueries({ queryKey })\n })\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mpb-localkit",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.7",
|
|
4
4
|
"description": "Type-driven, offline-first SDK for TypeScript developers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Erik Olsen",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
"bin": {
|
|
44
|
-
"localkit": "dist/cli/index.js"
|
|
44
|
+
"mpb-localkit": "./dist/cli/index.js"
|
|
45
45
|
},
|
|
46
46
|
"files": [
|
|
47
47
|
"dist/core",
|