@htlkg/data 0.0.14 → 0.0.16

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 (37) hide show
  1. package/README.md +72 -0
  2. package/dist/client/index.d.ts +123 -30
  3. package/dist/client/index.js +75 -1
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/hooks/index.d.ts +76 -2
  6. package/dist/hooks/index.js +224 -6
  7. package/dist/hooks/index.js.map +1 -1
  8. package/dist/index.d.ts +6 -4
  9. package/dist/index.js +550 -7
  10. package/dist/index.js.map +1 -1
  11. package/dist/mutations/index.d.ts +149 -5
  12. package/dist/mutations/index.js +397 -0
  13. package/dist/mutations/index.js.map +1 -1
  14. package/dist/productInstances-CzT3NZKU.d.ts +98 -0
  15. package/dist/queries/index.d.ts +54 -2
  16. package/dist/queries/index.js +60 -1
  17. package/dist/queries/index.js.map +1 -1
  18. package/dist/server/index.d.ts +47 -0
  19. package/dist/server/index.js +59 -0
  20. package/dist/server/index.js.map +1 -0
  21. package/package.json +5 -1
  22. package/src/client/index.ts +82 -3
  23. package/src/client/proxy.ts +170 -0
  24. package/src/hooks/index.ts +1 -0
  25. package/src/hooks/useProductInstances.ts +174 -0
  26. package/src/index.ts +11 -0
  27. package/src/mutations/accounts.ts +102 -1
  28. package/src/mutations/brands.ts +102 -1
  29. package/src/mutations/index.ts +23 -0
  30. package/src/mutations/productInstances/index.ts +14 -0
  31. package/src/mutations/productInstances/productInstances.integration.test.ts +621 -0
  32. package/src/mutations/productInstances/productInstances.test.ts +680 -0
  33. package/src/mutations/productInstances/productInstances.ts +280 -0
  34. package/src/mutations/systemSettings.ts +130 -0
  35. package/src/mutations/users.ts +102 -1
  36. package/src/queries/index.ts +9 -0
  37. package/src/queries/systemSettings.ts +115 -0
package/README.md CHANGED
@@ -30,6 +30,39 @@ Astro content collection generators and schema definitions.
30
30
 
31
31
  ## Quick Start
32
32
 
33
+ ### Server-Side (Astro Pages) - Zero Config (Recommended)
34
+
35
+ When using `@htlkg/astro` integration, the Amplify client is **automatically injected** into `Astro.locals.amplifyClient` by the auth middleware. No imports, no config needed:
36
+
37
+ ```typescript
38
+ ---
39
+ // In any Astro page (.astro file)
40
+ export const prerender = false;
41
+
42
+ // Just use it - no imports needed for client setup!
43
+ const { amplifyClient } = Astro.locals;
44
+
45
+ // Fetch data directly
46
+ const { data: users } = await amplifyClient.models.User.list({
47
+ selectionSet: ['id', 'email', 'status'],
48
+ authMode: 'userPool',
49
+ });
50
+
51
+ const { data: brands } = await amplifyClient.models.Brand.list();
52
+ ---
53
+
54
+ <ul>
55
+ {users?.map(user => <li>{user.email}</li>)}
56
+ </ul>
57
+ ```
58
+
59
+ **Requirements:**
60
+ - Must use `@htlkg/astro` integration with `vueAppSetup: 'full'`
61
+ - User must be authenticated (client is only available when `Astro.locals.user` exists)
62
+ - Page must have `export const prerender = false` (SSR mode)
63
+
64
+ ### Client-Side (Vue Components)
65
+
33
66
  ```typescript
34
67
  // Client-side data fetching
35
68
  import { getSharedClient } from '@htlkg/data/client';
@@ -51,3 +84,42 @@ import { fetchBrands, fetchAccounts } from '@htlkg/data/queries';
51
84
 
52
85
  const brands = await fetchBrands(client, { accountId });
53
86
  ```
87
+
88
+ ## Migration Guide: From Manual Client to Zero-Config
89
+
90
+ ### Before (Manual Setup)
91
+
92
+ ```typescript
93
+ ---
94
+ import { generateServerClientUsingCookies } from "@htlkg/data/client";
95
+ import { parseAmplifyConfig } from "aws-amplify/utils";
96
+ import type { Schema } from "@backend/data/resource";
97
+ import { amplifyOutputs } from "@/lib/amplify-config";
98
+
99
+ const amplifyConfig = parseAmplifyConfig(amplifyOutputs);
100
+ const client = generateServerClientUsingCookies<Schema>({
101
+ config: amplifyConfig,
102
+ cookies: Astro.cookies,
103
+ request: Astro.request,
104
+ });
105
+
106
+ const { data } = await client.models.User.list();
107
+ ---
108
+ ```
109
+
110
+ ### After (Zero-Config)
111
+
112
+ ```typescript
113
+ ---
114
+ const { amplifyClient } = Astro.locals;
115
+
116
+ const { data } = await amplifyClient.models.User.list();
117
+ ---
118
+ ```
119
+
120
+ **Benefits:**
121
+ - No imports needed for client setup
122
+ - No config parsing
123
+ - No manual parameter passing
124
+ - Type-safe with full IntelliSense support
125
+ - Client is automatically scoped to the authenticated user
@@ -1,57 +1,119 @@
1
1
  import { generateClient as generateClient$1 } from 'aws-amplify/data';
2
2
  import { ResourcesConfig } from 'aws-amplify';
3
- import { AstroGlobal } from 'astro';
4
- import { CommonPublicClientOptions, DefaultCommonClientOptions, V6ClientSSRCookies } from 'aws-amplify/api/internals';
3
+ import { generateServerClientUsingCookies } from '../server/index.js';
4
+ import 'astro';
5
+ import 'aws-amplify/api/internals';
5
6
 
6
7
  /**
7
- * Server-side data client for Astro
8
+ * GraphQL Proxy Client
8
9
  *
9
- * Provides a client generator similar to Next.js's generateServerClientUsingCookies
10
- * using generateClientWithAmplifyInstance for proper server context integration.
10
+ * Client-side helper for making authenticated GraphQL operations through
11
+ * the server-side proxy. This allows Vue components to perform mutations
12
+ * while keeping auth cookies httpOnly for security.
13
+ *
14
+ * @module @htlkg/data/proxy
11
15
  */
