@meeovi/layer-lists 1.0.2 → 1.0.3
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 +111 -0
- package/app/composables/config.ts +1 -1
- package/app/composables/module.ts +75 -0
- package/app/composables/providers/directus.ts +112 -16
- package/app/composables/providers/memory.ts +39 -0
- package/app/composables/registry.ts +5 -0
- package/app/composables/types.ts +9 -0
- package/app/composables/utils/health.ts +16 -0
- package/dist/app/composables/config.d.ts +7 -0
- package/dist/app/composables/config.js +9 -0
- package/dist/app/composables/globals/useDirectusForm.d.ts +4 -0
- package/dist/app/composables/globals/useDirectusForm.js +10 -0
- package/dist/app/composables/module.d.ts +7 -0
- package/dist/app/composables/module.js +60 -0
- package/dist/app/composables/providers/atproto.d.ts +1 -0
- package/dist/app/composables/providers/atproto.js +133 -0
- package/dist/app/composables/providers/directus.d.ts +1 -0
- package/dist/app/composables/providers/directus.js +130 -0
- package/dist/app/composables/providers/memory.d.ts +1 -0
- package/dist/app/composables/providers/memory.js +110 -0
- package/dist/app/composables/registry.d.ts +4 -0
- package/dist/app/composables/registry.js +14 -0
- package/dist/app/composables/types.d.ts +38 -0
- package/dist/app/composables/types.js +1 -0
- package/dist/app/composables/useLists.d.ts +11 -0
- package/dist/app/composables/useLists.js +17 -0
- package/dist/app/composables/utils/health.d.ts +10 -0
- package/dist/app/composables/utils/health.js +15 -0
- package/dist/app/composables/utils/transforms.d.ts +13 -0
- package/dist/app/composables/utils/transforms.js +38 -0
- package/dist/app/composables/utils/validation.d.ts +3 -0
- package/dist/app/composables/utils/validation.js +16 -0
- package/dist/layers/lists/app/composables/config.d.ts +7 -0
- package/dist/layers/lists/app/composables/config.js +9 -0
- package/dist/layers/lists/app/composables/globals/useDirectusForm.d.ts +1 -0
- package/dist/layers/lists/app/composables/globals/useDirectusForm.js +1 -0
- package/dist/layers/lists/app/composables/module.d.ts +7 -0
- package/dist/layers/lists/app/composables/module.js +60 -0
- package/dist/layers/lists/app/composables/providers/atproto.d.ts +1 -0
- package/dist/layers/lists/app/composables/providers/atproto.js +133 -0
- package/dist/layers/lists/app/composables/providers/directus.d.ts +1 -0
- package/dist/layers/lists/app/composables/providers/directus.js +130 -0
- package/dist/layers/lists/app/composables/providers/memory.d.ts +1 -0
- package/dist/layers/lists/app/composables/providers/memory.js +110 -0
- package/dist/layers/lists/app/composables/registry.d.ts +4 -0
- package/dist/layers/lists/app/composables/registry.js +14 -0
- package/dist/layers/lists/app/composables/types.d.ts +38 -0
- package/dist/layers/lists/app/composables/types.js +1 -0
- package/dist/layers/lists/app/composables/useLists.d.ts +11 -0
- package/dist/layers/lists/app/composables/useLists.js +17 -0
- package/dist/layers/lists/app/composables/utils/health.d.ts +10 -0
- package/dist/layers/lists/app/composables/utils/health.js +15 -0
- package/dist/layers/lists/app/composables/utils/transforms.d.ts +13 -0
- package/dist/layers/lists/app/composables/utils/transforms.js +38 -0
- package/dist/layers/lists/app/composables/utils/validation.d.ts +3 -0
- package/dist/layers/lists/app/composables/utils/validation.js +16 -0
- package/dist/layers/lists/nuxt.config.d.ts +2 -0
- package/dist/layers/lists/nuxt.config.js +7 -0
- package/dist/layers/shared/app/composables/globals/useDirectusForm.d.ts +10 -0
- package/dist/layers/shared/app/composables/globals/useDirectusForm.js +66 -0
- package/dist/lists/app/composables/config.d.ts +7 -0
- package/dist/lists/app/composables/config.js +9 -0
- package/dist/lists/app/composables/globals/useDirectusForm.d.ts +1 -0
- package/dist/lists/app/composables/globals/useDirectusForm.js +1 -0
- package/dist/lists/app/composables/module.d.ts +7 -0
- package/dist/lists/app/composables/module.js +60 -0
- package/dist/lists/app/composables/providers/atproto.d.ts +1 -0
- package/dist/lists/app/composables/providers/atproto.js +133 -0
- package/dist/lists/app/composables/providers/directus.d.ts +1 -0
- package/dist/lists/app/composables/providers/directus.js +130 -0
- package/dist/lists/app/composables/providers/memory.d.ts +1 -0
- package/dist/lists/app/composables/providers/memory.js +110 -0
- package/dist/lists/app/composables/registry.d.ts +4 -0
- package/dist/lists/app/composables/registry.js +14 -0
- package/dist/lists/app/composables/types.d.ts +38 -0
- package/dist/lists/app/composables/types.js +1 -0
- package/dist/lists/app/composables/useLists.d.ts +11 -0
- package/dist/lists/app/composables/useLists.js +17 -0
- package/dist/lists/app/composables/utils/health.d.ts +10 -0
- package/dist/lists/app/composables/utils/health.js +15 -0
- package/dist/lists/app/composables/utils/transforms.d.ts +13 -0
- package/dist/lists/app/composables/utils/transforms.js +38 -0
- package/dist/lists/app/composables/utils/validation.d.ts +3 -0
- package/dist/lists/app/composables/utils/validation.js +16 -0
- package/dist/lists/nuxt.config.d.ts +2 -0
- package/dist/lists/nuxt.config.js +7 -0
- package/dist/nuxt.config.d.ts +2 -0
- package/dist/nuxt.config.js +7 -0
- package/dist/packages/core/index.d.ts +17 -0
- package/dist/packages/core/index.js +18 -0
- package/dist/packages/core/src/adapters/auth.d.ts +9 -0
- package/dist/packages/core/src/adapters/auth.js +1 -0
- package/dist/packages/core/src/adapters/cart.d.ts +22 -0
- package/dist/packages/core/src/adapters/cart.js +1 -0
- package/dist/packages/core/src/adapters/catalog.d.ts +17 -0
- package/dist/packages/core/src/adapters/catalog.js +1 -0
- package/dist/packages/core/src/adapters/common.d.ts +9 -0
- package/dist/packages/core/src/adapters/common.js +1 -0
- package/dist/packages/core/src/adapters/lists.d.ts +17 -0
- package/dist/packages/core/src/adapters/lists.js +1 -0
- package/dist/packages/core/src/adapters/search.d.ts +21 -0
- package/dist/packages/core/src/adapters/search.js +1 -0
- package/dist/packages/core/src/plugins/defineAdapter.d.ts +2 -0
- package/dist/packages/core/src/plugins/defineAdapter.js +3 -0
- package/dist/packages/core/src/plugins/defineModule.d.ts +2 -0
- package/dist/packages/core/src/plugins/defineModule.js +3 -0
- package/dist/packages/core/src/plugins/registry.d.ts +14 -0
- package/dist/packages/core/src/plugins/registry.js +46 -0
- package/dist/packages/core/src/runtime/app.d.ts +2 -0
- package/dist/packages/core/src/runtime/app.js +20 -0
- package/dist/packages/core/src/runtime/config.d.ts +7 -0
- package/dist/packages/core/src/runtime/config.js +9 -0
- package/dist/packages/core/src/runtime/context.d.ts +9 -0
- package/dist/packages/core/src/runtime/context.js +11 -0
- package/dist/packages/core/src/runtime/hooks.d.ts +5 -0
- package/dist/packages/core/src/runtime/hooks.js +18 -0
- package/dist/packages/core/src/runtime/lifecycle.d.ts +4 -0
- package/dist/packages/core/src/runtime/lifecycle.js +5 -0
- package/dist/packages/core/src/types/adapters.d.ts +14 -0
- package/dist/packages/core/src/types/adapters.js +1 -0
- package/dist/packages/core/src/types/app.d.ts +13 -0
- package/dist/packages/core/src/types/app.js +1 -0
- package/dist/packages/core/src/types/config.d.ts +8 -0
- package/dist/packages/core/src/types/config.js +1 -0
- package/dist/packages/core/src/types/events.d.ts +20 -0
- package/dist/packages/core/src/types/events.js +22 -0
- package/dist/packages/core/src/types/module.d.ts +15 -0
- package/dist/packages/core/src/types/module.js +1 -0
- package/dist/shared/app/composables/globals/useDirectusForm.d.ts +10 -0
- package/dist/shared/app/composables/globals/useDirectusForm.js +66 -0
- package/global.d.ts +1 -0
- package/package.json +4 -1
- package/shims.d.ts +7 -0
- package/tsconfig.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# @meeovi/layer-lists
|
|
2
|
+
|
|
3
|
+
This layer provides first-class lists and task management functionality for the Alternate Framework. It's provider-driven: you can plug in different backends (Directus, memory, ATProto, etc.) without changing UI code. The default production-ready fallback is the `@meeovi/directus-client` provider.
|
|
4
|
+
|
|
5
|
+
Key goals:
|
|
6
|
+
- Provider-agnostic API used by the UI (`useLists()` composable).
|
|
7
|
+
- Advanced task features (due dates, reminders, priority, sharing, search, archive) exposed as optional provider methods.
|
|
8
|
+
- Production-ready defaults: Directus provider, health checks, graceful fallbacks.
|
|
9
|
+
|
|
10
|
+
Quick start
|
|
11
|
+
|
|
12
|
+
Install the layer into your project (monorepo/local install):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @meeovi/layer-lists
|
|
16
|
+
# also install your chosen provider (Directus example)
|
|
17
|
+
npm install @meeovi/directus-client
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Register the layer and configure the provider in your Alternate app (Directus example):
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import lists from '@meeovi/layer-lists'
|
|
24
|
+
|
|
25
|
+
const app = createAlternateApp({
|
|
26
|
+
config: {
|
|
27
|
+
lists: {
|
|
28
|
+
provider: 'directus',
|
|
29
|
+
directus: {
|
|
30
|
+
baseUrl: 'https://cms.example.com',
|
|
31
|
+
apiKey: process.env.DIRECTUS_KEY
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
modules: [lists]
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
await app.start()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Using in a Nuxt (modules) app
|
|
42
|
+
|
|
43
|
+
1. Install the packages into your Nuxt app project.
|
|
44
|
+
2. Add the layer module to your Nuxt alternate app bootstrap (see above).
|
|
45
|
+
3. In Vue components or composables, use the `useLists()` composable the same way as in the Alternate UI:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const { listLists, createList, addItem, updateItem } = useLists()
|
|
49
|
+
|
|
50
|
+
const lists = await listLists()
|
|
51
|
+
await createList({ title: 'Groceries' })
|
|
52
|
+
await addItem('list-id', { title: 'Buy milk', metadata: { dueDate: '2026-02-01' } })
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Advanced features
|
|
56
|
+
|
|
57
|
+
Providers may implement optional advanced methods:
|
|
58
|
+
- `toggleComplete(listId, itemId, completed)`
|
|
59
|
+
- `setDueDate(listId, itemId, dueDate)`
|
|
60
|
+
- `setReminder(listId, itemId, reminder)`
|
|
61
|
+
- `setPriority(listId, itemId, priority)`
|
|
62
|
+
- `shareList(listId, userId, role)`
|
|
63
|
+
- `searchItems(listId, query)`
|
|
64
|
+
- `archiveList(listId)`
|
|
65
|
+
|
|
66
|
+
If a provider doesn't implement these methods, the `memory` provider includes sensible defaults and the `directus` provider attempts fallbacks to existing endpoints when possible.
|
|
67
|
+
|
|
68
|
+
Creating a provider
|
|
69
|
+
|
|
70
|
+
Implement a `ListsProvider` and register it with `registerListsProvider(name, provider)`.
|
|
71
|
+
|
|
72
|
+
Example skeleton (register at runtime):
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { registerListsProvider } from '@meeovi/layer-lists/app/composables/registry'
|
|
76
|
+
|
|
77
|
+
const MyProvider = {
|
|
78
|
+
async getList(id) { /* ... */ },
|
|
79
|
+
async listLists() { /* ... */ },
|
|
80
|
+
async createList(data) { /* ... */ },
|
|
81
|
+
async addItem(listId, item) { /* ... */ },
|
|
82
|
+
// ... implement optional methods as desired
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
registerListsProvider('my-provider', MyProvider)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Runtime registration
|
|
89
|
+
|
|
90
|
+
Other modules can register providers at runtime using `registerListsProviderRuntime(name, provider)`.
|
|
91
|
+
|
|
92
|
+
Health checks
|
|
93
|
+
|
|
94
|
+
Use the provided `checkListsProviderHealth()` helper to validate that the configured provider is reachable (it performs a lightweight `listLists()` call). Example:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { checkListsProviderHealth } from '@meeovi/layer-lists/app/composables/utils/health'
|
|
98
|
+
|
|
99
|
+
const healthy = await checkListsProviderHealth()
|
|
100
|
+
if (!healthy) {
|
|
101
|
+
// fallback or alert
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
What's next
|
|
106
|
+
|
|
107
|
+
- Add server-side sync/notifications (webhooks) for reminders.
|
|
108
|
+
- Add tests and CI for providers and bridges.
|
|
109
|
+
- Provide an Express example wiring server-side endpoints to the Directus client.
|
|
110
|
+
|
|
111
|
+
License: MIT
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineAlternateModule,
|
|
3
|
+
useAlternateEventBus,
|
|
4
|
+
useAlternateContext,
|
|
5
|
+
type AlternateContext,
|
|
6
|
+
type ListsAdapter
|
|
7
|
+
} from '@meeovi/core'
|
|
8
|
+
|
|
9
|
+
import { getListsConfig } from './config'
|
|
10
|
+
import { registerListsProviderRuntime } from './registry'
|
|
11
|
+
|
|
12
|
+
export default defineAlternateModule({
|
|
13
|
+
id: 'lists',
|
|
14
|
+
adapters: {},
|
|
15
|
+
|
|
16
|
+
async setup(ctx: AlternateContext) {
|
|
17
|
+
const bus = useAlternateEventBus()
|
|
18
|
+
const config = getListsConfig()
|
|
19
|
+
|
|
20
|
+
// If a core adapter was registered under the `lists` key, register it
|
|
21
|
+
// into the local provider registry so UI code can consume it via `useLists()`.
|
|
22
|
+
// If a core adapter was registered under the `lists` key, adapt it
|
|
23
|
+
// into the `ListsProvider` shape and register it into the local registry.
|
|
24
|
+
try {
|
|
25
|
+
const runtimeAdapter = ctx.getAdapter('lists' as any) as ListsAdapter | undefined
|
|
26
|
+
if (runtimeAdapter) {
|
|
27
|
+
const provider = {
|
|
28
|
+
getList: (id: string) => runtimeAdapter.getList(id),
|
|
29
|
+
listLists: (params?: Record<string, unknown>) => runtimeAdapter.listLists(params),
|
|
30
|
+
createList: (data: Partial<Record<string, unknown>>) => runtimeAdapter.createList(data),
|
|
31
|
+
updateList: (id: string, data: Partial<Record<string, unknown>>) => runtimeAdapter.updateList(id, data),
|
|
32
|
+
deleteList: (id: string) => runtimeAdapter.deleteList(id),
|
|
33
|
+
|
|
34
|
+
addItem: (listId: string, item: Partial<Record<string, unknown>>) => runtimeAdapter.addItem(listId, item),
|
|
35
|
+
updateItem: (listId: string, itemId: string, data: Partial<Record<string, unknown>>) => runtimeAdapter.updateItem(listId, itemId, data),
|
|
36
|
+
deleteItem: (listId: string, itemId: string) => runtimeAdapter.deleteItem(listId, itemId),
|
|
37
|
+
|
|
38
|
+
reorderItems: runtimeAdapter.reorderItems ? (listId: string, itemIds: string[]) => runtimeAdapter.reorderItems!(listId, itemIds) : undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
registerListsProviderRuntime('core', provider)
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {
|
|
44
|
+
// noop
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Listen for runtime adapter registrations from ModuleRegistry
|
|
48
|
+
bus.on('adapter:registered' as any, (payload: any) => {
|
|
49
|
+
try {
|
|
50
|
+
if (payload?.key === 'lists') {
|
|
51
|
+
const runtimeAdapter = ctx.getAdapter('lists' as any) as ListsAdapter | undefined
|
|
52
|
+
if (runtimeAdapter) {
|
|
53
|
+
const provider = {
|
|
54
|
+
getList: (id: string) => runtimeAdapter.getList(id),
|
|
55
|
+
listLists: (params?: Record<string, unknown>) => runtimeAdapter.listLists(params),
|
|
56
|
+
createList: (data: Partial<Record<string, unknown>>) => runtimeAdapter.createList(data),
|
|
57
|
+
updateList: (id: string, data: Partial<Record<string, unknown>>) => runtimeAdapter.updateList(id, data),
|
|
58
|
+
deleteList: (id: string) => runtimeAdapter.deleteList(id),
|
|
59
|
+
|
|
60
|
+
addItem: (listId: string, item: Partial<Record<string, unknown>>) => runtimeAdapter.addItem(listId, item),
|
|
61
|
+
updateItem: (listId: string, itemId: string, data: Partial<Record<string, unknown>>) => runtimeAdapter.updateItem(listId, itemId, data),
|
|
62
|
+
deleteItem: (listId: string, itemId: string) => runtimeAdapter.deleteItem(listId, itemId),
|
|
63
|
+
|
|
64
|
+
reorderItems: runtimeAdapter.reorderItems ? (listId: string, itemIds: string[]) => runtimeAdapter.reorderItems!(listId, itemIds) : undefined
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
registerListsProviderRuntime('core', provider)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
/* noop */
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
})
|
|
@@ -1,48 +1,144 @@
|
|
|
1
1
|
import { registerListsProvider } from '../registry'
|
|
2
2
|
import type { ListsProvider } from '../types'
|
|
3
|
-
import {
|
|
3
|
+
import { getListsConfig } from '../config'
|
|
4
|
+
|
|
5
|
+
async function directusFetch(path: string, options: RequestInit = {}) {
|
|
6
|
+
const cfg = getListsConfig()
|
|
7
|
+
const base = cfg.baseUrl?.replace(/\/$/, '') || ''
|
|
8
|
+
|
|
9
|
+
const res = await fetch(`${base}${path}`, {
|
|
10
|
+
...options,
|
|
11
|
+
headers: {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
...(cfg.apiKey ? { Authorization: `Bearer ${cfg.apiKey}` } : {}),
|
|
14
|
+
...(options.headers || {})
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
const err: any = new Error(`Directus error: ${res.status}`)
|
|
20
|
+
err.status = res.status
|
|
21
|
+
err.response = res
|
|
22
|
+
throw err
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return res.json()
|
|
26
|
+
}
|
|
4
27
|
|
|
5
28
|
const DirectusListsProvider: ListsProvider = {
|
|
6
29
|
async getList(id) {
|
|
7
|
-
const
|
|
8
|
-
return
|
|
30
|
+
const json = await directusFetch(`/lists/${id}`)
|
|
31
|
+
return json.list ?? json
|
|
9
32
|
},
|
|
10
33
|
|
|
11
34
|
async listLists() {
|
|
12
|
-
const
|
|
13
|
-
return
|
|
35
|
+
const json = await directusFetch(`/lists`)
|
|
36
|
+
return json.lists ?? json
|
|
14
37
|
},
|
|
15
38
|
|
|
16
39
|
async createList(data) {
|
|
17
|
-
const
|
|
18
|
-
return
|
|
40
|
+
const json = await directusFetch(`/lists`, { method: 'POST', body: JSON.stringify(data) })
|
|
41
|
+
return json.list ?? json
|
|
19
42
|
},
|
|
20
43
|
|
|
21
44
|
async updateList(id, data) {
|
|
22
|
-
const
|
|
23
|
-
return
|
|
45
|
+
const json = await directusFetch(`/lists/${id}`, { method: 'PUT', body: JSON.stringify(data) })
|
|
46
|
+
return json.list ?? json
|
|
24
47
|
},
|
|
25
48
|
|
|
26
49
|
async deleteList(id) {
|
|
27
|
-
await
|
|
50
|
+
await directusFetch(`/lists/${id}`, { method: 'DELETE' })
|
|
28
51
|
},
|
|
29
52
|
|
|
30
53
|
async addItem(listId, item) {
|
|
31
|
-
const
|
|
32
|
-
return
|
|
54
|
+
const json = await directusFetch(`/lists/${listId}/items`, { method: 'POST', body: JSON.stringify(item) })
|
|
55
|
+
return json.item ?? json
|
|
33
56
|
},
|
|
34
57
|
|
|
35
58
|
async updateItem(listId, itemId, data) {
|
|
36
|
-
const
|
|
37
|
-
return
|
|
59
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify(data) })
|
|
60
|
+
return json.item ?? json
|
|
38
61
|
},
|
|
39
62
|
|
|
40
63
|
async deleteItem(listId, itemId) {
|
|
41
|
-
await
|
|
64
|
+
await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'DELETE' })
|
|
42
65
|
},
|
|
43
66
|
|
|
44
67
|
async reorderItems(listId, itemIds) {
|
|
45
|
-
await
|
|
68
|
+
await directusFetch(`/lists/${listId}/reorder`, { method: 'POST', body: JSON.stringify({ items: itemIds }) })
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
async toggleComplete(listId, itemId, completed = true) {
|
|
72
|
+
try {
|
|
73
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}/toggle`, { method: 'POST', body: JSON.stringify({ completed }) })
|
|
74
|
+
return json.item ?? json
|
|
75
|
+
} catch (e) {
|
|
76
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ completed }) })
|
|
77
|
+
return json.item ?? json
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async setDueDate(listId, itemId, dueDate) {
|
|
82
|
+
try {
|
|
83
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}/due`, { method: 'POST', body: JSON.stringify({ dueDate }) })
|
|
84
|
+
return json.item ?? json
|
|
85
|
+
} catch (e) {
|
|
86
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ metadata: { dueDate } }) })
|
|
87
|
+
return json.item ?? json
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async setReminder(listId, itemId, reminder) {
|
|
92
|
+
try {
|
|
93
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}/reminder`, { method: 'POST', body: JSON.stringify({ reminder }) })
|
|
94
|
+
return json.item ?? json
|
|
95
|
+
} catch (e) {
|
|
96
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ metadata: { reminder } }) })
|
|
97
|
+
return json.item ?? json
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
async setPriority(listId, itemId, priority) {
|
|
102
|
+
try {
|
|
103
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}/priority`, { method: 'POST', body: JSON.stringify({ priority }) })
|
|
104
|
+
return json.item ?? json
|
|
105
|
+
} catch (e) {
|
|
106
|
+
const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ metadata: { priority } }) })
|
|
107
|
+
return json.item ?? json
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
async shareList(listId, userId, role = 'editor') {
|
|
112
|
+
try {
|
|
113
|
+
await directusFetch(`/lists/${listId}/share`, { method: 'POST', body: JSON.stringify({ userId, role }) })
|
|
114
|
+
} catch (e) {
|
|
115
|
+
const json = await directusFetch(`/lists/${listId}`)
|
|
116
|
+
const list = json.list ?? json
|
|
117
|
+
const collaborators = (list.metadata?.collaborators || []).concat({ userId, role })
|
|
118
|
+
await directusFetch(`/lists/${listId}`, { method: 'PUT', body: JSON.stringify({ metadata: { ...(list.metadata || {}), collaborators } }) })
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
async searchItems(listId, query) {
|
|
123
|
+
try {
|
|
124
|
+
const json = await directusFetch(`/lists/${listId}/search?q=${encodeURIComponent(String(query))}`)
|
|
125
|
+
return json.items ?? json
|
|
126
|
+
} catch (e) {
|
|
127
|
+
const json = await directusFetch(`/lists/${listId}`)
|
|
128
|
+
const list = json.list ?? json
|
|
129
|
+
const q = String(query).toLowerCase()
|
|
130
|
+
return list.items.filter((i: any) => (i.title || '').toLowerCase().includes(q) || (i.description || '').toLowerCase().includes(q))
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
async archiveList(listId) {
|
|
135
|
+
try {
|
|
136
|
+
await directusFetch(`/lists/${listId}/archive`, { method: 'POST' })
|
|
137
|
+
} catch (e) {
|
|
138
|
+
const json = await directusFetch(`/lists/${listId}`)
|
|
139
|
+
const list = json.list ?? json
|
|
140
|
+
await directusFetch(`/lists/${listId}`, { method: 'PUT', body: JSON.stringify({ metadata: { ...(list.metadata || {}), archived: true } }) })
|
|
141
|
+
}
|
|
46
142
|
}
|
|
47
143
|
}
|
|
48
144
|
|
|
@@ -82,6 +82,45 @@ const MemoryListsProvider: ListsProvider = {
|
|
|
82
82
|
...item,
|
|
83
83
|
position: index
|
|
84
84
|
}))
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
async toggleComplete(listId, itemId, completed = true) {
|
|
88
|
+
const item = await this.updateItem(listId, itemId, { completed })
|
|
89
|
+
return item
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
async setDueDate(listId, itemId, dueDate) {
|
|
93
|
+
const item = await this.updateItem(listId, itemId, { metadata: { ...( (await this.getList(listId)).items.find(i => i.id === itemId)?.metadata || {} ), dueDate } })
|
|
94
|
+
return item
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
async setReminder(listId, itemId, reminder) {
|
|
98
|
+
const item = await this.updateItem(listId, itemId, { metadata: { ...( (await this.getList(listId)).items.find(i => i.id === itemId)?.metadata || {} ), reminder } })
|
|
99
|
+
return item
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
async setPriority(listId, itemId, priority) {
|
|
103
|
+
const item = await this.updateItem(listId, itemId, { metadata: { ...( (await this.getList(listId)).items.find(i => i.id === itemId)?.metadata || {} ), priority } })
|
|
104
|
+
return item
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
async shareList(listId, userId, role = 'editor') {
|
|
108
|
+
// memory store: attach collaborators in list.metadata.collaborators
|
|
109
|
+
const list = await this.getList(listId)
|
|
110
|
+
const collaborators = (list.metadata?.collaborators as any[]) || []
|
|
111
|
+
collaborators.push({ userId, role })
|
|
112
|
+
list.metadata = { ...(list.metadata || {}), collaborators }
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
async searchItems(listId, query) {
|
|
116
|
+
const list = await this.getList(listId)
|
|
117
|
+
const q = String(query).toLowerCase()
|
|
118
|
+
return list.items.filter(i => (i.title || '').toLowerCase().includes(q) || (i.description || '').toLowerCase().includes(q))
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
async archiveList(listId) {
|
|
122
|
+
const list = await this.getList(listId)
|
|
123
|
+
list.metadata = { ...(list.metadata || {}), archived: true }
|
|
85
124
|
}
|
|
86
125
|
}
|
|
87
126
|
|
|
@@ -6,6 +6,11 @@ export function registerListsProvider(name: string, provider: ListsProvider) {
|
|
|
6
6
|
providers[name] = provider
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
// Allow runtime registration from other modules (e.g. via core ModuleRegistry adapters)
|
|
10
|
+
export function registerListsProviderRuntime(name: string, provider: ListsProvider) {
|
|
11
|
+
registerListsProvider(name, provider)
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
export function getListsProvider(name: string): ListsProvider {
|
|
10
15
|
const provider = providers[name]
|
|
11
16
|
if (!provider) throw new Error(`Lists provider "${name}" not found`)
|
package/app/composables/types.ts
CHANGED
|
@@ -32,4 +32,13 @@ export interface ListsProvider {
|
|
|
32
32
|
deleteItem(listId: string, itemId: string): Promise<void>
|
|
33
33
|
|
|
34
34
|
reorderItems?(listId: string, itemIds: string[]): Promise<void>
|
|
35
|
+
|
|
36
|
+
// Optional advanced features commonly found in task apps
|
|
37
|
+
toggleComplete?(listId: string, itemId: string, completed: boolean): Promise<ListItem>
|
|
38
|
+
setDueDate?(listId: string, itemId: string, dueDate: string | null): Promise<ListItem>
|
|
39
|
+
setReminder?(listId: string, itemId: string, reminder: string | null): Promise<ListItem>
|
|
40
|
+
setPriority?(listId: string, itemId: string, priority: number | null): Promise<ListItem>
|
|
41
|
+
shareList?(listId: string, userId: string, role?: string): Promise<void>
|
|
42
|
+
searchItems?(listId: string, query: string): Promise<ListItem[]>
|
|
43
|
+
archiveList?(listId: string): Promise<void>
|
|
35
44
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getListsProvider } from '../registry'
|
|
2
|
+
import { getListsConfig } from '../config'
|
|
3
|
+
|
|
4
|
+
export async function checkListsProviderHealth(providerName?: string) {
|
|
5
|
+
try {
|
|
6
|
+
const cfg = getListsConfig()
|
|
7
|
+
const name = providerName || cfg.provider || 'directus'
|
|
8
|
+
const provider = getListsProvider(name)
|
|
9
|
+
const lists = await provider.listLists()
|
|
10
|
+
return { ok: true, count: Array.isArray(lists) ? lists.length : null }
|
|
11
|
+
} catch (e: any) {
|
|
12
|
+
return { ok: false, error: e?.message || String(e) }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default checkListsProviderHealth
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Light stub for isolated typechecks and builds.
|
|
2
|
+
// In the real app this re-exports from the shared layer.
|
|
3
|
+
export function useDirectusForm(..._args) {
|
|
4
|
+
return {
|
|
5
|
+
data: null,
|
|
6
|
+
save: async () => {
|
|
7
|
+
throw new Error('useDirectusForm stub - not available in isolated build');
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { defineAlternateModule, useAlternateEventBus } from '@meeovi/core';
|
|
2
|
+
import { getListsConfig } from './config';
|
|
3
|
+
import { registerListsProviderRuntime } from './registry';
|
|
4
|
+
export default defineAlternateModule({
|
|
5
|
+
id: 'lists',
|
|
6
|
+
adapters: {},
|
|
7
|
+
async setup(ctx) {
|
|
8
|
+
const bus = useAlternateEventBus();
|
|
9
|
+
const config = getListsConfig();
|
|
10
|
+
// If a core adapter was registered under the `lists` key, register it
|
|
11
|
+
// into the local provider registry so UI code can consume it via `useLists()`.
|
|
12
|
+
// If a core adapter was registered under the `lists` key, adapt it
|
|
13
|
+
// into the `ListsProvider` shape and register it into the local registry.
|
|
14
|
+
try {
|
|
15
|
+
const runtimeAdapter = ctx.getAdapter('lists');
|
|
16
|
+
if (runtimeAdapter) {
|
|
17
|
+
const provider = {
|
|
18
|
+
getList: (id) => runtimeAdapter.getList(id),
|
|
19
|
+
listLists: (params) => runtimeAdapter.listLists(params),
|
|
20
|
+
createList: (data) => runtimeAdapter.createList(data),
|
|
21
|
+
updateList: (id, data) => runtimeAdapter.updateList(id, data),
|
|
22
|
+
deleteList: (id) => runtimeAdapter.deleteList(id),
|
|
23
|
+
addItem: (listId, item) => runtimeAdapter.addItem(listId, item),
|
|
24
|
+
updateItem: (listId, itemId, data) => runtimeAdapter.updateItem(listId, itemId, data),
|
|
25
|
+
deleteItem: (listId, itemId) => runtimeAdapter.deleteItem(listId, itemId),
|
|
26
|
+
reorderItems: runtimeAdapter.reorderItems ? (listId, itemIds) => runtimeAdapter.reorderItems(listId, itemIds) : undefined
|
|
27
|
+
};
|
|
28
|
+
registerListsProviderRuntime('core', provider);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
// noop
|
|
33
|
+
}
|
|
34
|
+
// Listen for runtime adapter registrations from ModuleRegistry
|
|
35
|
+
bus.on('adapter:registered', (payload) => {
|
|
36
|
+
try {
|
|
37
|
+
if (payload?.key === 'lists') {
|
|
38
|
+
const runtimeAdapter = ctx.getAdapter('lists');
|
|
39
|
+
if (runtimeAdapter) {
|
|
40
|
+
const provider = {
|
|
41
|
+
getList: (id) => runtimeAdapter.getList(id),
|
|
42
|
+
listLists: (params) => runtimeAdapter.listLists(params),
|
|
43
|
+
createList: (data) => runtimeAdapter.createList(data),
|
|
44
|
+
updateList: (id, data) => runtimeAdapter.updateList(id, data),
|
|
45
|
+
deleteList: (id) => runtimeAdapter.deleteList(id),
|
|
46
|
+
addItem: (listId, item) => runtimeAdapter.addItem(listId, item),
|
|
47
|
+
updateItem: (listId, itemId, data) => runtimeAdapter.updateItem(listId, itemId, data),
|
|
48
|
+
deleteItem: (listId, itemId) => runtimeAdapter.deleteItem(listId, itemId),
|
|
49
|
+
reorderItems: runtimeAdapter.reorderItems ? (listId, itemIds) => runtimeAdapter.reorderItems(listId, itemIds) : undefined
|
|
50
|
+
};
|
|
51
|
+
registerListsProviderRuntime('core', provider);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
/* noop */
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|