@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.
Files changed (134) hide show
  1. package/README.md +111 -0
  2. package/app/composables/config.ts +1 -1
  3. package/app/composables/module.ts +75 -0
  4. package/app/composables/providers/directus.ts +112 -16
  5. package/app/composables/providers/memory.ts +39 -0
  6. package/app/composables/registry.ts +5 -0
  7. package/app/composables/types.ts +9 -0
  8. package/app/composables/utils/health.ts +16 -0
  9. package/dist/app/composables/config.d.ts +7 -0
  10. package/dist/app/composables/config.js +9 -0
  11. package/dist/app/composables/globals/useDirectusForm.d.ts +4 -0
  12. package/dist/app/composables/globals/useDirectusForm.js +10 -0
  13. package/dist/app/composables/module.d.ts +7 -0
  14. package/dist/app/composables/module.js +60 -0
  15. package/dist/app/composables/providers/atproto.d.ts +1 -0
  16. package/dist/app/composables/providers/atproto.js +133 -0
  17. package/dist/app/composables/providers/directus.d.ts +1 -0
  18. package/dist/app/composables/providers/directus.js +130 -0
  19. package/dist/app/composables/providers/memory.d.ts +1 -0
  20. package/dist/app/composables/providers/memory.js +110 -0
  21. package/dist/app/composables/registry.d.ts +4 -0
  22. package/dist/app/composables/registry.js +14 -0
  23. package/dist/app/composables/types.d.ts +38 -0
  24. package/dist/app/composables/types.js +1 -0
  25. package/dist/app/composables/useLists.d.ts +11 -0
  26. package/dist/app/composables/useLists.js +17 -0
  27. package/dist/app/composables/utils/health.d.ts +10 -0
  28. package/dist/app/composables/utils/health.js +15 -0
  29. package/dist/app/composables/utils/transforms.d.ts +13 -0
  30. package/dist/app/composables/utils/transforms.js +38 -0
  31. package/dist/app/composables/utils/validation.d.ts +3 -0
  32. package/dist/app/composables/utils/validation.js +16 -0
  33. package/dist/layers/lists/app/composables/config.d.ts +7 -0
  34. package/dist/layers/lists/app/composables/config.js +9 -0
  35. package/dist/layers/lists/app/composables/globals/useDirectusForm.d.ts +1 -0
  36. package/dist/layers/lists/app/composables/globals/useDirectusForm.js +1 -0
  37. package/dist/layers/lists/app/composables/module.d.ts +7 -0
  38. package/dist/layers/lists/app/composables/module.js +60 -0
  39. package/dist/layers/lists/app/composables/providers/atproto.d.ts +1 -0
  40. package/dist/layers/lists/app/composables/providers/atproto.js +133 -0
  41. package/dist/layers/lists/app/composables/providers/directus.d.ts +1 -0
  42. package/dist/layers/lists/app/composables/providers/directus.js +130 -0
  43. package/dist/layers/lists/app/composables/providers/memory.d.ts +1 -0
  44. package/dist/layers/lists/app/composables/providers/memory.js +110 -0
  45. package/dist/layers/lists/app/composables/registry.d.ts +4 -0
  46. package/dist/layers/lists/app/composables/registry.js +14 -0
  47. package/dist/layers/lists/app/composables/types.d.ts +38 -0
  48. package/dist/layers/lists/app/composables/types.js +1 -0
  49. package/dist/layers/lists/app/composables/useLists.d.ts +11 -0
  50. package/dist/layers/lists/app/composables/useLists.js +17 -0
  51. package/dist/layers/lists/app/composables/utils/health.d.ts +10 -0
  52. package/dist/layers/lists/app/composables/utils/health.js +15 -0
  53. package/dist/layers/lists/app/composables/utils/transforms.d.ts +13 -0
  54. package/dist/layers/lists/app/composables/utils/transforms.js +38 -0
  55. package/dist/layers/lists/app/composables/utils/validation.d.ts +3 -0
  56. package/dist/layers/lists/app/composables/utils/validation.js +16 -0
  57. package/dist/layers/lists/nuxt.config.d.ts +2 -0
  58. package/dist/layers/lists/nuxt.config.js +7 -0
  59. package/dist/layers/shared/app/composables/globals/useDirectusForm.d.ts +10 -0
  60. package/dist/layers/shared/app/composables/globals/useDirectusForm.js +66 -0
  61. package/dist/lists/app/composables/config.d.ts +7 -0
  62. package/dist/lists/app/composables/config.js +9 -0
  63. package/dist/lists/app/composables/globals/useDirectusForm.d.ts +1 -0
  64. package/dist/lists/app/composables/globals/useDirectusForm.js +1 -0
  65. package/dist/lists/app/composables/module.d.ts +7 -0
  66. package/dist/lists/app/composables/module.js +60 -0
  67. package/dist/lists/app/composables/providers/atproto.d.ts +1 -0
  68. package/dist/lists/app/composables/providers/atproto.js +133 -0
  69. package/dist/lists/app/composables/providers/directus.d.ts +1 -0
  70. package/dist/lists/app/composables/providers/directus.js +130 -0
  71. package/dist/lists/app/composables/providers/memory.d.ts +1 -0
  72. package/dist/lists/app/composables/providers/memory.js +110 -0
  73. package/dist/lists/app/composables/registry.d.ts +4 -0
  74. package/dist/lists/app/composables/registry.js +14 -0
  75. package/dist/lists/app/composables/types.d.ts +38 -0
  76. package/dist/lists/app/composables/types.js +1 -0
  77. package/dist/lists/app/composables/useLists.d.ts +11 -0
  78. package/dist/lists/app/composables/useLists.js +17 -0
  79. package/dist/lists/app/composables/utils/health.d.ts +10 -0
  80. package/dist/lists/app/composables/utils/health.js +15 -0
  81. package/dist/lists/app/composables/utils/transforms.d.ts +13 -0
  82. package/dist/lists/app/composables/utils/transforms.js +38 -0
  83. package/dist/lists/app/composables/utils/validation.d.ts +3 -0
  84. package/dist/lists/app/composables/utils/validation.js +16 -0
  85. package/dist/lists/nuxt.config.d.ts +2 -0
  86. package/dist/lists/nuxt.config.js +7 -0
  87. package/dist/nuxt.config.d.ts +2 -0
  88. package/dist/nuxt.config.js +7 -0
  89. package/dist/packages/core/index.d.ts +17 -0
  90. package/dist/packages/core/index.js +18 -0
  91. package/dist/packages/core/src/adapters/auth.d.ts +9 -0
  92. package/dist/packages/core/src/adapters/auth.js +1 -0
  93. package/dist/packages/core/src/adapters/cart.d.ts +22 -0
  94. package/dist/packages/core/src/adapters/cart.js +1 -0
  95. package/dist/packages/core/src/adapters/catalog.d.ts +17 -0
  96. package/dist/packages/core/src/adapters/catalog.js +1 -0
  97. package/dist/packages/core/src/adapters/common.d.ts +9 -0
  98. package/dist/packages/core/src/adapters/common.js +1 -0
  99. package/dist/packages/core/src/adapters/lists.d.ts +17 -0
  100. package/dist/packages/core/src/adapters/lists.js +1 -0
  101. package/dist/packages/core/src/adapters/search.d.ts +21 -0
  102. package/dist/packages/core/src/adapters/search.js +1 -0
  103. package/dist/packages/core/src/plugins/defineAdapter.d.ts +2 -0
  104. package/dist/packages/core/src/plugins/defineAdapter.js +3 -0
  105. package/dist/packages/core/src/plugins/defineModule.d.ts +2 -0
  106. package/dist/packages/core/src/plugins/defineModule.js +3 -0
  107. package/dist/packages/core/src/plugins/registry.d.ts +14 -0
  108. package/dist/packages/core/src/plugins/registry.js +46 -0
  109. package/dist/packages/core/src/runtime/app.d.ts +2 -0
  110. package/dist/packages/core/src/runtime/app.js +20 -0
  111. package/dist/packages/core/src/runtime/config.d.ts +7 -0
  112. package/dist/packages/core/src/runtime/config.js +9 -0
  113. package/dist/packages/core/src/runtime/context.d.ts +9 -0
  114. package/dist/packages/core/src/runtime/context.js +11 -0
  115. package/dist/packages/core/src/runtime/hooks.d.ts +5 -0
  116. package/dist/packages/core/src/runtime/hooks.js +18 -0
  117. package/dist/packages/core/src/runtime/lifecycle.d.ts +4 -0
  118. package/dist/packages/core/src/runtime/lifecycle.js +5 -0
  119. package/dist/packages/core/src/types/adapters.d.ts +14 -0
  120. package/dist/packages/core/src/types/adapters.js +1 -0
  121. package/dist/packages/core/src/types/app.d.ts +13 -0
  122. package/dist/packages/core/src/types/app.js +1 -0
  123. package/dist/packages/core/src/types/config.d.ts +8 -0
  124. package/dist/packages/core/src/types/config.js +1 -0
  125. package/dist/packages/core/src/types/events.d.ts +20 -0
  126. package/dist/packages/core/src/types/events.js +22 -0
  127. package/dist/packages/core/src/types/module.d.ts +15 -0
  128. package/dist/packages/core/src/types/module.js +1 -0
  129. package/dist/shared/app/composables/globals/useDirectusForm.d.ts +10 -0
  130. package/dist/shared/app/composables/globals/useDirectusForm.js +66 -0
  131. package/global.d.ts +1 -0
  132. package/package.json +4 -1
  133. package/shims.d.ts +7 -0
  134. package/tsconfig.json +21 -0