12
-
13
- interface AstroCookiesClientParams {
14
- cookies: AstroGlobal["cookies"];
15
- request: AstroGlobal["request"];
16
- config: ResourcesConfig;
16
+ /**
17
+ * Valid GraphQL operations
18
+ */
19
+ type Operation = "create" | "update" | "delete" | "get" | "list";
20
+ /**
21
+ * Response type from GraphQL operations
22
+ */
23
+ interface GraphQLResponse<T = any> {
24
+ data: T | null;
25
+ errors?: Array<{
26
+ message: string;
27
+ [key: string]: any;
28
+ }>;
17
29
  }
18
30
  /**
19
- * Generates a server-side data client for Astro (matches Next.js implementation)
31
+ * Options for proxy requests
32
+ */
33
+ interface ProxyOptions {
34
+ /** Custom API endpoint (default: /api/graphql) */
35
+ endpoint?: string;
36
+ /** Additional fetch options */
37
+ fetchOptions?: RequestInit;
38
+ }
39
+ /**
40
+ * Execute a GraphQL mutation through the server proxy
20
41
  *
21
- * This function creates a client that automatically wraps all operations in the Amplify server context,
22
- * ensuring that authentication tokens from cookies are properly used.
42
+ * @param model - The model name (e.g., 'User', 'Brand', 'Account')
43
+ * @param operation - The operation type ('create', 'update', 'delete')
44
+ * @param data - The operation data/input
45
+ * @param options - Optional configuration
46
+ * @returns Promise with the operation result
23
47
  *
24
- * @example
48
+ * @example Create
25
49
  * ```typescript
26
- * import type { Schema } from '../amplify/data/resource';
27
- * import { generateServerClientUsingCookies } from '@htlkg/data/client';
28
- * import { parseAmplifyConfig } from 'aws-amplify/utils';
29
- * import outputs from '../amplify_outputs.json';
30
- *
31
- * const amplifyConfig = parseAmplifyConfig(outputs);
50
+ * const result = await mutate('User', 'create', {
51
+ * email: 'user@example.com',
52
+ * accountId: '123',
53
+ * });
54
+ * ```
32
55
  *
33
- * const client = generateServerClientUsingCookies<Schema>({
34
- * config: amplifyConfig,
35
- * cookies: Astro.cookies,
36
- * request: Astro.request,
56
+ * @example Update
57
+ * ```typescript
58
+ * const result = await mutate('User', 'update', {
59
+ * id: 'user-id',
60
+ * status: 'deleted',
61
+ * deletedAt: new Date().toISOString(),
37
62
  * });
63
+ * ```
64
+ *
65
+ * @example Delete
66
+ * ```typescript
67
+ * const result = await mutate('User', 'delete', { id: 'user-id' });
68
+ * ```
69
+ */
70
+ declare function mutate<T = any>(model: string, operation: "create" | "update" | "delete", data: Record<string, any>, options?: ProxyOptions): Promise<GraphQLResponse<T>>;
71
+ /**
72
+ * Execute a GraphQL query through the server proxy
73
+ *
74
+ * @param model - The model name (e.g., 'User', 'Brand', 'Account')
75
+ * @param operation - The operation type ('get', 'list')
76
+ * @param data - The query parameters (id for get, filter/limit for list)
77
+ * @param options - Optional configuration
78
+ * @returns Promise with the query result
38
79
  *
39
- * // Use the client directly - operations are automatically wrapped
40
- * const result = await client.models.User.list({
41
- * selectionSet: ['id', 'email'],
80
+ * @example Get by ID
81
+ * ```typescript
82
+ * const result = await query('User', 'get', { id: 'user-id' });
83
+ * ```
84
+ *
85
+ * @example List with filter
86
+ * ```typescript
87
+ * const result = await query('User', 'list', {
88
+ * filter: { status: { eq: 'active' } },
42
89
  * limit: 100,
43
90
  * });
44
91
  * ```
45
92
  */
46
- declare function generateServerClientUsingCookies<T extends Record<any, any> = never, Options extends CommonPublicClientOptions & AstroCookiesClientParams = DefaultCommonClientOptions & AstroCookiesClientParams>(options: Options): V6ClientSSRCookies<T, Options>;
93
+ declare function query<T = any>(model: string, operation: "get" | "list", data?: Record<string, any>, options?: ProxyOptions): Promise<GraphQLResponse<T>>;
94
+ /**
95
+ * Helper to check if a response has errors
96
+ */
97
+ declare function hasErrors(response: GraphQLResponse): boolean;
98
+ /**
99
+ * Helper to get the first error message from a response
100
+ */
101
+ declare function getErrorMessage(response: GraphQLResponse): string | null;
47
102
 
48
103
  /**
49
104
  * GraphQL Client for @htlkg/data
50
105
  *
51
106
  * Provides both client-side and server-side GraphQL capabilities using AWS Amplify Data.
52
107
  * The server-side functions use the Amplify Astro adapter for proper SSR support.
108
+ *
109
+ * For server-side usage, use `Astro.locals.amplifyClient` (zero-config, injected by middleware).
53
110
  */
54
111
 
112
+ /**
113
+ * Type for the server-side Amplify client (for use in type declarations)
114
+ * This represents the client returned by generateServerClientUsingCookies
115
+ */
116
+ type AmplifyServerClient<TSchema extends Record<string, unknown> = Record<string, unknown>> = ReturnType<typeof generateServerClientUsingCookies<TSchema>>;
55
117
  /**
56
118
  * Get or create the shared GraphQL client instance (singleton pattern)
57
119
  * Use this for client-side fetching to avoid creating multiple client instances.
@@ -151,6 +213,37 @@ interface GenerateServerClientOptions {
151
213
  * });
152
214
  * ```
153
215
  */
154
- declare function generateServerClient<TSchema extends Record<string, unknown> = Record<string, unknown>>(options?: GenerateServerClientOptions): ReturnType<typeof generateClient$1<TSchema>>;
216
+ declare function generateServerClient<TSchema extends Record<string, unknown> = Record<string, unknown>>(_options?: GenerateServerClientOptions): ReturnType<typeof generateClient$1<TSchema>>;
217
+ /**
218
+ * Context required for getting a server client in API routes
219
+ */
220
+ interface ServerClientContext {
221
+ locals: {
222
+ amplifyClient?: any;
223
+ user?: any;
224
+ };
225
+ cookies: any;
226
+ request: Request;
227
+ }
228
+ /**
229
+ * Get the server client from Astro context
230
+ *
231
+ * Uses locals.amplifyClient if available (set by middleware),
232
+ * otherwise creates a new client using Amplify's global config.
233
+ * No config parameter needed - uses the config set by the middleware.
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * import { getServerClient } from '@htlkg/data/client';
238
+ *
239
+ * export const POST: APIRoute = async (context) => {
240
+ * const client = getServerClient(context);
241
+ * if (!client) return new Response('Not authenticated', { status: 401 });
242
+ *
243
+ * const result = await client.models.User.list();
244
+ * };
245
+ * ```
246
+ */
247
+ declare function getServerClient<TSchema extends Record<string, unknown> = Record<string, unknown>>(context: ServerClientContext): ReturnType<typeof generateServerClientUsingCookies<TSchema>> | null;
155
248
 
156
- export { type AstroAmplifyConfig, type GenerateServerClientOptions, type ServerAuthMode, generateClient, generateServerClient, generateServerClientUsingCookies, getSharedClient, resetSharedClient };
249
+ export { type AmplifyServerClient, type AstroAmplifyConfig, type GenerateServerClientOptions, type GraphQLResponse, type Operation, type ProxyOptions, type ServerAuthMode, type ServerClientContext, generateClient, generateServerClient, generateServerClientUsingCookies, getErrorMessage, getServerClient, getSharedClient, hasErrors, mutate, query, resetSharedClient };
@@ -1,5 +1,6 @@
1
1
  // src/client/index.ts
2
2
  import { generateClient as generateDataClient } from "aws-amplify/data";
3
+ import { Amplify } from "aws-amplify";
3
4
 
4
5
  // src/client/server.ts
5
6
  import {
@@ -57,6 +58,54 @@ function generateServerClientUsingCookies(options) {
57
58
  });
58
59
  }
