mpb-localkit 1.3.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.
- package/LICENSE +21 -0
- package/README.md +375 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +853 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/index.d.ts +404 -0
- package/dist/core/index.js +1780 -0
- package/dist/core/index.js.map +1 -0
- package/dist/react/index.d.ts +90 -0
- package/dist/react/index.js +230 -0
- package/dist/react/index.js.map +1 -0
- package/dist/svelte/index.d.ts +60 -0
- package/dist/svelte/index.js +151 -0
- package/dist/svelte/index.js.map +1 -0
- package/dist/vue/index.d.ts +97 -0
- package/dist/vue/index.js +133 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +120 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { shallowRef, ref, onUnmounted } from 'vue';
|
|
2
|
+
|
|
3
|
+
// src/vue/composables.ts
|
|
4
|
+
|
|
5
|
+
// src/core/storage/query.ts
|
|
6
|
+
function isCondition(value) {
|
|
7
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
8
|
+
const keys = Object.keys(value);
|
|
9
|
+
return keys.some((k) => k === "$gt" || k === "$lt" || k === "$gte" || k === "$lte" || k === "$in");
|
|
10
|
+
}
|
|
11
|
+
function matchesWhere(doc, where) {
|
|
12
|
+
for (const key of Object.keys(where)) {
|
|
13
|
+
const condition = where[key];
|
|
14
|
+
const docValue = doc[key];
|
|
15
|
+
if (isCondition(condition)) {
|
|
16
|
+
if (condition.$gt != null && !(docValue > condition.$gt)) return false;
|
|
17
|
+
if (condition.$lt != null && !(docValue < condition.$lt)) return false;
|
|
18
|
+
if (condition.$gte != null && !(docValue >= condition.$gte)) return false;
|
|
19
|
+
if (condition.$lte != null && !(docValue <= condition.$lte)) return false;
|
|
20
|
+
if (condition.$in !== void 0 && !condition.$in.includes(docValue)) return false;
|
|
21
|
+
} else {
|
|
22
|
+
if (docValue !== condition) return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
function applySort(docs, sort) {
|
|
28
|
+
const entries = Object.entries(sort);
|
|
29
|
+
if (entries.length === 0) return docs;
|
|
30
|
+
return [...docs].sort((a, b) => {
|
|
31
|
+
for (const [field, direction] of entries) {
|
|
32
|
+
const av = a[field];
|
|
33
|
+
const bv = b[field];
|
|
34
|
+
if (av === bv) continue;
|
|
35
|
+
const cmp = av < bv ? -1 : 1;
|
|
36
|
+
return direction === "asc" ? cmp : -cmp;
|
|
37
|
+
}
|
|
38
|
+
return 0;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function applyQuery(docs, options) {
|
|
42
|
+
let result = docs;
|
|
43
|
+
if (options.where) {
|
|
44
|
+
const where = options.where;
|
|
45
|
+
result = result.filter((doc) => matchesWhere(doc, where));
|
|
46
|
+
}
|
|
47
|
+
if (options.sort) {
|
|
48
|
+
result = applySort(result, options.sort);
|
|
49
|
+
}
|
|
50
|
+
const offset = options.offset ?? 0;
|
|
51
|
+
if (offset > 0) {
|
|
52
|
+
result = result.slice(offset);
|
|
53
|
+
}
|
|
54
|
+
if (options.limit !== void 0) {
|
|
55
|
+
result = result.slice(0, options.limit);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/vue/composables.ts
|
|
61
|
+
function useCollection(collection, options) {
|
|
62
|
+
const getFiltered = () => {
|
|
63
|
+
const snapshot = [...collection.getSnapshot()];
|
|
64
|
+
return options ? applyQuery(snapshot, options) : snapshot;
|
|
65
|
+
};
|
|
66
|
+
const data = shallowRef(getFiltered());
|
|
67
|
+
const isLoading = ref(false);
|
|
68
|
+
const unsub = collection.subscribe(() => {
|
|
69
|
+
data.value = getFiltered();
|
|
70
|
+
});
|
|
71
|
+
onUnmounted(unsub);
|
|
72
|
+
return { data, isLoading };
|
|
73
|
+
}
|
|
74
|
+
function useAuth(auth) {
|
|
75
|
+
const user = ref(auth.currentUser());
|
|
76
|
+
const isLoading = ref(false);
|
|
77
|
+
const signUp = async (credentials) => {
|
|
78
|
+
isLoading.value = true;
|
|
79
|
+
try {
|
|
80
|
+
await auth.signUp(credentials);
|
|
81
|
+
user.value = auth.currentUser();
|
|
82
|
+
} finally {
|
|
83
|
+
isLoading.value = false;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const signIn = async (credentials) => {
|
|
87
|
+
isLoading.value = true;
|
|
88
|
+
try {
|
|
89
|
+
await auth.signIn(credentials);
|
|
90
|
+
user.value = auth.currentUser();
|
|
91
|
+
} finally {
|
|
92
|
+
isLoading.value = false;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const signOut = async () => {
|
|
96
|
+
isLoading.value = true;
|
|
97
|
+
try {
|
|
98
|
+
await auth.signOut();
|
|
99
|
+
user.value = auth.currentUser();
|
|
100
|
+
} finally {
|
|
101
|
+
isLoading.value = false;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
return { user, isLoading, signUp, signIn, signOut };
|
|
105
|
+
}
|
|
106
|
+
function useSync(engine) {
|
|
107
|
+
const status = ref(engine.getStatus());
|
|
108
|
+
const lastSyncAt = ref(engine.getLastSyncAt());
|
|
109
|
+
const onStart = () => {
|
|
110
|
+
status.value = "syncing";
|
|
111
|
+
};
|
|
112
|
+
const onComplete = () => {
|
|
113
|
+
status.value = "idle";
|
|
114
|
+
lastSyncAt.value = engine.getLastSyncAt();
|
|
115
|
+
};
|
|
116
|
+
const onError = () => {
|
|
117
|
+
status.value = engine.getStatus();
|
|
118
|
+
};
|
|
119
|
+
engine.on("sync:start", onStart);
|
|
120
|
+
engine.on("sync:complete", onComplete);
|
|
121
|
+
engine.on("sync:error", onError);
|
|
122
|
+
onUnmounted(() => {
|
|
123
|
+
engine.off("sync:start", onStart);
|
|
124
|
+
engine.off("sync:complete", onComplete);
|
|
125
|
+
engine.off("sync:error", onError);
|
|
126
|
+
});
|
|
127
|
+
const sync = () => engine.sync().then(() => void 0);
|
|
128
|
+
return { status, lastSyncAt, sync };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export { useAuth, useCollection, useSync };
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
133
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/storage/query.ts","../../src/vue/composables.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 { ref, shallowRef, onUnmounted, type Ref } from 'vue'\nimport type { ObservableCollection } from '../core/client/collection.js'\nimport type { WithMeta } from '../core/schema/types.js'\nimport type { QueryOptions } from '../core/storage/query.js'\nimport { applyQuery } from '../core/storage/query.js'\nimport type { AuthAdapter, User } from '../core/auth/types.js'\nimport type { SyncEngine } from '../core/sync/engine.js'\nimport type { SyncStatus } from '../core/sync/types.js'\n\n/**\n * Reactive wrapper around an {@link ObservableCollection} for Vue.\n * Automatically subscribes to collection changes and returns a reactive `data` ref.\n *\n * @param collection - The observable collection to subscribe to.\n * @param options - Optional query options (where, sort, limit, offset).\n * @returns An object with a reactive `data` array and an `isLoading` flag.\n *\n * @example\n * ```vue\n * <script setup>\n * const { data: todos } = useCollection(app.todos, {\n * where: { done: { $eq: false } },\n * sort: { field: 'title', direction: 'asc' },\n * })\n * </script>\n * ```\n */\nexport function useCollection<T>(\n collection: ObservableCollection<T>,\n options?: QueryOptions<T>,\n): { data: Ref<WithMeta<T>[]>; isLoading: Ref<boolean> } {\n const getFiltered = (): WithMeta<T>[] => {\n const snapshot = [...collection.getSnapshot()] as WithMeta<T>[]\n return options ? (applyQuery(snapshot, options) as WithMeta<T>[]) : snapshot\n }\n\n const data = shallowRef<WithMeta<T>[]>(getFiltered())\n const isLoading = ref(false)\n\n const unsub = collection.subscribe(() => {\n data.value = getFiltered()\n })\n\n onUnmounted(unsub)\n\n return { data, isLoading }\n}\n\n/**\n * Reactive auth state for Vue. Wraps an {@link AuthAdapter} and exposes\n * reactive `user` and `isLoading` refs, plus `signUp`, `signIn`, and `signOut` methods.\n *\n * @param auth - The auth adapter to wrap.\n * @returns Reactive auth state and action methods.\n *\n * @example\n * ```vue\n * <script setup>\n * const { user, isLoading, signIn, signOut } = useAuth(app.auth)\n * </script>\n * ```\n */\nexport function useAuth(auth: AuthAdapter): {\n user: Ref<User | null>\n isLoading: Ref<boolean>\n signUp(credentials: { email: string; password: string }): Promise<void>\n signIn(credentials: { email: string; password: string }): Promise<void>\n signOut(): Promise<void>\n} {\n const user = ref<User | null>(auth.currentUser())\n const isLoading = ref(false)\n\n const signUp = async (credentials: { email: string; password: string }): Promise<void> => {\n isLoading.value = true\n try {\n await auth.signUp(credentials)\n user.value = auth.currentUser()\n } finally {\n isLoading.value = false\n }\n }\n\n const signIn = async (credentials: { email: string; password: string }): Promise<void> => {\n isLoading.value = true\n try {\n await auth.signIn(credentials)\n user.value = auth.currentUser()\n } finally {\n isLoading.value = false\n }\n }\n\n const signOut = async (): Promise<void> => {\n isLoading.value = true\n try {\n await auth.signOut()\n user.value = auth.currentUser()\n } finally {\n isLoading.value = false\n }\n }\n\n return { user, isLoading, signUp, signIn, signOut }\n}\n\n/**\n * Reactive sync state for Vue. Subscribes to sync engine events and exposes\n * reactive `status` and `lastSyncAt` refs, plus a `sync()` trigger.\n *\n * @param engine - The {@link SyncEngine} instance to observe.\n * @returns Reactive sync state and a `sync` function to trigger a sync cycle.\n *\n * @example\n * ```vue\n * <script setup>\n * const { status, lastSyncAt, sync } = useSync(syncEngine)\n * </script>\n * ```\n */\nexport function useSync(engine: SyncEngine): {\n status: Ref<SyncStatus>\n lastSyncAt: Ref<number>\n sync(): Promise<void>\n} {\n const status = ref<SyncStatus>(engine.getStatus())\n const lastSyncAt = ref(engine.getLastSyncAt())\n\n const onStart = (): void => { status.value = 'syncing' }\n const onComplete = (): void => {\n status.value = 'idle'\n lastSyncAt.value = engine.getLastSyncAt()\n }\n const onError = (): void => { status.value = engine.getStatus() }\n\n engine.on('sync:start', onStart)\n engine.on('sync:complete', onComplete)\n engine.on('sync:error', onError)\n\n onUnmounted(() => {\n engine.off('sync:start', onStart)\n engine.off('sync:complete', onComplete)\n engine.off('sync:error', onError)\n })\n\n const sync = (): Promise<void> => engine.sync().then(() => undefined)\n\n return { status, lastSyncAt, sync }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mpb-localkit",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Type-driven, offline-first SDK for TypeScript developers",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Erik Olsen",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"offline-first",
|
|
9
|
+
"indexeddb",
|
|
10
|
+
"sync",
|
|
11
|
+
"typescript",
|
|
12
|
+
"cloudflare-workers",
|
|
13
|
+
"zod",
|
|
14
|
+
"react",
|
|
15
|
+
"svelte",
|
|
16
|
+
"local-first"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/core/index.d.ts",
|
|
28
|
+
"import": "./dist/core/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./react": {
|
|
31
|
+
"types": "./dist/react/index.d.ts",
|
|
32
|
+
"import": "./dist/react/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./svelte": {
|
|
35
|
+
"types": "./dist/svelte/index.d.ts",
|
|
36
|
+
"import": "./dist/svelte/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./vue": {
|
|
39
|
+
"types": "./dist/vue/index.d.ts",
|
|
40
|
+
"import": "./dist/vue/index.js"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"bin": {
|
|
44
|
+
"localkit": "dist/cli/index.js"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist/core",
|
|
48
|
+
"dist/react",
|
|
49
|
+
"dist/svelte",
|
|
50
|
+
"dist/vue",
|
|
51
|
+
"dist/cli",
|
|
52
|
+
"README.md",
|
|
53
|
+
"LICENSE"
|
|
54
|
+
],
|
|
55
|
+
"sideEffects": false,
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"commander": "^12.1.0",
|
|
58
|
+
"idb": "^8.0.0",
|
|
59
|
+
"uuid": "^10.0.0",
|
|
60
|
+
"zod": "^3.23.8"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@tanstack/query-core": "^5.62.0",
|
|
64
|
+
"@tanstack/react-query": "^5.62.0",
|
|
65
|
+
"@testing-library/react": "^16.0.0",
|
|
66
|
+
"@types/node": "^22.0.0",
|
|
67
|
+
"@types/react": "^19.0.0",
|
|
68
|
+
"@types/react-dom": "^19.0.0",
|
|
69
|
+
"@types/uuid": "^10.0.0",
|
|
70
|
+
"@vitest/coverage-v8": "^2.1.9",
|
|
71
|
+
"fake-indexeddb": "^6.0.0",
|
|
72
|
+
"hono": "^4.6.0",
|
|
73
|
+
"jsdom": "^25.0.0",
|
|
74
|
+
"miniflare": "^3.20241106.1",
|
|
75
|
+
"react": "^19.0.0",
|
|
76
|
+
"react-dom": "^19.0.0",
|
|
77
|
+
"tsup": "^8.3.0",
|
|
78
|
+
"typescript": "^5.6.0",
|
|
79
|
+
"vitest": "^2.1.0",
|
|
80
|
+
"vue": "^3.5.29"
|
|
81
|
+
},
|
|
82
|
+
"peerDependencies": {
|
|
83
|
+
"@tanstack/react-query": ">=5.0.0",
|
|
84
|
+
"@tanstack/svelte-query": ">=5.0.0",
|
|
85
|
+
"better-auth": "^1.0.0",
|
|
86
|
+
"react": ">=18.0.0",
|
|
87
|
+
"react-dom": ">=18.0.0",
|
|
88
|
+
"svelte": "^4.0.0 || ^5.0.0",
|
|
89
|
+
"vue": ">=3.3.0"
|
|
90
|
+
},
|
|
91
|
+
"peerDependenciesMeta": {
|
|
92
|
+
"react": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"react-dom": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"@tanstack/react-query": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"@tanstack/svelte-query": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"better-auth": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"svelte": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"vue": {
|
|
111
|
+
"optional": true
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"scripts": {
|
|
115
|
+
"build": "tsup",
|
|
116
|
+
"typecheck": "tsc --noEmit",
|
|
117
|
+
"test": "vitest run",
|
|
118
|
+
"dev": "vitest"
|
|
119
|
+
}
|
|
120
|
+
}
|