@htlkg/data 0.0.14 → 0.0.15
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/dist/hooks/index.d.ts +75 -2
- package/dist/hooks/index.js +220 -3
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +224 -3
- package/dist/index.js.map +1 -1
- package/dist/mutations/index.d.ts +1 -0
- package/dist/mutations/index.js +152 -0
- package/dist/mutations/index.js.map +1 -1
- package/dist/productInstances-CzT3NZKU.d.ts +98 -0
- package/package.json +2 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useProductInstances.ts +174 -0
- package/src/mutations/index.ts +10 -0
- package/src/mutations/productInstances/index.ts +14 -0
- package/src/mutations/productInstances/productInstances.integration.test.ts +621 -0
- package/src/mutations/productInstances/productInstances.test.ts +680 -0
- package/src/mutations/productInstances/productInstances.ts +280 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProductInstance Mutation Functions
|
|
3
|
+
*
|
|
4
|
+
* Provides mutation functions for creating, updating, and deleting product instances.
|
|
5
|
+
* Product instances represent enabled products for a specific brand with their configuration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ProductInstance } from "@htlkg/core/types";
|
|
9
|
+
import { getClientUser } from "@htlkg/core/auth";
|
|
10
|
+
import { getCurrentTimestamp } from "@htlkg/core/utils";
|
|
11
|
+
import { AppError } from "@htlkg/core/errors";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get current user identifier for audit trails
|
|
15
|
+
* Uses getClientUser() and returns email or username, falling back to "system"
|
|
16
|
+
*/
|
|
17
|
+
async function getUserIdentifier(fallback = "system"): Promise<string> {
|
|
18
|
+
try {
|
|
19
|
+
const user = await getClientUser();
|
|
20
|
+
if (user) {
|
|
21
|
+
return user.email || user.username || fallback;
|
|
22
|
+
}
|
|
23
|
+
return fallback;
|
|
24
|
+
} catch {
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Input type for creating a product instance
|
|
31
|
+
*/
|
|
32
|
+
export interface CreateProductInstanceInput {
|
|
33
|
+
productId: string;
|
|
34
|
+
brandId: string;
|
|
35
|
+
accountId: string;
|
|
36
|
+
productName: string;
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
config?: Record<string, any>;
|
|
39
|
+
version?: string;
|
|
40
|
+
lastUpdated?: string;
|
|
41
|
+
updatedBy?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Input type for updating a product instance
|
|
46
|
+
*/
|
|
47
|
+
export interface UpdateProductInstanceInput {
|
|
48
|
+
id: string;
|
|
49
|
+
enabled?: boolean;
|
|
50
|
+
config?: Record<string, any>;
|
|
51
|
+
version?: string;
|
|
52
|
+
lastUpdated?: string;
|
|
53
|
+
updatedBy?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create a new product instance
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* import { createProductInstance } from '@htlkg/data/mutations';
|
|
62
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
63
|
+
*
|
|
64
|
+
* const client = generateClient<Schema>();
|
|
65
|
+
* const instance = await createProductInstance(client, {
|
|
66
|
+
* productId: 'product-123',
|
|
67
|
+
* brandId: 'brand-456',
|
|
68
|
+
* accountId: 'account-789',
|
|
69
|
+
* enabled: true,
|
|
70
|
+
* config: { apiKey: 'xxx', maxRequests: 100 }
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export async function createProductInstance<TClient = any>(
|
|
75
|
+
client: TClient,
|
|
76
|
+
input: CreateProductInstanceInput,
|
|
77
|
+
): Promise<ProductInstance | null> {
|
|
78
|
+
try {
|
|
79
|
+
// Build input - manually construct to avoid Vue Proxy issues
|
|
80
|
+
const createInput: any = {
|
|
81
|
+
productId: input.productId,
|
|
82
|
+
productName: input.productName,
|
|
83
|
+
brandId: input.brandId,
|
|
84
|
+
accountId: input.accountId,
|
|
85
|
+
enabled: input.enabled,
|
|
86
|
+
version: input.version,
|
|
87
|
+
lastUpdated: input.lastUpdated || getCurrentTimestamp(),
|
|
88
|
+
updatedBy: input.updatedBy || await getUserIdentifier(),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// AWSJSON type requires JSON STRING
|
|
92
|
+
if (input.config) {
|
|
93
|
+
// Double stringify: first to strip Vue Proxy, second to create JSON string
|
|
94
|
+
createInput.config = JSON.stringify(JSON.parse(JSON.stringify(input.config)));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log("[createProductInstance] Config as string:", createInput.config);
|
|
98
|
+
console.log("[createProductInstance] Config type:", typeof createInput.config);
|
|
99
|
+
|
|
100
|
+
const { data, errors } = await (client as any).models.ProductInstance.create(createInput);
|
|
101
|
+
|
|
102
|
+
if (errors) {
|
|
103
|
+
console.error("[createProductInstance] GraphQL errors:", errors);
|
|
104
|
+
throw new AppError(
|
|
105
|
+
"Failed to create product instance",
|
|
106
|
+
"PRODUCT_INSTANCE_CREATE_ERROR",
|
|
107
|
+
500,
|
|
108
|
+
{ errors }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return data as ProductInstance;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error("[createProductInstance] Error creating product instance:", error);
|
|
115
|
+
if (error instanceof AppError) {
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
throw new AppError(
|
|
119
|
+
"Failed to create product instance",
|
|
120
|
+
"PRODUCT_INSTANCE_CREATE_ERROR",
|
|
121
|
+
500,
|
|
122
|
+
{ originalError: error }
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Update an existing product instance
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* import { updateProductInstance } from '@htlkg/data/mutations';
|
|
133
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
134
|
+
*
|
|
135
|
+
* const client = generateClient<Schema>();
|
|
136
|
+
* const instance = await updateProductInstance(client, {
|
|
137
|
+
* id: 'instance-123',
|
|
138
|
+
* enabled: false,
|
|
139
|
+
* config: { apiKey: 'new-key', maxRequests: 200 }
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export async function updateProductInstance<TClient = any>(
|
|
144
|
+
client: TClient,
|
|
145
|
+
input: UpdateProductInstanceInput,
|
|
146
|
+
): Promise<ProductInstance | null> {
|
|
147
|
+
try {
|
|
148
|
+
// Add timestamp and user metadata if not provided
|
|
149
|
+
// Convert config from Vue Proxy to plain object
|
|
150
|
+
const updateInput: any = {
|
|
151
|
+
...input,
|
|
152
|
+
lastUpdated: input.lastUpdated || getCurrentTimestamp(),
|
|
153
|
+
updatedBy: input.updatedBy || await getUserIdentifier(),
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// AWSJSON type requires JSON STRING
|
|
157
|
+
if (input.config) {
|
|
158
|
+
updateInput.config = JSON.stringify(JSON.parse(JSON.stringify(input.config)));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { data, errors } = await (client as any).models.ProductInstance.update(updateInput);
|
|
162
|
+
|
|
163
|
+
if (errors) {
|
|
164
|
+
console.error("[updateProductInstance] GraphQL errors:", errors);
|
|
165
|
+
throw new AppError(
|
|
166
|
+
"Failed to update product instance",
|
|
167
|
+
"PRODUCT_INSTANCE_UPDATE_ERROR",
|
|
168
|
+
500,
|
|
169
|
+
{ errors }
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return data as ProductInstance;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.error("[updateProductInstance] Error updating product instance:", error);
|
|
176
|
+
if (error instanceof AppError) {
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
throw new AppError(
|
|
180
|
+
"Failed to update product instance",
|
|
181
|
+
"PRODUCT_INSTANCE_UPDATE_ERROR",
|
|
182
|
+
500,
|
|
183
|
+
{ originalError: error }
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Delete a product instance
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* import { deleteProductInstance } from '@htlkg/data/mutations';
|
|
194
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
195
|
+
*
|
|
196
|
+
* const client = generateClient<Schema>();
|
|
197
|
+
* await deleteProductInstance(client, 'instance-123');
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
export async function deleteProductInstance<TClient = any>(
|
|
201
|
+
client: TClient,
|
|
202
|
+
id: string,
|
|
203
|
+
): Promise<boolean> {
|
|
204
|
+
try {
|
|
205
|
+
const { errors } = await (client as any).models.ProductInstance.delete({ id });
|
|
206
|
+
|
|
207
|
+
if (errors) {
|
|
208
|
+
console.error("[deleteProductInstance] GraphQL errors:", errors);
|
|
209
|
+
throw new AppError(
|
|
210
|
+
"Failed to delete product instance",
|
|
211
|
+
"PRODUCT_INSTANCE_DELETE_ERROR",
|
|
212
|
+
500,
|
|
213
|
+
{ errors }
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return true;
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error("[deleteProductInstance] Error deleting product instance:", error);
|
|
220
|
+
if (error instanceof AppError) {
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
throw new AppError(
|
|
224
|
+
"Failed to delete product instance",
|
|
225
|
+
"PRODUCT_INSTANCE_DELETE_ERROR",
|
|
226
|
+
500,
|
|
227
|
+
{ originalError: error }
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Toggle the enabled status of a product instance
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```typescript
|
|
237
|
+
* import { toggleProductInstanceEnabled } from '@htlkg/data/mutations';
|
|
238
|
+
* import { generateClient } from '@htlkg/data/client';
|
|
239
|
+
*
|
|
240
|
+
* const client = generateClient<Schema>();
|
|
241
|
+
* const instance = await toggleProductInstanceEnabled(client, 'instance-123', true);
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
export async function toggleProductInstanceEnabled<TClient = any>(
|
|
245
|
+
client: TClient,
|
|
246
|
+
id: string,
|
|
247
|
+
enabled: boolean,
|
|
248
|
+
): Promise<ProductInstance | null> {
|
|
249
|
+
try {
|
|
250
|
+
const { data, errors } = await (client as any).models.ProductInstance.update({
|
|
251
|
+
id,
|
|
252
|
+
enabled,
|
|
253
|
+
lastUpdated: getCurrentTimestamp(),
|
|
254
|
+
updatedBy: await getUserIdentifier(),
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (errors) {
|
|
258
|
+
console.error("[toggleProductInstanceEnabled] GraphQL errors:", errors);
|
|
259
|
+
throw new AppError(
|
|
260
|
+
"Failed to toggle product instance",
|
|
261
|
+
"PRODUCT_INSTANCE_TOGGLE_ERROR",
|
|
262
|
+
500,
|
|
263
|
+
{ errors }
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return data as ProductInstance;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error("[toggleProductInstanceEnabled] Error toggling product instance:", error);
|
|
270
|
+
if (error instanceof AppError) {
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
throw new AppError(
|
|
274
|
+
"Failed to toggle product instance",
|
|
275
|
+
"PRODUCT_INSTANCE_TOGGLE_ERROR",
|
|
276
|
+
500,
|
|
277
|
+
{ originalError: error }
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
}
|