59
60
 
61
+ // src/client/proxy.ts
62
+ var DEFAULT_ENDPOINT = "/api/graphql";
63
+ async function mutate(model, operation, data, options) {
64
+ return proxyRequest(model, operation, data, options);
65
+ }
66
+ async function query(model, operation, data, options) {
67
+ return proxyRequest(model, operation, data, options);
68
+ }
69
+ async function proxyRequest(model, operation, data, options) {
70
+ const endpoint = options?.endpoint ?? DEFAULT_ENDPOINT;
71
+ try {
72
+ const response = await fetch(endpoint, {
73
+ method: "POST",
74
+ headers: {
75
+ "Content-Type": "application/json"
76
+ },
77
+ credentials: "include",
78
+ // Important: include cookies
79
+ ...options?.fetchOptions,
80
+ body: JSON.stringify({ model, operation, data })
81
+ });
82
+ const result = await response.json();
83
+ if (response.status === 401) {
84
+ console.error("[GraphQL Proxy] Unauthorized - session may have expired");
85
+ }
86
+ return result;
87
+ } catch (error) {
88
+ console.error("[GraphQL Proxy] Request failed:", error);
89
+ return {
90
+ data: null,
91
+ errors: [
92
+ {
93
+ message: error instanceof Error ? error.message : "Network error"
94
+ }
95
+ ]
96
+ };
97
+ }
98
+ }
99
+ function hasErrors(response) {
100
+ return !!response.errors && response.errors.length > 0;
101
+ }
102
+ function getErrorMessage(response) {
103
+ if (!response.errors || response.errors.length === 0) {
104
+ return null;
105
+ }
106
+ return response.errors[0].message;
107
+ }
108
+
60
109
  // src/client/index.ts
61
110
  var sharedClientInstance = null;
