@htlkg/data 0.0.1 → 0.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 +53 -0
- package/dist/client/index.d.ts +117 -31
- package/dist/client/index.js +74 -22
- package/dist/client/index.js.map +1 -1
- package/dist/content-collections/index.js +20 -24
- package/dist/content-collections/index.js.map +1 -1
- package/dist/hooks/index.d.ts +113 -5
- package/dist/hooks/index.js +165 -182
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +305 -182
- package/dist/index.js.map +1 -1
- package/dist/queries/index.d.ts +78 -1
- package/dist/queries/index.js +47 -0
- package/dist/queries/index.js.map +1 -1
- package/dist/stores/index.d.ts +106 -0
- package/dist/stores/index.js +108 -0
- package/dist/stores/index.js.map +1 -0
- package/package.json +60 -37
- package/src/client/__tests__/server.test.ts +100 -0
- package/src/client/client.md +91 -0
- package/src/client/index.test.ts +232 -0
- package/src/client/index.ts +145 -0
- package/src/client/server.ts +118 -0
- package/src/content-collections/content-collections.md +87 -0
- package/src/content-collections/generator.ts +314 -0
- package/src/content-collections/index.ts +32 -0
- package/src/content-collections/schemas.ts +75 -0
- package/src/content-collections/sync.ts +139 -0
- package/src/hooks/README.md +293 -0
- package/src/hooks/createDataHook.ts +208 -0
- package/src/hooks/data-hook-errors.property.test.ts +270 -0
- package/src/hooks/data-hook-filters.property.test.ts +263 -0
- package/src/hooks/data-hooks.property.test.ts +190 -0
- package/src/hooks/hooks.test.ts +76 -0
- package/src/hooks/index.ts +21 -0
- package/src/hooks/useAccounts.ts +66 -0
- package/src/hooks/useBrands.ts +95 -0
- package/src/hooks/useProducts.ts +88 -0
- package/src/hooks/useUsers.ts +89 -0
- package/src/index.ts +32 -0
- package/src/mutations/accounts.ts +127 -0
- package/src/mutations/brands.ts +133 -0
- package/src/mutations/index.ts +32 -0
- package/src/mutations/mutations.md +96 -0
- package/src/mutations/users.ts +136 -0
- package/src/queries/accounts.ts +121 -0
- package/src/queries/brands.ts +176 -0
- package/src/queries/index.ts +45 -0
- package/src/queries/products.ts +282 -0
- package/src/queries/queries.md +88 -0
- package/src/queries/server-helpers.ts +114 -0
- package/src/queries/users.ts +199 -0
- package/src/stores/createStores.ts +148 -0
- package/src/stores/index.ts +15 -0
- package/src/stores/stores.md +104 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Query Functions
|
|
3
|
+
*
|
|
4
|
+
* Provides query functions for fetching user data from the GraphQL API.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { User } from "@htlkg/core/types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get a single user by ID
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { getUser } from '@htlkg/data/queries';
|
|
15
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
16
|
+
*
|
|
17
|
+
* const client = generateClient<Schema>();
|
|
18
|
+
* const user = await getUser(client, 'user-123');
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export async function getUser<TClient = any>(
|
|
22
|
+
client: TClient,
|
|
23
|
+
id: string,
|
|
24
|
+
): Promise<User | null> {
|
|
25
|
+
try {
|
|
26
|
+
const { data, errors } = await (client as any).models.User.get({ id });
|
|
27
|
+
|
|
28
|
+
if (errors) {
|
|
29
|
+
console.error("[getUser] GraphQL errors:", errors);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return data as User;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("[getUser] Error fetching user:", error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get a user by Cognito ID
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import { getUserByCognitoId } from '@htlkg/data/queries';
|
|
46
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
47
|
+
*
|
|
48
|
+
* const client = generateClient<Schema>();
|
|
49
|
+
* const user = await getUserByCognitoId(client, 'cognito-id-123');
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export async function getUserByCognitoId<TClient = any>(
|
|
53
|
+
client: TClient,
|
|
54
|
+
cognitoId: string,
|
|
55
|
+
): Promise<User | null> {
|
|
56
|
+
try {
|
|
57
|
+
const { data, errors } = await (client as any).models.User.list({
|
|
58
|
+
filter: { cognitoId: { eq: cognitoId } },
|
|
59
|
+
limit: 1,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (errors) {
|
|
63
|
+
console.error("[getUserByCognitoId] GraphQL errors:", errors);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return data?.[0] as User | null;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error("[getUserByCognitoId] Error fetching user:", error);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get a user by email
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* import { getUserByEmail } from '@htlkg/data/queries';
|
|
80
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
81
|
+
*
|
|
82
|
+
* const client = generateClient<Schema>();
|
|
83
|
+
* const user = await getUserByEmail(client, 'user@example.com');
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export async function getUserByEmail<TClient = any>(
|
|
87
|
+
client: TClient,
|
|
88
|
+
email: string,
|
|
89
|
+
): Promise<User | null> {
|
|
90
|
+
try {
|
|
91
|
+
const { data, errors } = await (client as any).models.User.list({
|
|
92
|
+
filter: { email: { eq: email } },
|
|
93
|
+
limit: 1,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (errors) {
|
|
97
|
+
console.error("[getUserByEmail] GraphQL errors:", errors);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return data?.[0] as User | null;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error("[getUserByEmail] Error fetching user:", error);
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* List all users with optional filtering
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* import { listUsers } from '@htlkg/data/queries';
|
|
114
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
115
|
+
*
|
|
116
|
+
* const client = generateClient<Schema>();
|
|
117
|
+
* const users = await listUsers(client, {
|
|
118
|
+
* filter: { status: { eq: 'active' } }
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export async function listUsers<TClient = any>(
|
|
123
|
+
client: TClient,
|
|
124
|
+
options?: {
|
|
125
|
+
filter?: any;
|
|
126
|
+
limit?: number;
|
|
127
|
+
nextToken?: string;
|
|
128
|
+
},
|
|
129
|
+
): Promise<{ items: User[]; nextToken?: string }> {
|
|
130
|
+
try {
|
|
131
|
+
const { data, errors, nextToken } = await (client as any).models.User.list(
|
|
132
|
+
options,
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (errors) {
|
|
136
|
+
console.error("[listUsers] GraphQL errors:", errors);
|
|
137
|
+
return { items: [], nextToken: undefined };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
items: (data || []) as User[],
|
|
142
|
+
nextToken,
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error("[listUsers] Error fetching users:", error);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* List users by account ID
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* import { listUsersByAccount } from '@htlkg/data/queries';
|
|
156
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
157
|
+
*
|
|
158
|
+
* const client = generateClient<Schema>();
|
|
159
|
+
* const users = await listUsersByAccount(client, 'account-123');
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export async function listUsersByAccount<TClient = any>(
|
|
163
|
+
client: TClient,
|
|
164
|
+
accountId: string,
|
|
165
|
+
options?: {
|
|
166
|
+
limit?: number;
|
|
167
|
+
nextToken?: string;
|
|
168
|
+
},
|
|
169
|
+
): Promise<{ items: User[]; nextToken?: string }> {
|
|
170
|
+
return listUsers(client, {
|
|
171
|
+
filter: { accountId: { eq: accountId } },
|
|
172
|
+
...options,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* List active users
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* import { listActiveUsers } from '@htlkg/data/queries';
|
|
182
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
183
|
+
*
|
|
184
|
+
* const client = generateClient<Schema>();
|
|
185
|
+
* const users = await listActiveUsers(client);
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export async function listActiveUsers<TClient = any>(
|
|
189
|
+
client: TClient,
|
|
190
|
+
options?: {
|
|
191
|
+
limit?: number;
|
|
192
|
+
nextToken?: string;
|
|
193
|
+
},
|
|
194
|
+
): Promise<{ items: User[]; nextToken?: string }> {
|
|
195
|
+
return listUsers(client, {
|
|
196
|
+
filter: { status: { eq: "active" } },
|
|
197
|
+
...options,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates request-scoped nanostores for sharing data across Vue islands
|
|
5
|
+
* without props. Works with @inox-tools/request-nanostores for Astro integration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { atom, type WritableAtom } from "nanostores";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Type for the shared function from @it-astro:request-nanostores
|
|
12
|
+
*/
|
|
13
|
+
type SharedFn = <T>(key: string, atomFactory: WritableAtom<T>) => WritableAtom<T>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for a resource store
|
|
17
|
+
*/
|
|
18
|
+
export interface StoreConfig {
|
|
19
|
+
/** Resource name (e.g., 'accounts', 'users') */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Related resources to create stores for (e.g., ['brands', 'products']) */
|
|
22
|
+
relations?: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Result type for created stores
|
|
27
|
+
*/
|
|
28
|
+
export type ResourceStores<T, TRelations extends string = never> = {
|
|
29
|
+
/** Main resource store */
|
|
30
|
+
$data: WritableAtom<readonly T[]>;
|
|
31
|
+
} & {
|
|
32
|
+
[K in TRelations as `$${K}`]: WritableAtom<readonly any[]>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Capitalize first letter of a string
|
|
37
|
+
*/
|
|
38
|
+
function capitalize(str: string): string {
|
|
39
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Creates request-scoped stores for a resource and its relations.
|
|
44
|
+
*
|
|
45
|
+
* This factory is designed to work with Astro's request-nanostores integration,
|
|
46
|
+
* providing request-isolated state that syncs from server to client.
|
|
47
|
+
*
|
|
48
|
+
* @param shared - The shared function from @it-astro:request-nanostores
|
|
49
|
+
* @param config - Store configuration
|
|
50
|
+
* @returns Object containing the main store and relation stores
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* // In your store file (e.g., stores/accounts.ts)
|
|
55
|
+
* import { shared } from '@it-astro:request-nanostores';
|
|
56
|
+
* import { createResourceStores } from '@htlkg/data/stores';
|
|
57
|
+
*
|
|
58
|
+
* export const accountStores = createResourceStores(shared, {
|
|
59
|
+
* name: 'accounts',
|
|
60
|
+
* relations: ['brands'],
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* // This creates:
|
|
64
|
+
* // - accountStores.$data (WritableAtom<any[]>) - main accounts store
|
|
65
|
+
* // - accountStores.$brands (WritableAtom<any[]>) - related brands store
|
|
66
|
+
*
|
|
67
|
+
* // For cleaner exports:
|
|
68
|
+
* export const $accounts = accountStores.$data;
|
|
69
|
+
* export const $accountsBrands = accountStores.$brands;
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // With typed stores
|
|
75
|
+
* interface Account { id: number; name: string; }
|
|
76
|
+
* interface Brand { id: number; name: string; }
|
|
77
|
+
*
|
|
78
|
+
* export const { $data: $accounts, $brands } = createResourceStores<Account, 'brands'>(
|
|
79
|
+
* shared,
|
|
80
|
+
* { name: 'accounts', relations: ['brands'] }
|
|
81
|
+
* );
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export function createResourceStores<T = any, TRelations extends string = never>(
|
|
85
|
+
shared: SharedFn,
|
|
86
|
+
config: StoreConfig & { relations?: TRelations[] },
|
|
87
|
+
): ResourceStores<T, TRelations> {
|
|
88
|
+
const { name, relations = [] } = config;
|
|
89
|
+
|
|
90
|
+
const stores: Record<string, any> = {};
|
|
91
|
+
|
|
92
|
+
// Main resource store
|
|
93
|
+
stores.$data = shared(name, atom<T[]>([]));
|
|
94
|
+
|
|
95
|
+
// Relation stores
|
|
96
|
+
for (const relation of relations) {
|
|
97
|
+
const storeKey = `$${relation}`;
|
|
98
|
+
const sharedKey = `${name}${capitalize(relation)}`;
|
|
99
|
+
stores[storeKey] = shared(sharedKey, atom<any[]>([]));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return stores as ResourceStores<T, TRelations>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Creates a simple single store (non-factory version for simpler use cases)
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* import { shared } from '@it-astro:request-nanostores';
|
|
111
|
+
* import { createStore } from '@htlkg/data/stores';
|
|
112
|
+
*
|
|
113
|
+
* export const $currentUser = createStore<User>(shared, 'currentUser');
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export function createStore<T>(
|
|
117
|
+
shared: SharedFn,
|
|
118
|
+
name: string,
|
|
119
|
+
defaultValue: T[] = [],
|
|
120
|
+
): WritableAtom<readonly T[]> {
|
|
121
|
+
return shared(name, atom<T[]>(defaultValue));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Creates a single-value store (for non-array values like current user)
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* import { shared } from '@it-astro:request-nanostores';
|
|
130
|
+
* import { createSingleStore } from '@htlkg/data/stores';
|
|
131
|
+
*
|
|
132
|
+
* export const $currentUser = createSingleStore<User | null>(shared, 'currentUser', null);
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function createSingleStore<T>(
|
|
136
|
+
shared: SharedFn,
|
|
137
|
+
name: string,
|
|
138
|
+
defaultValue: T,
|
|
139
|
+
): WritableAtom<T> {
|
|
140
|
+
return shared(name, atom<T>(defaultValue));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Helper to create typed store with proper inference
|
|
145
|
+
*/
|
|
146
|
+
export type InferStoreType<TStore extends WritableAtom<any>> = TStore extends WritableAtom<infer T>
|
|
147
|
+
? T
|
|
148
|
+
: never;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store Factories for @htlkg/data
|
|
3
|
+
*
|
|
4
|
+
* Utilities for creating request-scoped nanostores that work with Astro's
|
|
5
|
+
* server-client state synchronization.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
createResourceStores,
|
|
10
|
+
createStore,
|
|
11
|
+
createSingleStore,
|
|
12
|
+
type StoreConfig,
|
|
13
|
+
type ResourceStores,
|
|
14
|
+
type InferStoreType,
|
|
15
|
+
} from "./createStores";
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Stores Module
|
|
2
|
+
|
|
3
|
+
Nanostore factories for request-scoped state management in Astro SSR.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import {
|
|
9
|
+
createResourceStores,
|
|
10
|
+
createStore,
|
|
11
|
+
createSingleStore,
|
|
12
|
+
} from '@htlkg/data/stores';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## createResourceStores
|
|
16
|
+
|
|
17
|
+
Create a set of stores for a resource type with list and single-item stores.
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { createResourceStores } from '@htlkg/data/stores';
|
|
21
|
+
import type { Brand } from '@htlkg/core/types';
|
|
22
|
+
|
|
23
|
+
const brandStores = createResourceStores<Brand>('brands');
|
|
24
|
+
|
|
25
|
+
// List store
|
|
26
|
+
brandStores.list.set([brand1, brand2]);
|
|
27
|
+
const brands = brandStores.list.get();
|
|
28
|
+
|
|
29
|
+
// Single item store
|
|
30
|
+
brandStores.current.set(selectedBrand);
|
|
31
|
+
const current = brandStores.current.get();
|
|
32
|
+
|
|
33
|
+
// Loading state
|
|
34
|
+
brandStores.loading.set(true);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## createStore
|
|
38
|
+
|
|
39
|
+
Create a simple list store.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { createStore } from '@htlkg/data/stores';
|
|
43
|
+
|
|
44
|
+
const accountsStore = createStore<Account[]>('accounts', []);
|
|
45
|
+
|
|
46
|
+
accountsStore.set(accounts);
|
|
47
|
+
const value = accountsStore.get();
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## createSingleStore
|
|
51
|
+
|
|
52
|
+
Create a store for a single item (nullable).
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { createSingleStore } from '@htlkg/data/stores';
|
|
56
|
+
|
|
57
|
+
const currentUserStore = createSingleStore<User>('currentUser');
|
|
58
|
+
|
|
59
|
+
currentUserStore.set(user);
|
|
60
|
+
const user = currentUserStore.get(); // User | null
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Astro SSR Integration
|
|
64
|
+
|
|
65
|
+
Stores work with Astro's server-client state sync:
|
|
66
|
+
|
|
67
|
+
```astro
|
|
68
|
+
---
|
|
69
|
+
// Server-side: populate store
|
|
70
|
+
import { brandStores } from '@/stores';
|
|
71
|
+
import { fetchBrands } from '@htlkg/data/queries';
|
|
72
|
+
|
|
73
|
+
const brands = await fetchBrands(client, { accountId });
|
|
74
|
+
brandStores.list.set(brands);
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
<BrandList client:load />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```vue
|
|
81
|
+
<!-- Client-side: read from store -->
|
|
82
|
+
<script setup>
|
|
83
|
+
import { useStore } from '@nanostores/vue';
|
|
84
|
+
import { brandStores } from '@/stores';
|
|
85
|
+
|
|
86
|
+
const brands = useStore(brandStores.list);
|
|
87
|
+
</script>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Types
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
interface StoreConfig<T> {
|
|
94
|
+
name: string;
|
|
95
|
+
initial?: T;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
interface ResourceStores<T> {
|
|
99
|
+
list: WritableAtom<T[]>;
|
|
100
|
+
current: WritableAtom<T | null>;
|
|
101
|
+
loading: WritableAtom<boolean>;
|
|
102
|
+
error: WritableAtom<Error | null>;
|
|
103
|
+
}
|
|
104
|
+
```
|