@@ -0,0 +1,66 @@
1
+ import { ref, provide } from 'vue';
2
+ export function useDirectusForm(collectionName, fieldsRef, opts) {
3
+ const form = ref({});
4
+ const formError = ref(null);
5
+ const formSuccess = ref(null);
6
+ // provide form context for DirectusFormElement children
7
+ provide('directusForm', {
8
+ form,
9
+ fields: fieldsRef,
10
+ });
11
+ const submitForm = async () => {
12
+ formError.value = null;
13
+ formSuccess.value = null;
14
+ // Validate form data against field validation rules
15
+ for (const field of fieldsRef.value) {
16
+ if (field.meta?.validation) {
17
+ try {
18
+ const validation = field.meta.validation;
19
+ if (validation._and) {
20
+ for (const rule of validation._and) {
21
+ const fieldName = Object.keys(rule)[0];
22
+ if (!fieldName)
23
+ continue;
24
+ const ruleDef = rule[fieldName];
25
+ if (ruleDef && ruleDef._regex) {
26
+ const regex = new RegExp(ruleDef._regex);
27
+ const valueToTest = String(form.value[field.field] ?? '');
28
+ if (!regex.test(valueToTest)) {
29
+ formError.value = field.meta.validation_message || field.meta.field + ' failed validation';
30
+ console.error(`Validation failed for ${field.field}: ${field.meta.validation_message || 'Invalid format'}`);
31
+ return; // Stop submission if validation fails
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ catch (err) {
38
+ console.error(`Error parsing validation for ${field.field}:`, err);
39
+ }
40
+ }
41
+ }
42
+ const { $directus, $createItem } = useNuxtApp();
43
+ const result = await $directus.request($createItem(collectionName, form.value));
44
+ if (result.error) {
45
+ formError.value = result.error.message;
46
+ console.error(`Error creating ${collectionName}:`, result.error);
47
+ return; // Stop submission if error occurs
48
+ }
49
+ formSuccess.value = `${collectionName} created successfully`;
50
+ if (opts?.clearOnSuccess) {
51
+ form.value = {};
52
+ }
53
+ if (opts?.closeDialogRef) {
54
+ try {
55
+ opts.closeDialogRef.value = false;
56
+ }
57
+ catch (e) { }
58
+ }
59
+ };
60
+ return {
61
+ form,
62
+ formError,
63
+ formSuccess,
64
+ submitForm,
65
+ };
66
+ }
@@ -0,0 +1,7 @@
1
+ export interface ListsConfig {
2
+ provider: string;
3
+ baseUrl?: string;
4
+ apiKey?: string;
5
+ }
6
+ export declare function setListsConfig(newConfig: Partial<ListsConfig>): void;
7
+ export declare function getListsConfig(): ListsConfig;
@@ -0,0 +1,9 @@
1
+ let config = {
2
+ provider: 'directus'
3
+ };
4
+ export function setListsConfig(newConfig) {
5
+ config = { ...config, ...newConfig };
6
+ }
7
+ export function getListsConfig() {
8
+ return config;
9
+ }
@@ -0,0 +1 @@
1
+ export * from '#shared/app/composables/globals/useDirectusForm';
@@ -0,0 +1 @@
1
+ export * from '#shared/app/composables/globals/useDirectusForm';
@@ -0,0 +1,7 @@
1
+ import { type AlternateContext } from '@meeovi/core';
2
+ declare const _default: {
3
+ id: string;
4
+ adapters: {};
5
+ setup(ctx: AlternateContext): Promise<void>;
6
+ };
7
+ export default _default;
@@ -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 {};
@@ -0,0 +1,133 @@
1
+ import { registerListsProvider } from '../registry';
2
+ import { wrapSocialRequest } from '@meeovi/social';
3
+ import { transformList, transformItem } from '../utils/transforms';
4
+ import { validateListInput, validateItemInput } from '../utils/validation';
5
+ import { getListsConfig } from '../config';
6
+ async function atprotoFetch(path, options = {}) {
7
+ const { baseUrl, apiKey } = getListsConfig();
8
+ const res = await fetch(`${baseUrl}${path}`, {
9
+ ...options,
10
+ headers: {
11
+ 'Content-Type': 'application/json',
12
+ ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
13
+ ...(options.headers || {})
14
+ }
15
+ });
16
+ if (!res.ok) {
17
+ const error = new Error(`ATProto error: ${res.status}`);
18
+ error.status = res.status;
19
+ error.response = res;
20
+ throw error;
21
+ }
22
+ return res.json();
23
+ }
24
+ const AtprotoListsProvider = {
25
+ async getList(id) {
26
+ return wrapSocialRequest('atproto', async () => {
27
+ const data = await atprotoFetch(`/xrpc/app.bsky.graph.getList?list=${id}`);
28
+ return transformList(data.list);
29
+ }, {
30
+ cacheKey: `atproto:list:${id}`,
31
+ ttlMs: 1000 * 30,
32
+ retry: true,
33
+ swr: true
34
+ });
35
+ },
36
+ async listLists() {
37
+ return wrapSocialRequest('atproto', async () => {
38
+ const data = await atprotoFetch(`/xrpc/app.bsky.graph.getLists`);
39
+ return data.lists.map(transformList);
40
+ }, {
41
+ cacheKey: `atproto:lists`,
42
+ ttlMs: 1000 * 30,
43
+ retry: true,
44
+ swr: true
45
+ });
46
+ },
47
+ async createList(data) {
48
+ validateListInput(data);
49
+ return wrapSocialRequest('atproto', async () => {
50
+ const result = await atprotoFetch(`/xrpc/app.bsky.graph.createList`, {
51
+ method: 'POST',
52
+ body: JSON.stringify({
53
+ name: data.title,
54
+ purpose: data.type ?? 'list',
55
+ description: data.metadata?.description ?? ''
56
+ })
57
+ });
58
+ return transformList(result);
59
+ });
60
+ },
61
+ async updateList(id, data) {
62
+ validateListInput(data);
63
+ return wrapSocialRequest('atproto', async () => {
64
+ const result = await atprotoFetch(`/xrpc/app.bsky.graph.updateList`, {
65
+ method: 'POST',
66
+ body: JSON.stringify({
67
+ list: id,
68
+ name: data.title,
69
+ description: data.metadata?.description
70
+ })
71
+ });
72
+ return transformList(result);
73
+ });
74
+ },
75
+ async deleteList(id) {
76
+ return wrapSocialRequest('atproto', async () => {
77
+ await atprotoFetch(`/xrpc/app.bsky.graph.deleteList`, {
78
+ method: 'POST',
79
+ body: JSON.stringify({ list: id })
80
+ });
81
+ });
82
+ },
83
+ async addItem(listId, item) {
84
+ validateItemInput(item);
85
+ return wrapSocialRequest('atproto', async () => {
86
+ const result = await atprotoFetch(`/xrpc/app.bsky.graph.addListItem`, {
87
+ method: 'POST',
88
+ body: JSON.stringify({
89
+ list: listId,
90
+ subject: item.title // ATProto uses "subject" for list entries
91
+ })
92
+ });
93
+ return transformItem(result);
94
+ });
95
+ },
96
+ async updateItem(listId, itemId, data) {
97
+ validateItemInput(data);
98
+ return wrapSocialRequest('atproto', async () => {
99
+ const result = await atprotoFetch(`/xrpc/app.bsky.graph.updateListItem`, {
100
+ method: 'POST',
101
+ body: JSON.stringify({
102
+ list: listId,
103
+ item: itemId,
104
+ ...data
105
+ })
106
+ });
107
+ return transformItem(result);
108
+ });
109
+ },
110
+ async deleteItem(listId, itemId) {
111
+ return wrapSocialRequest('atproto', async () => {
112
+ await atprotoFetch(`/xrpc/app.bsky.graph.deleteListItem`, {
113
+ method: 'POST',
114
+ body: JSON.stringify({
115
+ list: listId,
116
+ item: itemId
117
+ })
118
+ });
119
+ });
120
+ },
121
+ async reorderItems(listId, itemIds) {
122
+ return wrapSocialRequest('atproto', async () => {
123
+ await atprotoFetch(`/xrpc/app.bsky.graph.reorderListItems`, {
124
+ method: 'POST',
125
+ body: JSON.stringify({
126
+ list: listId,
127
+ items: itemIds
128
+ })
129
+ });
130
+ });
131
+ }
132
+ };
133
+ registerListsProvider('atproto', AtprotoListsProvider);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,130 @@
1
+ import { registerListsProvider } from '../registry';
2
+ import { getListsConfig } from '../config';
3
+ async function directusFetch(path, options = {}) {
4
+ const cfg = getListsConfig();
5
+ const base = cfg.baseUrl?.replace(/\/$/, '') || '';
6
+ const res = await fetch(`${base}${path}`, {
7
+ ...options,
8
+ headers: {
9
+ 'Content-Type': 'application/json',
10
+ ...(cfg.apiKey ? { Authorization: `Bearer ${cfg.apiKey}` } : {}),
11
+ ...(options.headers || {})
12
+ }
13
+ });
14
+ if (!res.ok) {
15
+ const err = new Error(`Directus error: ${res.status}`);
16
+ err.status = res.status;
17
+ err.response = res;
18
+ throw err;
19
+ }
20
+ return res.json();
21
+ }
22
+ const DirectusListsProvider = {
23
+ async getList(id) {
24
+ const json = await directusFetch(`/lists/${id}`);
25
+ return json.list ?? json;
26
+ },
27
+ async listLists() {
28
+ const json = await directusFetch(`/lists`);
29
+ return json.lists ?? json;
30
+ },
31
+ async createList(data) {
32
+ const json = await directusFetch(`/lists`, { method: 'POST', body: JSON.stringify(data) });
33
+ return json.list ?? json;
34
+ },
35
+ async updateList(id, data) {
36
+ const json = await directusFetch(`/lists/${id}`, { method: 'PUT', body: JSON.stringify(data) });
37
+ return json.list ?? json;
38
+ },
39
+ async deleteList(id) {
40
+ await directusFetch(`/lists/${id}`, { method: 'DELETE' });
41
+ },
42
+ async addItem(listId, item) {
43
+ const json = await directusFetch(`/lists/${listId}/items`, { method: 'POST', body: JSON.stringify(item) });
44
+ return json.item ?? json;
45
+ },
46
+ async updateItem(listId, itemId, data) {
47
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify(data) });
48
+ return json.item ?? json;
49
+ },
50
+ async deleteItem(listId, itemId) {
51
+ await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'DELETE' });
52
+ },
53
+ async reorderItems(listId, itemIds) {
54
+ await directusFetch(`/lists/${listId}/reorder`, { method: 'POST', body: JSON.stringify({ items: itemIds }) });
55
+ },
56
+ async toggleComplete(listId, itemId, completed = true) {
57
+ try {
58
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}/toggle`, { method: 'POST', body: JSON.stringify({ completed }) });
59
+ return json.item ?? json;
60
+ }
61
+ catch (e) {
62
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ completed }) });
63
+ return json.item ?? json;
64
+ }
65
+ },
66
+ async setDueDate(listId, itemId, dueDate) {
67
+ try {
68
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}/due`, { method: 'POST', body: JSON.stringify({ dueDate }) });
69
+ return json.item ?? json;
70
+ }
71
+ catch (e) {
72
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ metadata: { dueDate } }) });
73
+ return json.item ?? json;
74
+ }
75
+ },
76
+ async setReminder(listId, itemId, reminder) {
77
+ try {
78
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}/reminder`, { method: 'POST', body: JSON.stringify({ reminder }) });
79
+ return json.item ?? json;
80
+ }
81
+ catch (e) {
82
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ metadata: { reminder } }) });
83
+ return json.item ?? json;
84
+ }
85
+ },
86
+ async setPriority(listId, itemId, priority) {
87
+ try {
88
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}/priority`, { method: 'POST', body: JSON.stringify({ priority }) });
89
+ return json.item ?? json;
90
+ }
91
+ catch (e) {
92
+ const json = await directusFetch(`/lists/${listId}/items/${itemId}`, { method: 'PUT', body: JSON.stringify({ metadata: { priority } }) });
93
+ return json.item ?? json;
94
+ }
95
+ },
96
+ async shareList(listId, userId, role = 'editor') {
97
+ try {
98
+ await directusFetch(`/lists/${listId}/share`, { method: 'POST', body: JSON.stringify({ userId, role }) });
99
+ }
100
+ catch (e) {
101
+ const json = await directusFetch(`/lists/${listId}`);
102
+ const list = json.list ?? json;
103
+ const collaborators = (list.metadata?.collaborators || []).concat({ userId, role });
104
+ await directusFetch(`/lists/${listId}`, { method: 'PUT', body: JSON.stringify({ metadata: { ...(list.metadata || {}), collaborators } }) });
105
+ }
106
+ },
107
+ async searchItems(listId, query) {
108
+ try {
109
+ const json = await directusFetch(`/lists/${listId}/search?q=${encodeURIComponent(String(query))}`);
110
+ return json.items ?? json;
111
+ }
112
+ catch (e) {
113
+ const json = await directusFetch(`/lists/${listId}`);
114
+ const list = json.list ?? json;
115
+ const q = String(query).toLowerCase();
116
+ return list.items.filter((i) => (i.title || '').toLowerCase().includes(q) || (i.description || '').toLowerCase().includes(q));
117
+ }
118
+ },
119
+ async archiveList(listId) {
120
+ try {
121
+ await directusFetch(`/lists/${listId}/archive`, { method: 'POST' });
122
+ }
123
+ catch (e) {
124
+ const json = await directusFetch(`/lists/${listId}`);
125
+ const list = json.list ?? json;
126
+ await directusFetch(`/lists/${listId}`, { method: 'PUT', body: JSON.stringify({ metadata: { ...(list.metadata || {}), archived: true } }) });
127
+ }
128
+ }
129
+ };
130
+ registerListsProvider('directus', DirectusListsProvider);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,110 @@
1
+ import { registerListsProvider } from '../registry';
2
+ import { nanoid } from 'nanoid';
3
+ const lists = new Map();
4
+ const MemoryListsProvider = {
5
+ async getList(id) {
6
+ const list = lists.get(id);
7
+ if (!list)
8
+ throw new Error(`List ${id} not found`);
9
+ return list;
10
+ },
11
+ async listLists() {
12
+ return Array.from(lists.values());
13
+ },
14
+ async createList(data) {
15
+ const id = nanoid();
16
+ const list = {
17
+ id,
18
+ title: data.title || 'Untitled List',
19
+ type: data.type || 'list',
20
+ items: [],
21
+ metadata: data.metadata || {},
22
+ createdAt: new Date().toISOString(),
23
+ updatedAt: new Date().toISOString()
24
+ };
25
+ lists.set(id, list);
26
+ return list;
27
+ },
28
+ async updateList(id, data) {
29
+ const list = await this.getList(id);
30
+ const updated = {
31
+ ...list,
32
+ ...data,
33
+ updatedAt: new Date().toISOString()
34
+ };
35
+ lists.set(id, updated);
36
+ return updated;
37
+ },
38
+ async deleteList(id) {
39
+ lists.delete(id);
40
+ },
41
+ async addItem(listId, item) {
42
+ const list = await this.getList(listId);
43
+ const newItem = {
44
+ id: nanoid(),
45
+ title: item.title || '',
46
+ description: item.description,
47
+ completed: item.completed || false,
48
+ position: list.items.length,
49
+ parentId: item.parentId,
50
+ metadata: item.metadata || {},
51
+ createdAt: new Date().toISOString(),
52
+ updatedAt: new Date().toISOString()
53
+ };
54
+ list.items.push(newItem);
55
+ return newItem;
56
+ },
57
+ async updateItem(listId, itemId, data) {
58
+ const list = await this.getList(listId);
59
+ const item = list.items.find(i => i.id === itemId);
60
+ if (!item)
61
+ throw new Error(`Item ${itemId} not found`);
62
+ Object.assign(item, data, { updatedAt: new Date().toISOString() });
63
+ return item;
64
+ },
65
+ async deleteItem(listId, itemId) {
66
+ const list = await this.getList(listId);
67
+ list.items = list.items.filter(i => i.id !== itemId);
68
+ },
69
+ async reorderItems(listId, itemIds) {
70
+ const list = await this.getList(listId);
71
+ const newOrder = itemIds.map(id => list.items.find(i => i.id === id));
72
+ list.items = newOrder.map((item, index) => ({
73
+ ...item,
74
+ position: index
75
+ }));
76
+ },
77
+ async toggleComplete(listId, itemId, completed = true) {
78
+ const item = await this.updateItem(listId, itemId, { completed });
79
+ return item;
80
+ },
81
+ async setDueDate(listId, itemId, dueDate) {
82
+ const item = await this.updateItem(listId, itemId, { metadata: { ...((await this.getList(listId)).items.find(i => i.id === itemId)?.metadata || {}), dueDate } });
83
+ return item;
84
+ },
85
+ async setReminder(listId, itemId, reminder) {
86
+ const item = await this.updateItem(listId, itemId, { metadata: { ...((await this.getList(listId)).items.find(i => i.id === itemId)?.metadata || {}), reminder } });
87
+ return item;
88
+ },
89
+ async setPriority(listId, itemId, priority) {
90
+ const item = await this.updateItem(listId, itemId, { metadata: { ...((await this.getList(listId)).items.find(i => i.id === itemId)?.metadata || {}), priority } });
91
+ return item;
92
+ },
93
+ async shareList(listId, userId, role = 'editor') {
94
+ // memory store: attach collaborators in list.metadata.collaborators
95
+ const list = await this.getList(listId);
96
+ const collaborators = list.metadata?.collaborators || [];
97
+ collaborators.push({ userId, role });
98
+ list.metadata = { ...(list.metadata || {}), collaborators };
99
+ },
100
+ async searchItems(listId, query) {
101
+ const list = await this.getList(listId);
102
+ const q = String(query).toLowerCase();
103
+ return list.items.filter(i => (i.title || '').toLowerCase().includes(q) || (i.description || '').toLowerCase().includes(q));
104
+ },
105
+ async archiveList(listId) {
106
+ const list = await this.getList(listId);
107
+ list.metadata = { ...(list.metadata || {}), archived: true };
108
+ }
109
+ };
110
+ registerListsProvider('memory', MemoryListsProvider);
@@ -0,0 +1,4 @@
1
+ import type { ListsProvider } from './types';
2
+ export declare function registerListsProvider(name: string, provider: ListsProvider): void;
3
+ export declare function registerListsProviderRuntime(name: string, provider: ListsProvider): void;
4
+ export declare function getListsProvider(name: string): ListsProvider;
@@ -0,0 +1,14 @@
1
+ const providers = {};
2
+ export function registerListsProvider(name, provider) {
3
+ providers[name] = provider;
4
+ }
5
+ // Allow runtime registration from other modules (e.g. via core ModuleRegistry adapters)
6
+ export function registerListsProviderRuntime(name, provider) {
7
+ registerListsProvider(name, provider);
8
+ }
9
+ export function getListsProvider(name) {
10
+ const provider = providers[name];
11
+ if (!provider)
12
+ throw new Error(`Lists provider "${name}" not found`);
13
+ return provider;
14
+ }
@@ -0,0 +1,38 @@
1
+ export interface ListItem {
2
+ id: string;
3
+ title: string;
4
+ description?: string;
5
+ completed?: boolean;
6
+ position?: number;
7
+ parentId?: string;
8
+ metadata?: Record<string, any>;
9
+ createdAt?: string;
10
+ updatedAt?: string;
11
+ }
12
+ export interface List {
13
+ id: string;
14
+ title: string;
15
+ type: 'checklist' | 'kanban' | 'list' | string;
16
+ items: ListItem[];
17
+ metadata?: Record<string, any>;
18
+ createdAt?: string;
19
+ updatedAt?: string;
20
+ }
21
+ export interface ListsProvider {
22
+ getList(id: string): Promise<List>;
23
+ listLists(params?: Record<string, any>): Promise<List[]>;
24
+ createList(data: Partial<List>): Promise<List>;
25
+ updateList(id: string, data: Partial<List>): Promise<List>;
26
+ deleteList(id: string): Promise<void>;
27
+ addItem(listId: string, item: Partial<ListItem>): Promise<ListItem>;
28
+ updateItem(listId: string, itemId: string, data: Partial<ListItem>): Promise<ListItem>;
29
+ deleteItem(listId: string, itemId: string): Promise<void>;
30
+ reorderItems?(listId: string, itemIds: string[]): Promise<void>;
31
+ toggleComplete?(listId: string, itemId: string, completed: boolean): Promise<ListItem>;
32
+ setDueDate?(listId: string, itemId: string, dueDate: string | null): Promise<ListItem>;
33
+ setReminder?(listId: string, itemId: string, reminder: string | null): Promise<ListItem>;
34
+ setPriority?(listId: string, itemId: string, priority: number | null): Promise<ListItem>;
35
+ shareList?(listId: string, userId: string, role?: string): Promise<void>;
36
+ searchItems?(listId: string, query: string): Promise<ListItem[]>;
37
+ archiveList?(listId: string): Promise<void>;
38
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ export declare function useLists(): {
2
+ getList: (id: string) => Promise<import("./types").List>;
3
+ listLists: (params?: Record<string, any>) => Promise<import("./types").List[]>;
4
+ createList: (data: Partial<import("./types").List>) => Promise<import("./types").List>;
5
+ updateList: (id: string, data: Partial<import("./types").List>) => Promise<import("./types").List>;
6
+ deleteList: (id: string) => Promise<void>;
7
+ addItem: (listId: string, item: Partial<import("./types").ListItem>) => Promise<import("./types").ListItem>;
8
+ updateItem: (listId: string, itemId: string, data: Partial<import("./types").ListItem>) => Promise<import("./types").ListItem>;
9
+ deleteItem: (listId: string, itemId: string) => Promise<void>;
10
+ reorderItems: ((listId: string, itemIds: string[]) => Promise<void>) | undefined;
11
+ };
@@ -0,0 +1,17 @@
1
+ import { getListsConfig } from './config';
2
+ import { getListsProvider } from './registry';
3
+ export function useLists() {
4
+ const { provider } = getListsConfig();
5
+ const lists = getListsProvider(provider);
6
+ return {
7
+ getList: lists.getList,
8
+ listLists: lists.listLists,
9
+ createList: lists.createList,
10
+ updateList: lists.updateList,
11
+ deleteList: lists.deleteList,
12
+ addItem: lists.addItem,
13
+ updateItem: lists.updateItem,
14
+ deleteItem: lists.deleteItem,
15
+ reorderItems: lists.reorderItems
16
+ };
17
+ }
@@ -0,0 +1,10 @@
1
+ export declare function checkListsProviderHealth(providerName?: string): Promise<{
2
+ ok: boolean;
3
+ count: number | null;
4
+ error?: undefined;
5
+ } | {
6
+ ok: boolean;
7
+ error: any;
8
+ count?: undefined;
9
+ }>;
10
+ export default checkListsProviderHealth;
@@ -0,0 +1,15 @@
1
+ import { getListsProvider } from '../registry';
2
+ import { getListsConfig } from '../config';
3
+ export async function checkListsProviderHealth(providerName) {
4
+ try {
5
+ const cfg = getListsConfig();
6
+ const name = providerName || cfg.provider || 'directus';
7
+ const provider = getListsProvider(name);
8
+ const lists = await provider.listLists();
9
+ return { ok: true, count: Array.isArray(lists) ? lists.length : null };
10
+ }
11
+ catch (e) {
12
+ return { ok: false, error: e?.message || String(e) };
13
+ }
14
+ }
15
+ export default checkListsProviderHealth;