62
111
  function getSharedClient() {
@@ -71,15 +120,40 @@ function resetSharedClient() {
71
120
  function generateClient() {
72
121
  return generateDataClient();
73
122
  }
74
- function generateServerClient(options) {
123
+ function generateServerClient(_options) {
75
124
  const client = generateDataClient();
76
125
  return client;
77
126
  }
127
+ function getServerClient(context) {
128
+ if (context.locals.amplifyClient) {
129
+ return context.locals.amplifyClient;
130
+ }
131
+ if (context.locals.user) {
132
+ try {
133
+ const amplifyConfig = Amplify.getConfig();
134
+ if (amplifyConfig) {
135
+ return generateServerClientUsingCookies({
136
+ config: amplifyConfig,
137
+ cookies: context.cookies,
138
+ request: context.request
139
+ });
140
+ }
141
+ } catch (e) {
142
+ console.error("[getServerClient] Failed to get Amplify config:", e);
143
+ }
144
+ }
145
+ return null;
146
+ }
78
147
  export {
79
148
  generateClient,
80
149
  generateServerClient,
81
150
  generateServerClientUsingCookies,
151
+ getErrorMessage,
152
+ getServerClient,
82
153
  getSharedClient,
154
+ hasErrors,
155
+ mutate,
156
+ query,
83
157
  resetSharedClient
84
158
  };
85
159
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/index.ts","../../src/client/server.ts"],"sourcesContent":["/**\n * GraphQL Client for @htlkg/data\n *\n * Provides both client-side and server-side GraphQL capabilities using AWS Amplify Data.\n * The server-side functions use the Amplify Astro adapter for proper SSR support.\n */\n\nimport { generateClient as generateDataClient } from \"aws-amplify/data\";\nimport type { ResourcesConfig } from \"aws-amplify\";\n\n// Re-export server-side client generation\nexport { generateServerClientUsingCookies } from \"./server\";\n\n// Singleton client instance for client-side fetching\nlet sharedClientInstance: any = null;\n\n/**\n * Get or create the shared GraphQL client instance (singleton pattern)\n * Use this for client-side fetching to avoid creating multiple client instances.\n *\n * @example\n * ```typescript\n * const client = getSharedClient<Schema>();\n * const { data } = await client.models.Account.list();\n * ```\n */\nexport function getSharedClient<\n\tTSchema extends Record<string, unknown> = Record<string, unknown>,\n>(): ReturnType<typeof generateDataClient<TSchema>> {\n\tif (!sharedClientInstance) {\n\t\tsharedClientInstance = generateDataClient<TSchema>();\n\t}\n\treturn sharedClientInstance;\n}\n\n/**\n * Reset the shared client instance (useful for testing or auth state changes)\n */\nexport function resetSharedClient(): void {\n\tsharedClientInstance = null;\n}\n\n/**\n * Generate a client-side GraphQL client for use in Vue components and browser contexts\n * This is SSR-safe and should be called within a component's setup function or after hydration\n *\n * @example\n * ```typescript\n * import type { Schema } from '@backend/data/resource';\n * import { generateClient } from '@htlkg/data/client';\n *\n * const client = generateClient<Schema>();\n * const { data: brands } = await client.models.Brand.list();\n * ```\n */\nexport function generateClient<\n\tTSchema extends Record<string, unknown> = Record<string, unknown>,\n>(): ReturnType<typeof generateDataClient<TSchema>> {\n\treturn generateDataClient<TSchema>();\n}\n\n/**\n * Configuration for Amplify (matches amplify_outputs.json format)\n */\nexport type AstroAmplifyConfig = ResourcesConfig;\n\n/**\n * Authentication mode for server-side GraphQL client\n */\nexport type ServerAuthMode = 'userPool' | 'apiKey';\n\n/**\n * Options for generating a server-side GraphQL client\n */\nexport interface GenerateServerClientOptions {\n\t/** Authentication mode - 'userPool' (default) uses JWT from cookies, 'apiKey' uses API key */\n\tauthMode?: ServerAuthMode;\n}\n\n/**\n * Generate a server-side GraphQL client for use within runWithAmplifyServerContext\n * \n * This function creates a GraphQL client that can be used for server-side data fetching in Astro.\n * It MUST be called within runWithAmplifyServerContext to access JWT tokens from cookies.\n * \n * The client supports two authentication modes:\n * - 'userPool' (default): Uses JWT tokens from cookies (requires runWithAmplifyServerContext)\n * - 'apiKey': Uses API key for public/unauthenticated requests\n *\n * **Important**: \n * - Amplify.configure() must be called once at app startup (e.g., in amplify-server.ts)\n * - This function must be called INSIDE the operation function of runWithAmplifyServerContext\n * - The context automatically provides the token provider that reads JWT tokens from cookies\n *\n * @example\n * ```typescript\n * // In your Astro page\n * import type { Schema } from '../amplify/data/resource';\n * import { generateServerClient } from '@htlkg/data/client';\n * import { createRunWithAmplifyServerContext } from '@htlkg/core/amplify-astro-adapter';\n * import outputs from '../amplify_outputs.json';\n *\n * const runWithAmplifyServerContext = createRunWithAmplifyServerContext({ config: outputs });\n *\n * // Fetch data with authentication\n * const result = await runWithAmplifyServerContext({\n * astroServerContext: {\n * cookies: Astro.cookies,\n * request: Astro.request\n * },\n * operation: async (contextSpec) => {\n * // Generate client INSIDE the operation\n * const client = generateServerClient<Schema>({ authMode: 'userPool' });\n * return await client.models.User.list();\n * }\n * });\n * \n * const users = result.data || [];\n * ```\n * \n * @example Using API key for public data\n * ```typescript\n * const result = await runWithAmplifyServerContext({\n * astroServerContext: {\n * cookies: Astro.cookies,\n * request: Astro.request\n * },\n * operation: async (contextSpec) => {\n * const client = generateServerClient<Schema>({ authMode: 'apiKey' });\n * return await client.models.Brand.list();\n * }\n * });\n * ```\n */\nexport function generateServerClient<\n\tTSchema extends Record<string, unknown> = Record<string, unknown>,\n>(options?: GenerateServerClientOptions): ReturnType<typeof generateDataClient<TSchema>> {\n\t// Generate the client without authMode parameter\n\t// When called within runWithAmplifyServerContext, it will automatically use the token provider\n\t// from the context (which reads JWT tokens from cookies)\n\t// The authMode should be specified per-operation, not at client creation\n\tconst client = generateDataClient<TSchema>();\n\t\n\treturn client;\n}\n","/**\n * Server-side data client for Astro\n *\n * Provides a client generator similar to Next.js's generateServerClientUsingCookies\n * using generateClientWithAmplifyInstance for proper server context integration.\n */\n\nimport type { AstroGlobal } from \"astro\";\nimport type { ResourcesConfig } from \"aws-amplify\";\nimport {\n\tCommonPublicClientOptions,\n\tDefaultCommonClientOptions,\n\tV6ClientSSRCookies,\n\tgenerateClientWithAmplifyInstance,\n} from \"aws-amplify/api/internals\";\nimport { getAmplifyServerContext } from \"aws-amplify/adapter-core/internals\";\nimport { createRunWithAmplifyServerContext, createLogger } from \"@htlkg/core/amplify-astro-adapter\";\n\nconst log = createLogger('server-client');\n\ninterface AstroCookiesClientParams {\n\tcookies: AstroGlobal[\"cookies\"];\n\trequest: AstroGlobal[\"request\"];\n\tconfig: ResourcesConfig;\n}\n\n/**\n * Generates a server-side data client for Astro (matches Next.js implementation)\n *\n * This function creates a client that automatically wraps all operations in the Amplify server context,\n * ensuring that authentication tokens from cookies are properly used.\n *\n * @example\n * ```typescript\n * import type { Schema } from '../amplify/data/resource';\n * import { generateServerClientUsingCookies } from '@htlkg/data/client';\n * import { parseAmplifyConfig } from 'aws-amplify/utils';\n * import outputs from '../amplify_outputs.json';\n *\n * const amplifyConfig = parseAmplifyConfig(outputs);\n *\n * const client = generateServerClientUsingCookies<Schema>({\n * config: amplifyConfig,\n * cookies: Astro.cookies,\n * request: Astro.request,\n * });\n *\n * // Use the client directly - operations are automatically wrapped\n * const result = await client.models.User.list({\n * selectionSet: ['id', 'email'],\n * limit: 100,\n * });\n * ```\n */\nexport function generateServerClientUsingCookies<\n\tT extends Record<any, any> = never,\n\tOptions extends CommonPublicClientOptions &\n\t\tAstroCookiesClientParams = DefaultCommonClientOptions &\n\t\tAstroCookiesClientParams,\n>(options: Options): V6ClientSSRCookies<T, Options> {\n\tconst runWithAmplifyServerContext = createRunWithAmplifyServerContext({\n\t\tconfig: options.config,\n\t});\n\n\tconst resourcesConfig = options.config;\n\n\t// This function reference gets passed down to InternalGraphQLAPI.ts.graphql\n\t// where this._graphql is passed in as the `fn` argument\n\t// causing it to always get invoked inside `runWithAmplifyServerContext`\n\tconst getAmplify = (fn: (amplify: any) => Promise<any>) => {\n\t\treturn runWithAmplifyServerContext({\n\t\t\tastroServerContext: {\n\t\t\t\tcookies: options.cookies,\n\t\t\t\trequest: options.request,\n\t\t\t},\n\t\t\toperation: async (contextSpec: any) => {\n\t\t\t\tconst amplifyInstance = getAmplifyServerContext(contextSpec).amplify;\n\t\t\t\t\n\t\t\t\t// Debug logging (only when DEBUG=true)\n\t\t\t\ttry {\n\t\t\t\t\tconst config = amplifyInstance.getConfig();\n\t\t\t\t\tlog.debug('Amplify config from instance:', {\n\t\t\t\t\t\thasAPI: !!config.API,\n\t\t\t\t\t\thasGraphQL: !!config.API?.GraphQL,\n\t\t\t\t\t\tendpoint: config.API?.GraphQL?.endpoint,\n\t\t\t\t\t\tdefaultAuthMode: config.API?.GraphQL?.defaultAuthMode,\n\t\t\t\t\t\tregion: config.API?.GraphQL?.region,\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\tconst session = await amplifyInstance.Auth.fetchAuthSession();\n\t\t\t\t\tlog.debug('Auth session:', {\n\t\t\t\t\t\thasTokens: !!session.tokens,\n\t\t\t\t\t\thasAccessToken: !!session.tokens?.accessToken,\n\t\t\t\t\t\thasIdToken: !!session.tokens?.idToken,\n\t\t\t\t\t\thasCredentials: !!session.credentials,\n\t\t\t\t\t});\n\t\t\t\t} catch (e: any) {\n\t\t\t\t\tlog.debug('Error fetching session:', e.message);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn fn(amplifyInstance);\n\t\t\t},\n\t\t});\n\t};\n\n\tconst {\n\t\tcookies: _cookies,\n\t\trequest: _request,\n\t\tconfig: _config,\n\t\t...params\n\t} = options;\n\n\treturn generateClientWithAmplifyInstance<T, V6ClientSSRCookies<T, Options>>({\n\t\tamplify: getAmplify,\n\t\tconfig: resourcesConfig,\n\t\t...params,\n\t} as any);\n}\n"],"mappings":";AAOA,SAAS,kBAAkB,0BAA0B;;;ACErD;AAAA,EAIC;AAAA,OACM;AACP,SAAS,+BAA+B;AACxC,SAAS,mCAAmC,oBAAoB;AAEhE,IAAM,MAAM,aAAa,eAAe;AAoCjC,SAAS,iCAKd,SAAkD;AACnD,QAAM,8BAA8B,kCAAkC;AAAA,IACrE,QAAQ,QAAQ;AAAA,EACjB,CAAC;AAED,QAAM,kBAAkB,QAAQ;AAKhC,QAAM,aAAa,CAAC,OAAuC;AAC1D,WAAO,4BAA4B;AAAA,MAClC,oBAAoB;AAAA,QACnB,SAAS,QAAQ;AAAA,QACjB,SAAS,QAAQ;AAAA,MAClB;AAAA,MACA,WAAW,OAAO,gBAAqB;AACtC,cAAM,kBAAkB,wBAAwB,WAAW,EAAE;AAG7D,YAAI;AACH,gBAAM,SAAS,gBAAgB,UAAU;AACzC,cAAI,MAAM,iCAAiC;AAAA,YAC1C,QAAQ,CAAC,CAAC,OAAO;AAAA,YACjB,YAAY,CAAC,CAAC,OAAO,KAAK;AAAA,YAC1B,UAAU,OAAO,KAAK,SAAS;AAAA,YAC/B,iBAAiB,OAAO,KAAK,SAAS;AAAA,YACtC,QAAQ,OAAO,KAAK,SAAS;AAAA,UAC9B,CAAC;AAED,gBAAM,UAAU,MAAM,gBAAgB,KAAK,iBAAiB;AAC5D,cAAI,MAAM,iBAAiB;AAAA,YAC1B,WAAW,CAAC,CAAC,QAAQ;AAAA,YACrB,gBAAgB,CAAC,CAAC,QAAQ,QAAQ;AAAA,YAClC,YAAY,CAAC,CAAC,QAAQ,QAAQ;AAAA,YAC9B,gBAAgB,CAAC,CAAC,QAAQ;AAAA,UAC3B,CAAC;AAAA,QACF,SAAS,GAAQ;AAChB,cAAI,MAAM,2BAA2B,EAAE,OAAO;AAAA,QAC/C;AAEA,eAAO,GAAG,eAAe;AAAA,MAC1B;AAAA,IACD,CAAC;AAAA,EACF;AAEA,QAAM;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,GAAG;AAAA,EACJ,IAAI;AAEJ,SAAO,kCAAqE;AAAA,IAC3E,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,GAAG;AAAA,EACJ,CAAQ;AACT;;;ADvGA,IAAI,uBAA4B;AAYzB,SAAS,kBAEoC;AACnD,MAAI,CAAC,sBAAsB;AAC1B,2BAAuB,mBAA4B;AAAA,EACpD;AACA,SAAO;AACR;AAKO,SAAS,oBAA0B;AACzC,yBAAuB;AACxB;AAeO,SAAS,iBAEoC;AACnD,SAAO,mBAA4B;AACpC;AA2EO,SAAS,qBAEd,SAAuF;AAKxF,QAAM,SAAS,mBAA4B;AAE3C,SAAO;AACR;","names":[]}
1
+ {"version":3,"sources":["../../src/client/index.ts","../../src/client/server.ts","../../src/client/proxy.ts"],"sourcesContent":["/**\n * GraphQL Client for @htlkg/data\n *\n * Provides both client-side and server-side GraphQL capabilities using AWS Amplify Data.\n * The server-side functions use the Amplify Astro adapter for proper SSR support.\n *\n * For server-side usage, use `Astro.locals.amplifyClient` (zero-config, injected by middleware).\n */\n\nimport { generateClient as generateDataClient } from \"aws-amplify/data\";\nimport { Amplify } from \"aws-amplify\";\nimport type { ResourcesConfig } from \"aws-amplify\";\nimport { generateServerClientUsingCookies } from \"./server\";\n\n// Re-export server-side client generation (used internally by middleware)\nexport { generateServerClientUsingCookies } from \"./server\";\n\n// Re-export proxy functions for authenticated client-side operations\nexport {\n\tmutate,\n\tquery,\n\thasErrors,\n\tgetErrorMessage,\n\ttype Operation,\n\ttype GraphQLResponse,\n\ttype ProxyOptions,\n} from \"./proxy\";\n\n/**\n * Type for the server-side Amplify client (for use in type declarations)\n * This represents the client returned by generateServerClientUsingCookies\n */\nexport type AmplifyServerClient<TSchema extends Record<string, unknown> = Record<string, unknown>> =\n\tReturnType<typeof generateServerClientUsingCookies<TSchema>>;\n\n// Singleton client instance for client-side fetching\nlet sharedClientInstance: any = null;\n\n/**\n * Get or create the shared GraphQL client instance (singleton pattern)\n * Use this for client-side fetching to avoid creating multiple client instances.\n *\n * @example\n * ```typescript\n * const client = getSharedClient<Schema>();\n * const { data } = await client.models.Account.list();\n * ```\n */\nexport function getSharedClient<\n\tTSchema extends Record<string, unknown> = Record<string, unknown>,\n>(): ReturnType<typeof generateDataClient<TSchema>> {\n\tif (!sharedClientInstance) {\n\t\tsharedClientInstance = generateDataClient<TSchema>();\n\t}\n\treturn sharedClientInstance;\n}\n\n/**\n * Reset the shared client instance (useful for testing or auth state changes)\n */\nexport function resetSharedClient(): void {\n\tsharedClientInstance = null;\n}\n\n/**\n * Generate a client-side GraphQL client for use in Vue components and browser contexts\n * This is SSR-safe and should be called within a component's setup function or after hydration\n *\n * @example\n * ```typescript\n * import type { Schema } from '@backend/data/resource';\n * import { generateClient } from '@htlkg/data/client';\n *\n * const client = generateClient<Schema>();\n * const { data: brands } = await client.models.Brand.list();\n * ```\n */\nexport function generateClient<\n\tTSchema extends Record<string, unknown> = Record<string, unknown>,\n>(): ReturnType<typeof generateDataClient<TSchema>> {\n\treturn generateDataClient<TSchema>();\n}\n\n/**\n * Configuration for Amplify (matches amplify_outputs.json format)\n */\nexport type AstroAmplifyConfig = ResourcesConfig;\n\n/**\n * Authentication mode for server-side GraphQL client\n */\nexport type ServerAuthMode = 'userPool' | 'apiKey';\n\n/**\n * Options for generating a server-side GraphQL client\n */\nexport interface GenerateServerClientOptions {\n\t/** Authentication mode - 'userPool' (default) uses JWT from cookies, 'apiKey' uses API key */\n\tauthMode?: ServerAuthMode;\n}\n\n/**\n * Generate a server-side GraphQL client for use within runWithAmplifyServerContext\n * \n * This function creates a GraphQL client that can be used for server-side data fetching in Astro.\n * It MUST be called within runWithAmplifyServerContext to access JWT tokens from cookies.\n * \n * The client supports two authentication modes:\n * - 'userPool' (default): Uses JWT tokens from cookies (requires runWithAmplifyServerContext)\n * - 'apiKey': Uses API key for public/unauthenticated requests\n *\n * **Important**: \n * - Amplify.configure() must be called once at app startup (e.g., in amplify-server.ts)\n * - This function must be called INSIDE the operation function of runWithAmplifyServerContext\n * - The context automatically provides the token provider that reads JWT tokens from cookies\n *\n * @example\n * ```typescript\n * // In your Astro page\n * import type { Schema } from '../amplify/data/resource';\n * import { generateServerClient } from '@htlkg/data/client';\n * import { createRunWithAmplifyServerContext } from '@htlkg/core/amplify-astro-adapter';\n * import outputs from '../amplify_outputs.json';\n *\n * const runWithAmplifyServerContext = createRunWithAmplifyServerContext({ config: outputs });\n *\n * // Fetch data with authentication\n * const result = await runWithAmplifyServerContext({\n * astroServerContext: {\n * cookies: Astro.cookies,\n * request: Astro.request\n * },\n * operation: async (contextSpec) => {\n * // Generate client INSIDE the operation\n * const client = generateServerClient<Schema>({ authMode: 'userPool' });\n * return await client.models.User.list();\n * }\n * });\n * \n * const users = result.data || [];\n * ```\n * \n * @example Using API key for public data\n * ```typescript\n * const result = await runWithAmplifyServerContext({\n * astroServerContext: {\n * cookies: Astro.cookies,\n * request: Astro.request\n * },\n * operation: async (contextSpec) => {\n * const client = generateServerClient<Schema>({ authMode: 'apiKey' });\n * return await client.models.Brand.list();\n * }\n * });\n * ```\n */\nexport function generateServerClient<\n\tTSchema extends Record<string, unknown> = Record<string, unknown>,\n>(_options?: GenerateServerClientOptions): ReturnType<typeof generateDataClient<TSchema>> {\n\t// Generate the client without authMode parameter\n\t// When called within runWithAmplifyServerContext, it will automatically use the token provider\n\t// from the context (which reads JWT tokens from cookies)\n\t// The authMode should be specified per-operation, not at client creation\n\tconst client = generateDataClient<TSchema>();\n\n\treturn client;\n}\n\n/**\n * Context required for getting a server client in API routes\n */\nexport interface ServerClientContext {\n\tlocals: { amplifyClient?: any; user?: any };\n\tcookies: any;\n\trequest: Request;\n}\n\n/**\n * Get the server client from Astro context\n *\n * Uses locals.amplifyClient if available (set by middleware),\n * otherwise creates a new client using Amplify's global config.\n * No config parameter needed - uses the config set by the middleware.\n *\n * @example\n * ```typescript\n * import { getServerClient } from '@htlkg/data/client';\n *\n * export const POST: APIRoute = async (context) => {\n * const client = getServerClient(context);\n * if (!client) return new Response('Not authenticated', { status: 401 });\n *\n * const result = await client.models.User.list();\n * };\n * ```\n */\nexport function getServerClient<TSchema extends Record<string, unknown> = Record<string, unknown>>(\n\tcontext: ServerClientContext,\n): ReturnType<typeof generateServerClientUsingCookies<TSchema>> | null {\n\t// Try to use client from middleware first\n\tif (context.locals.amplifyClient) {\n\t\treturn context.locals.amplifyClient as ReturnType<typeof generateServerClientUsingCookies<TSchema>>;\n\t}\n\n\t// If no client from middleware and user is authenticated, create one using global Amplify config\n\tif (context.locals.user) {\n\t\ttry {\n\t\t\t// Get config from Amplify (set by middleware)\n\t\t\tconst amplifyConfig = Amplify.getConfig();\n\t\t\tif (amplifyConfig) {\n\t\t\t\treturn generateServerClientUsingCookies<TSchema>({\n\t\t\t\t\tconfig: amplifyConfig,\n\t\t\t\t\tcookies: context.cookies,\n\t\t\t\t\trequest: context.request,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.error('[getServerClient] Failed to get Amplify config:', e);\n\t\t}\n\t}\n\n\t// No authentication available\n\treturn null;\n}\n","/**\n * Server-side data client for Astro\n *\n * Provides a client generator similar to Next.js's generateServerClientUsingCookies\n * using generateClientWithAmplifyInstance for proper server context integration.\n */\n\nimport type { AstroGlobal } from \"astro\";\nimport type { ResourcesConfig } from \"aws-amplify\";\nimport {\n\tCommonPublicClientOptions,\n\tDefaultCommonClientOptions,\n\tV6ClientSSRCookies,\n\tgenerateClientWithAmplifyInstance,\n} from \"aws-amplify/api/internals\";\nimport { getAmplifyServerContext } from \"aws-amplify/adapter-core/internals\";\nimport { createRunWithAmplifyServerContext, createLogger } from \"@htlkg/core/amplify-astro-adapter\";\n\nconst log = createLogger('server-client');\n\ninterface AstroCookiesClientParams {\n\tcookies: AstroGlobal[\"cookies\"];\n\trequest: AstroGlobal[\"request\"];\n\tconfig: ResourcesConfig;\n}\n\n/**\n * Generates a server-side data client for Astro (matches Next.js implementation)\n *\n * This function creates a client that automatically wraps all operations in the Amplify server context,\n * ensuring that authentication tokens from cookies are properly used.\n *\n * @example\n * ```typescript\n * import type { Schema } from '../amplify/data/resource';\n * import { generateServerClientUsingCookies } from '@htlkg/data/client';\n * import { parseAmplifyConfig } from 'aws-amplify/utils';\n * import outputs from '../amplify_outputs.json';\n *\n * const amplifyConfig = parseAmplifyConfig(outputs);\n *\n * const client = generateServerClientUsingCookies<Schema>({\n * config: amplifyConfig,\n * cookies: Astro.cookies,\n * request: Astro.request,\n * });\n *\n * // Use the client directly - operations are automatically wrapped\n * const result = await client.models.User.list({\n * selectionSet: ['id', 'email'],\n * limit: 100,\n * });\n * ```\n */\nexport function generateServerClientUsingCookies<\n\tT extends Record<any, any> = never,\n\tOptions extends CommonPublicClientOptions &\n\t\tAstroCookiesClientParams = DefaultCommonClientOptions &\n\t\tAstroCookiesClientParams,\n>(options: Options): V6ClientSSRCookies<T, Options> {\n\tconst runWithAmplifyServerContext = createRunWithAmplifyServerContext({\n\t\tconfig: options.config,\n\t});\n\n\tconst resourcesConfig = options.config;\n\n\t// This function reference gets passed down to InternalGraphQLAPI.ts.graphql\n\t// where this._graphql is passed in as the `fn` argument\n\t// causing it to always get invoked inside `runWithAmplifyServerContext`\n\tconst getAmplify = (fn: (amplify: any) => Promise<any>) => {\n\t\treturn runWithAmplifyServerContext({\n\t\t\tastroServerContext: {\n\t\t\t\tcookies: options.cookies,\n\t\t\t\trequest: options.request,\n\t\t\t},\n\t\t\toperation: async (contextSpec: any) => {\n\t\t\t\tconst amplifyInstance = getAmplifyServerContext(contextSpec).amplify;\n\t\t\t\t\n\t\t\t\t// Debug logging (only when DEBUG=true)\n\t\t\t\ttry {\n\t\t\t\t\tconst config = amplifyInstance.getConfig();\n\t\t\t\t\tlog.debug('Amplify config from instance:', {\n\t\t\t\t\t\thasAPI: !!config.API,\n\t\t\t\t\t\thasGraphQL: !!config.API?.GraphQL,\n\t\t\t\t\t\tendpoint: config.API?.GraphQL?.endpoint,\n\t\t\t\t\t\tdefaultAuthMode: config.API?.GraphQL?.defaultAuthMode,\n\t\t\t\t\t\tregion: config.API?.GraphQL?.region,\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\tconst session = await amplifyInstance.Auth.fetchAuthSession();\n\t\t\t\t\tlog.debug('Auth session:', {\n\t\t\t\t\t\thasTokens: !!session.tokens,\n\t\t\t\t\t\thasAccessToken: !!session.tokens?.accessToken,\n\t\t\t\t\t\thasIdToken: !!session.tokens?.idToken,\n\t\t\t\t\t\thasCredentials: !!session.credentials,\n\t\t\t\t\t});\n\t\t\t\t} catch (e: any) {\n\t\t\t\t\tlog.debug('Error fetching session:', e.message);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn fn(amplifyInstance);\n\t\t\t},\n\t\t});\n\t};\n\n\tconst {\n\t\tcookies: _cookies,\n\t\trequest: _request,\n\t\tconfig: _config,\n\t\t...params\n\t} = options;\n\n\treturn generateClientWithAmplifyInstance<T, V6ClientSSRCookies<T, Options>>({\n\t\tamplify: getAmplify,\n\t\tconfig: resourcesConfig,\n\t\t...params,\n\t} as any);\n}\n","/**\n * GraphQL Proxy Client\n *\n * Client-side helper for making authenticated GraphQL operations through\n * the server-side proxy. This allows Vue components to perform mutations\n * while keeping auth cookies httpOnly for security.\n *\n * @module @htlkg/data/proxy\n */\n\n/**\n * Valid GraphQL operations\n */\nexport type Operation = \"create\" | \"update\" | \"delete\" | \"get\" | \"list\";\n\n/**\n * Response type from GraphQL operations\n */\nexport interface GraphQLResponse<T = any> {\n\tdata: T | null;\n\terrors?: Array<{ message: string; [key: string]: any }>;\n}\n\n/**\n * Options for proxy requests\n */\nexport interface ProxyOptions {\n\t/** Custom API endpoint (default: /api/graphql) */\n\tendpoint?: string;\n\t/** Additional fetch options */\n\tfetchOptions?: RequestInit;\n}\n\n/**\n * Default proxy endpoint\n */\nconst DEFAULT_ENDPOINT = \"/api/graphql\";\n\n/**\n * Execute a GraphQL mutation through the server proxy\n *\n * @param model - The model name (e.g., 'User', 'Brand', 'Account')\n * @param operation - The operation type ('create', 'update', 'delete')\n * @param data - The operation data/input\n * @param options - Optional configuration\n * @returns Promise with the operation result\n *\n * @example Create\n * ```typescript\n * const result = await mutate('User', 'create', {\n * email: 'user@example.com',\n * accountId: '123',\n * });\n * ```\n *\n * @example Update\n * ```typescript\n * const result = await mutate('User', 'update', {\n * id: 'user-id',\n * status: 'deleted',\n * deletedAt: new Date().toISOString(),\n * });\n * ```\n *\n * @example Delete\n * ```typescript\n * const result = await mutate('User', 'delete', { id: 'user-id' });\n * ```\n */\nexport async function mutate<T = any>(\n\tmodel: string,\n\toperation: \"create\" | \"update\" | \"delete\",\n\tdata: Record<string, any>,\n\toptions?: ProxyOptions,\n): Promise<GraphQLResponse<T>> {\n\treturn proxyRequest<T>(model, operation, data, options);\n}\n\n/**\n * Execute a GraphQL query through the server proxy\n *\n * @param model - The model name (e.g., 'User', 'Brand', 'Account')\n * @param operation - The operation type ('get', 'list')\n * @param data - The query parameters (id for get, filter/limit for list)\n * @param options - Optional configuration\n * @returns Promise with the query result\n *\n * @example Get by ID\n * ```typescript\n * const result = await query('User', 'get', { id: 'user-id' });\n * ```\n *\n * @example List with filter\n * ```typescript\n * const result = await query('User', 'list', {\n * filter: { status: { eq: 'active' } },\n * limit: 100,\n * });\n * ```\n */\nexport async function query<T = any>(\n\tmodel: string,\n\toperation: \"get\" | \"list\",\n\tdata?: Record<string, any>,\n\toptions?: ProxyOptions,\n): Promise<GraphQLResponse<T>> {\n\treturn proxyRequest<T>(model, operation, data, options);\n}\n\n/**\n * Internal function to make proxy requests\n */\nasync function proxyRequest<T>(\n\tmodel: string,\n\toperation: Operation,\n\tdata?: Record<string, any>,\n\toptions?: ProxyOptions,\n): Promise<GraphQLResponse<T>> {\n\tconst endpoint = options?.endpoint ?? DEFAULT_ENDPOINT;\n\n\ttry {\n\t\tconst response = await fetch(endpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tcredentials: \"include\", // Important: include cookies\n\t\t\t...options?.fetchOptions,\n\t\t\tbody: JSON.stringify({ model, operation, data }),\n\t\t});\n\n\t\tconst result: GraphQLResponse<T> = await response.json();\n\n\t\t// Handle auth errors\n\t\tif (response.status === 401) {\n\t\t\tconsole.error(\"[GraphQL Proxy] Unauthorized - session may have expired\");\n\t\t\t// Optionally trigger a redirect to login\n\t\t\t// window.location.href = '/login';\n\t\t}\n\n\t\treturn result;\n\t} catch (error) {\n\t\tconsole.error(\"[GraphQL Proxy] Request failed:\", error);\n\t\treturn {\n\t\t\tdata: null,\n\t\t\terrors: [\n\t\t\t\t{\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Network error\",\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n}\n\n/**\n * Helper to check if a response has errors\n */\nexport function hasErrors(response: GraphQLResponse): boolean {\n\treturn !!response.errors && response.errors.length > 0;\n}\n\n/**\n * Helper to get the first error message from a response\n */\nexport function getErrorMessage(response: GraphQLResponse): string | null {\n\tif (!response.errors || response.errors.length === 0) {\n\t\treturn null;\n\t}\n\treturn response.errors[0].message;\n}\n"],"mappings":"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","names":[]}
@@ -1,8 +1,10 @@
1
1
  import { Ref, ComputedRef } from 'vue';
2
- import { Brand, Account, User, Product } from '@htlkg/core/types';
2
+ import { Brand, Account, User, Product, ProductInstance } from '@htlkg/core/types';
3
+ import { C as CreateProductInstanceInput, U as UpdateProductInstanceInput } from '../productInstances-CzT3NZKU.js';
3
4
  export { resetSharedClient as resetClientInstance } from '../client/index.js';
4
5
  import 'aws-amplify/data';
5
6
  import 'aws-amplify';
7
+ import '../server/index.js';
6
8
  import 'astro';
7
9
  import 'aws-amplify/api/internals';
8
10
 
@@ -305,4 +307,76 @@ interface UseProductsReturn {
305
307
  */
306
308
  declare function useProducts(options?: UseProductsOptions): UseProductsReturn;
307
309
 
308
- export { type BaseHookOptions, type CreateDataHookOptions, type DataHookReturn, type InferHookReturn, type UseAccountsOptions, type UseAccountsReturn, type UseBrandsOptions, type UseBrandsReturn, type UseProductsOptions, type UseProductsReturn, type UseUsersOptions, type UseUsersReturn, createDataHook, useAccounts, useBrands, useProducts, useUsers };
310
+ /**
311
+ * useProductInstances Hook
312
+ *
313
+ * Vue composable for fetching and managing product instance data with reactive state.
314
+ * Provides loading states, error handling, refetch capabilities, and CRUD operations.
315
+ */
316
+
317
+ interface UseProductInstancesOptions extends BaseHookOptions {
318
+ /** Filter criteria for product instances */
319
+ filter?: any;
320
+ /** Limit number of results */
321
+ limit?: number;
322
+ /** Auto-fetch on mount (default: true) */
323
+ autoFetch?: boolean;
324
+ /** Filter by brand ID */
325
+ brandId?: string;
326
+ /** Filter by account ID */
327
+ accountId?: string;
328
+ /** Filter by product ID */
329
+ productId?: string;
330
+ /** Only enabled instances */
331
+ enabledOnly?: boolean;
332
+ }
333
+ interface UseProductInstancesReturn {
334
+ /** Reactive array of product instances */
335
+ instances: Ref<ProductInstance[]>;
336
+ /** Computed array of enabled instances only */
337
+ enabledInstances: ComputedRef<ProductInstance[]>;
338
+ /** Loading state */
339
+ loading: Ref<boolean>;
340
+ /** Error state */
341
+ error: Ref<Error | null>;
342
+ /** Refetch product instances */
343
+ refetch: () => Promise<void>;
344
+ /** Create a new product instance */
345
+ createInstance: (input: CreateProductInstanceInput) => Promise<ProductInstance>;
346
+ /** Update an existing product instance */
347
+ updateInstance: (input: UpdateProductInstanceInput) => Promise<ProductInstance>;
348
+ /** Delete a product instance */
349
+ deleteInstance: (id: string) => Promise<boolean>;
350
+ /** Toggle the enabled status of a product instance */
351
+ toggleEnabled: (id: string, enabled: boolean) => Promise<ProductInstance>;
352
+ }
353
+ /**
354
+ * Composable for fetching and managing product instances
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * import { useProductInstances } from '@htlkg/data/hooks';
359
+ *
360
+ * const { instances, loading, error, refetch } = useProductInstances();
361
+ * ```
362
+ *
363
+ * @example With filters
364
+ * ```typescript
365
+ * const { instances, enabledInstances, loading } = useProductInstances({
366
+ * brandId: 'brand-123',
367
+ * enabledOnly: true,
368
+ * limit: 50
369
+ * });
370
+ * ```
371
+ *
372
+ * @example For a specific account
373
+ * ```typescript
374
+ * const { instances, loading } = useProductInstances({
375
+ * accountId: 'account-456',
376
+ * autoFetch: true
377
+ * });
378
+ * ```
379
+ */
380
+ declare function useProductInstances(options?: UseProductInstancesOptions): UseProductInstancesReturn;
381
+
382
+ export { type BaseHookOptions, type CreateDataHookOptions, type DataHookReturn, type InferHookReturn, type UseAccountsOptions, type UseAccountsReturn, type UseBrandsOptions, type UseBrandsReturn, type UseProductInstancesOptions, type UseProductInstancesReturn, type UseProductsOptions, type UseProductsReturn, type UseUsersOptions, type UseUsersReturn, createDataHook, useAccounts, useBrands, useProductInstances, useProducts, useUsers };