@intrig/plugin-next 0.0.2-1 → 0.0.2-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 (3) hide show
  1. package/dist/index.cjs +293 -69
  2. package/dist/index.js +293 -69
  3. package/package.json +3 -4
package/dist/index.cjs CHANGED
@@ -8,7 +8,7 @@ var fsx = require('fs-extra');
8
8
  var mimeType = require('mime-types');
9
9
  var _ = require('lodash');
10
10
  var fs = require('fs');
11
- var inquirer = require('inquirer');
11
+ var chalk = require('chalk');
12
12
 
13
13
  function _interopNamespaceDefault(e) {
14
14
  var n = Object.create(null);
@@ -1651,6 +1651,7 @@ function providerHooksTemplate() {
1651
1651
  useMemo,
1652
1652
  useState,
1653
1653
  useRef,
1654
+ useEffect,
1654
1655
  } from 'react';
1655
1656
  import {
1656
1657
  ErrorState,
@@ -1694,6 +1695,16 @@ export function useNetworkState<T>({
1694
1695
  const context = useContext(Context);
1695
1696
 
1696
1697
  const [abortController, setAbortController] = useState<AbortController>();
1698
+
1699
+ const contextRef = useRef(context);
1700
+ const schemaRef = useRef(schema);
1701
+ const errorSchemaRef = useRef(errorSchema);
1702
+
1703
+ useEffect(() => {
1704
+ contextRef.current = context;
1705
+ schemaRef.current = schema;
1706
+ errorSchemaRef.current = errorSchema;
1707
+ });
1697
1708
 
1698
1709
  const networkState = useMemo(() => {
1699
1710
  logger.info(${"`Updating status ${key} ${operation} ${source}`"});
@@ -1702,7 +1713,7 @@ export function useNetworkState<T>({
1702
1713
  (context.state?.[${"`${source}:${operation}:${key}`"}] as NetworkState<T>) ??
1703
1714
  init()
1704
1715
  );
1705
- }, [JSON.stringify(context.state?.[${"`${source}:${operation}:${key}`"}])]);
1716
+ }, [context.state, key, operation, source]);
1706
1717
 
1707
1718
  const dispatch = useCallback(
1708
1719
  (state: NetworkState<T>) => {
@@ -1750,30 +1761,30 @@ export function useNetworkState<T>({
1750
1761
  signal: abortController.signal,
1751
1762
  };
1752
1763
 
1753
- await context.execute(
1764
+ await contextRef.current.execute(
1754
1765
  requestConfig,
1755
1766
  dispatch,
1756
- schema,
1757
- errorSchema as any,
1767
+ schemaRef.current,
1768
+ errorSchemaRef.current as any,
1758
1769
  );
1759
1770
  },
1760
- [networkState, context.dispatch],
1771
+ [dispatch, key, operation, source],
1761
1772
  );
1762
1773
 
1763
1774
  const deboundedExecute = useMemo(
1764
- () => debounce(execute, debounceDelay ?? 0),
1765
- [execute],
1775
+ () => debounce(execute, debounceDelay),
1776
+ [execute, debounceDelay],
1766
1777
  );
1767
1778
 
1768
1779
  const clear = useCallback(() => {
1769
1780
  logger.info(${"`Clearing request ${key} ${operation} ${source}`"});
1770
1781
  dispatch(init());
1771
- setAbortController((abortController) => {
1782
+ setAbortController((prev) => {
1772
1783
  logger.info(${"`Aborting request ${key} ${operation} ${source}`"});
1773
- abortController?.abort();
1784
+ prev?.abort();
1774
1785
  return undefined;
1775
1786
  });
1776
- }, [dispatch, abortController]);
1787
+ }, [dispatch, key, operation, source]);
1777
1788
 
1778
1789
  return [networkState, deboundedExecute, clear, dispatch];
1779
1790
  }
@@ -1790,6 +1801,14 @@ export function useTransitionCall<T>({
1790
1801
  }): [(request: RequestType) => Promise<T>, () => void] {
1791
1802
  const ctx = useContext(Context);
1792
1803
  const controller = useRef<AbortController | undefined>(undefined);
1804
+
1805
+ const schemaRef = useRef(schema);
1806
+ const errorSchemaRef = useRef(errorSchema);
1807
+
1808
+ useEffect(() => {
1809
+ schemaRef.current = schema;
1810
+ errorSchemaRef.current = errorSchema;
1811
+ });
1793
1812
 
1794
1813
  const call = useCallback(
1795
1814
  async (request: RequestType) => {
@@ -1807,12 +1826,12 @@ export function useTransitionCall<T>({
1807
1826
  reject(state.error);
1808
1827
  }
1809
1828
  },
1810
- schema,
1811
- errorSchema,
1829
+ schemaRef.current,
1830
+ errorSchemaRef.current,
1812
1831
  );
1813
1832
  });
1814
1833
  },
1815
- [ctx, schema, errorSchema],
1834
+ [ctx],
1816
1835
  );
1817
1836
 
1818
1837
  const abort = useCallback(() => {
@@ -2448,7 +2467,7 @@ async function requestHookTemplate({ source, data: { paths, operationId, respons
2448
2467
  const modifiedRequestUrl = `${requestUrl == null ? void 0 : requestUrl.replace(/\{/g, "${")}`;
2449
2468
  const imports = new Set();
2450
2469
  imports.add(`import { z } from 'zod'`);
2451
- imports.add(`import { useCallback, useEffect } from 'react'`);
2470
+ imports.add(`import { useCallback, useEffect, useRef } from 'react'`);
2452
2471
  imports.add(`import {useNetworkState, NetworkState, DispatchState, error, successfulDispatch, validationError, encode, requestValidationError} from "@intrig/react"`);
2453
2472
  const { hookShape, optionsShape } = extractHookShapeAndOptionsShape$1(response, requestBody, imports);
2454
2473
  const { paramExpression, paramType } = extractParamDeconstruction$3(variables != null ? variables : [], requestBody);
@@ -2501,6 +2520,11 @@ async function requestHookTemplate({ source, data: { paths, operationId, respons
2501
2520
  schema,
2502
2521
  errorSchema
2503
2522
  });
2523
+
2524
+ const optionsRef = useRef(options);
2525
+ useEffect(() => {
2526
+ optionsRef.current = options;
2527
+ });
2504
2528
 
2505
2529
  const doExecute = useCallback<(${paramType}) => DispatchState<any>>((${paramExpression}) => {
2506
2530
  const { ${paramExplode}} = p
@@ -2526,22 +2550,22 @@ async function requestHookTemplate({ source, data: { paths, operationId, respons
2526
2550
  ${responseTypePart()}
2527
2551
  })
2528
2552
  return successfulDispatch();
2529
- }, [dispatch])
2553
+ }, [dispatch, dispatchState])
2530
2554
 
2531
2555
  useEffect(() => {
2532
- if (options.fetchOnMount) {
2556
+ if (optionsRef.current.fetchOnMount) {
2533
2557
  doExecute(${[
2534
- requestBody ? `options.body!` : undefined,
2535
- "options.params!"
2558
+ requestBody ? `optionsRef.current.body!` : undefined,
2559
+ "optionsRef.current.params!"
2536
2560
  ].filter((a)=>a).join(",")});
2537
2561
  }
2538
2562
 
2539
2563
  return () => {
2540
- if (options.clearOnUnmount) {
2564
+ if (optionsRef.current.clearOnUnmount) {
2541
2565
  clear();
2542
2566
  }
2543
2567
  }
2544
- }, [])
2568
+ }, [doExecute, clear])
2545
2569
 
2546
2570
  return [
2547
2571
  state,
@@ -2838,7 +2862,7 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2838
2862
  const modifiedRequestUrl = `${requestUrl == null ? void 0 : requestUrl.replace(/\{/g, "${")}`;
2839
2863
  const imports = new Set();
2840
2864
  imports.add(`import { z } from 'zod'`);
2841
- imports.add(`import { useCallback, useEffect } from 'react'`);
2865
+ imports.add(`import { useCallback, useEffect, useRef } from 'react'`);
2842
2866
  imports.add(`import {useNetworkState, NetworkState, DispatchState, pending, success, error, init, successfulDispatch, validationError, encode, isSuccess, requestValidationError} from "@intrig/react"`);
2843
2867
  const { hookShape, optionsShape } = extractHookShapeAndOptionsShape(response, requestBody, imports);
2844
2868
  const { paramExpression, paramType } = extractParamDeconstruction$1(variables, requestBody);
@@ -2884,7 +2908,7 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2884
2908
  const source = "${source}"
2885
2909
 
2886
2910
  function use${pluginSdk.pascalCase(operationId)}Hook(options: ${optionsShape} = {}): [NetworkState<Response>, (${paramType}) => DispatchState<any>, () => void] {
2887
- let [state, dispatch, clear, dispatchState] = useNetworkState<Response>({
2911
+ const [state, dispatch, clear, dispatchState] = useNetworkState<Response>({
2888
2912
  key: options?.key ?? 'default',
2889
2913
  operation,
2890
2914
  source,
@@ -2892,6 +2916,11 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2892
2916
  errorSchema
2893
2917
  });
2894
2918
 
2919
+ const optionsRef = useRef(options);
2920
+ useEffect(() => {
2921
+ optionsRef.current = options;
2922
+ });
2923
+
2895
2924
  useEffect(() => {
2896
2925
  if (isSuccess(state)) {
2897
2926
  let a = document.createElement('a');
@@ -2924,10 +2953,10 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2924
2953
  document.body.removeChild(a);
2925
2954
  dispatchState(init())
2926
2955
  }
2927
- }, [state])
2956
+ }, [state, dispatchState])
2928
2957
 
2929
- let doExecute = useCallback<(${paramType}) => DispatchState<any>>((${paramExpression}) => {
2930
- let { ${paramExplode}} = p
2958
+ const doExecute = useCallback<(${paramType}) => DispatchState<any>>((${paramExpression}) => {
2959
+ const { ${paramExplode}} = p
2931
2960
 
2932
2961
  ${requestBody ? `
2933
2962
  const validationResult = requestBodySchema.safeParse(data);
@@ -2950,22 +2979,22 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2950
2979
  ${responseTypePart()}
2951
2980
  })
2952
2981
  return successfulDispatch();
2953
- }, [dispatch])
2982
+ }, [dispatch, dispatchState])
2954
2983
 
2955
2984
  useEffect(() => {
2956
- if (options.fetchOnMount) {
2985
+ if (optionsRef.current.fetchOnMount) {
2957
2986
  doExecute(${[
2958
- requestBody ? `options.body!` : undefined,
2959
- "options.params!"
2987
+ requestBody ? `optionsRef.current.body!` : undefined,
2988
+ "optionsRef.current.params!"
2960
2989
  ].filter((a)=>a).join(",")});
2961
2990
  }
2962
2991
 
2963
2992
  return () => {
2964
- if (options.clearOnUnmount) {
2993
+ if (optionsRef.current.clearOnUnmount) {
2965
2994
  clear();
2966
2995
  }
2967
2996
  }
2968
- }, [])
2997
+ }, [doExecute, clear]) // Added proper dependencies
2969
2998
 
2970
2999
  return [
2971
3000
  state,
@@ -3582,6 +3611,217 @@ function handleComplexSchema(schema, imports) {
3582
3611
  };
3583
3612
  }
3584
3613
 
3614
+ function serverFunctionDocs(descriptor) {
3615
+ const md = pluginSdk.mdLiteral('server-function.md');
3616
+ var _descriptor_data_variables;
3617
+ // ===== Derived names (preserve these) =====
3618
+ const hasPathParams = ((_descriptor_data_variables = descriptor.data.variables) != null ? _descriptor_data_variables : []).some((v)=>{
3619
+ var _v_in;
3620
+ return ((_v_in = v.in) == null ? void 0 : _v_in.toUpperCase()) === 'PATH';
3621
+ });
3622
+ const actionName = pluginSdk.camelCase(descriptor.name) // e.g. getUser
3623
+ ;
3624
+ const executeActionName = `execute${pluginSdk.pascalCase(descriptor.name)}` // e.g. executeGetUser
3625
+ ;
3626
+ const requestBodyVar = descriptor.data.requestBody ? pluginSdk.camelCase(descriptor.data.requestBody) // e.g. createUser
3627
+ : undefined;
3628
+ const requestBodyType = descriptor.data.requestBody ? pluginSdk.pascalCase(descriptor.data.requestBody) // e.g. CreateUser
3629
+ : undefined;
3630
+ const paramsVar = hasPathParams ? `${actionName}Params` : undefined // e.g. getUserParams
3631
+ ;
3632
+ const paramsType = hasPathParams ? `${pluginSdk.pascalCase(descriptor.name)}Params` : undefined // e.g. GetUserParams
3633
+ ;
3634
+ const responseTypeName = `${pluginSdk.pascalCase(descriptor.name)}Response` // e.g. GetUserResponse
3635
+ ;
3636
+ const callArgs = [
3637
+ requestBodyVar,
3638
+ paramsVar
3639
+ ].filter(Boolean).join(', ');
3640
+ return md`
3641
+ # Server-Side Functions — Quick Guide
3642
+
3643
+ ## Copy-paste starter (fast lane)
3644
+
3645
+ ### 1) Function import (in your Next.js API route or server component)
3646
+ ${"```ts"}
3647
+ import { ${actionName}, ${executeActionName} } from '@intrig/react/${descriptor.path}/server';
3648
+ ${"```"}
3649
+
3650
+ ### 2) Use the async function
3651
+ ${"```ts"}
3652
+ // Simple usage - returns parsed response
3653
+ const result = await ${actionName}(${callArgs});
3654
+
3655
+ // Advanced usage - returns raw data + headers
3656
+ const { data, headers } = await ${executeActionName}(${callArgs});
3657
+ ${"```"}
3658
+
3659
+ Server-side functions are for **Next.js API routes** and **server components**. They return **awaitable promises** that directly call your backend API.
3660
+
3661
+ ---
3662
+
3663
+ ## TL;DR (copy–paste examples)
3664
+
3665
+ ### In API Route (\`pages/api\` or \`app/api\`)
3666
+ ${"```ts"}
3667
+ // pages/api/example.ts or app/api/example/route.ts
3668
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3669
+ import type { NextApiRequest, NextApiResponse } from 'next';
3670
+
3671
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
3672
+ try {
3673
+ const result = await ${actionName}(${callArgs});
3674
+ res.status(200).json(result);
3675
+ } catch (error) {
3676
+ console.error('API call failed:', error);
3677
+ res.status(500).json({ error: 'Internal server error' });
3678
+ }
3679
+ }
3680
+ ${"```"}
3681
+
3682
+ ### In Server Component (App Router)
3683
+ ${"```tsx"}
3684
+ // app/example/page.tsx
3685
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3686
+
3687
+ export default async function ExamplePage() {
3688
+ try {
3689
+ const data = await ${actionName}(${callArgs});
3690
+
3691
+ return (
3692
+ <div>
3693
+ <h1>Server Data</h1>
3694
+ <pre>{JSON.stringify(data, null, 2)}</pre>
3695
+ </div>
3696
+ );
3697
+ } catch (error) {
3698
+ return <div>Error loading data: {error.message}</div>;
3699
+ }
3700
+ }
3701
+ ${"```"}
3702
+
3703
+ ### In Server Action (App Router)
3704
+ ${"```ts"}
3705
+ // app/actions.ts
3706
+ 'use server';
3707
+
3708
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3709
+
3710
+ export async function serverAction(formData: FormData) {
3711
+ try {
3712
+ const result = await ${actionName}(${callArgs});
3713
+ // Process result...
3714
+ return { success: true, data: result };
3715
+ } catch (error) {
3716
+ return { success: false, error: error.message };
3717
+ }
3718
+ }
3719
+ ${"```"}
3720
+
3721
+ ${requestBodyType || paramsType ? `### Optional types (if generated by your build)
3722
+ ${"```ts"}
3723
+ ${requestBodyType ? `import type { ${requestBodyType} } from '@intrig/react/${descriptor.source}/components/schemas/${requestBodyType}';
3724
+ ` : ''}${paramsType ? `import type { ${paramsType} } from '@intrig/react/${descriptor.path}/${pluginSdk.pascalCase(descriptor.name)}.params';
3725
+ ` : ''}import type { ${responseTypeName} } from '@intrig/react/${descriptor.path}/${pluginSdk.pascalCase(descriptor.name)}.response';
3726
+ ${"```"}
3727
+ ` : ''}
3728
+
3729
+ ---
3730
+
3731
+ ## Function API
3732
+
3733
+ ${"```ts"}
3734
+ // Prefer concrete types if your build emits them:
3735
+ // import type { ${responseTypeName} } from '@intrig/react/${descriptor.path}/${pluginSdk.pascalCase(descriptor.name)}.response';
3736
+ // ${paramsType ? `import type { ${paramsType} } from '@intrig/react/${descriptor.path}/${pluginSdk.pascalCase(descriptor.name)}.params';` : ''}
3737
+
3738
+ type ${pluginSdk.pascalCase(descriptor.name)}Data = ${'unknown'}; // replace with ${responseTypeName} if generated
3739
+ type ${pluginSdk.pascalCase(descriptor.name)}Request = {
3740
+ body?: ${requestBodyType != null ? requestBodyType : 'unknown'};
3741
+ params?: ${paramsType != null ? paramsType : 'unknown'};
3742
+ };
3743
+
3744
+ // Main function - returns parsed response
3745
+ declare function ${actionName}(
3746
+ ${requestBodyVar ? `body: ${pluginSdk.pascalCase(descriptor.name)}Request['body'], ` : ''}${paramsVar ? `params: ${pluginSdk.pascalCase(descriptor.name)}Request['params'], ` : ''}options?: AsyncRequestOptions
3747
+ ): Promise<${pluginSdk.pascalCase(descriptor.name)}Data>;
3748
+
3749
+ // Advanced function - returns raw data + headers
3750
+ declare function ${executeActionName}(
3751
+ ${requestBodyVar ? `body: ${pluginSdk.pascalCase(descriptor.name)}Request['body'], ` : ''}${paramsVar ? `params: ${pluginSdk.pascalCase(descriptor.name)}Request['params'], ` : ''}options?: AsyncRequestOptions
3752
+ ): Promise<{ data: any, headers: any }>;
3753
+ ${"```"}
3754
+
3755
+ ### Why server-side functions?
3756
+ - **Server-only execution:** Perfect for Next.js API routes and server components.
3757
+ - **Direct API calls:** No client-side state management needed.
3758
+ - **SSR/SSG friendly:** Use in \`getServerSideProps\`, \`getStaticProps\`, or server components.
3759
+ - **Built-in error handling:** Automatic network and validation error handling.
3760
+
3761
+ ### Options
3762
+ Both functions accept an optional \`options\` parameter:
3763
+
3764
+ ${"```ts"}
3765
+ type AsyncRequestOptions = {
3766
+ hydrate?: boolean; // Cache response for client-side hydration
3767
+ key?: string; // Custom cache key (when hydrate is true)
3768
+ };
3769
+ ${"```"}
3770
+
3771
+ ### Error Handling
3772
+ Server-side functions throw errors for:
3773
+ - **Network errors:** Connection issues, HTTP error status codes
3774
+ - **Validation errors:** Response doesn't match expected schema
3775
+ - **Request errors:** Invalid request body or parameters
3776
+
3777
+ Always wrap calls in try-catch blocks for production use.
3778
+
3779
+ ---
3780
+
3781
+ ## Next.js Integration Patterns
3782
+
3783
+ ### 1. API Routes (Pages Router)
3784
+ Use server functions in your API routes to proxy requests or process data server-side.
3785
+
3786
+ ### 2. Server Components (App Router)
3787
+ Directly call server functions in your server components for SSR data fetching.
3788
+
3789
+ ### 3. Server Actions (App Router)
3790
+ Use server functions within server actions for form submissions and mutations.
3791
+
3792
+ ### 4. Middleware
3793
+ Server functions can be used in Next.js middleware for request preprocessing.
3794
+
3795
+ ### 5. getServerSideProps / getStaticProps (Pages Router)
3796
+ Perfect for data fetching in traditional Next.js data fetching methods.
3797
+
3798
+ ---
3799
+
3800
+ ## Best Practices
3801
+
3802
+ 1. **Error boundaries:** Always handle errors appropriately for your use case
3803
+ 2. **Caching:** Use the \`hydrate\` option for data that should be available client-side
3804
+ 3. **Types:** Import and use the generated TypeScript types for better DX
3805
+ 4. **Logging:** Server functions include built-in logging for debugging
3806
+
3807
+ ${"```ts"}
3808
+ // Example with proper error handling and types
3809
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3810
+ ${paramsType ? `import type { ${paramsType} } from '@intrig/react/${descriptor.path}/${pluginSdk.pascalCase(descriptor.name)}.params';` : ''}
3811
+ import type { ${responseTypeName} } from '@intrig/react/${descriptor.path}/${pluginSdk.pascalCase(descriptor.name)}.response';
3812
+
3813
+ export async function fetchData(${paramsVar ? `params: ${paramsType}` : ''}): Promise<${responseTypeName} | null> {
3814
+ try {
3815
+ return await ${actionName}(${callArgs});
3816
+ } catch (error) {
3817
+ console.error('Failed to fetch data:', error);
3818
+ return null;
3819
+ }
3820
+ }
3821
+ ${"```"}
3822
+ `;
3823
+ }
3824
+
3585
3825
  async function generateCode(ctx) {
3586
3826
  // Root/project files
3587
3827
  await ctx.dump(packageJsonTemplate(ctx));
@@ -3615,6 +3855,7 @@ async function generateCode(ctx) {
3615
3855
  await ctx.dump(paramsTemplate(restDescriptor));
3616
3856
  await ctx.dump(asyncFunctionHookTemplate(restDescriptor, internalGeneratorContext));
3617
3857
  await ctx.dump(nextRequestMethodTemplate(restDescriptor, internalGeneratorContext));
3858
+ await ctx.dump(serverFunctionDocs(restDescriptor));
3618
3859
  if (restDescriptor.data.isDownloadable) {
3619
3860
  await ctx.dump(downloadHookTemplate(restDescriptor, internalGeneratorContext));
3620
3861
  }
@@ -3660,12 +3901,12 @@ Use this TypeScript type anywhere you need static typing for this object shape i
3660
3901
 
3661
3902
  ## Import
3662
3903
  ${'```ts'}
3663
- ${importContent}
3904
+ ${importContent.content}
3664
3905
  ${'```'}
3665
3906
 
3666
3907
  ## Definition
3667
3908
  ${'```ts'}
3668
- ${codeContent}
3909
+ ${codeContent.content}
3669
3910
  ${'```'}
3670
3911
  `;
3671
3912
  }
@@ -3687,12 +3928,12 @@ Use this JSON Schema with tools that consume JSON Schema: UI form builders (e.g.
3687
3928
 
3688
3929
  ## Import
3689
3930
  ${'```ts'}
3690
- ${importContent}
3931
+ ${importContent.content}
3691
3932
  ${'```'}
3692
3933
 
3693
3934
  ## Definition
3694
3935
  ${'```ts'}
3695
- ${codeContent}
3936
+ ${codeContent.content}
3696
3937
  ${'```'}
3697
3938
  `;
3698
3939
  }
@@ -3714,12 +3955,12 @@ Use this Zod schema for runtime validation and parsing: form validation, client/
3714
3955
 
3715
3956
  ## Import
3716
3957
  ${'```ts'}
3717
- ${importContent}
3958
+ ${importContent.content}
3718
3959
  ${'```'}
3719
3960
 
3720
3961
  ## Definition
3721
3962
  ${'```ts'}
3722
- ${codeContent}
3963
+ ${codeContent.content}
3723
3964
  ${'```'}
3724
3965
  `;
3725
3966
  }
@@ -4734,37 +4975,19 @@ function updateGitIgnore(rootDir, entryToAdd) {
4734
4975
  fs__namespace.writeFileSync(gitIgnorePath, gitIgnoreContent.join('\n'), 'utf-8');
4735
4976
  }
4736
4977
  }
4737
- function updateIntrigConfig(rootDir, apiRoutesDir) {
4738
- const configPath = path__namespace.resolve(rootDir, 'intrig.config.json');
4739
- if (fs__namespace.existsSync(configPath)) {
4740
- const config = JSON.parse(fs__namespace.readFileSync(configPath, 'utf-8'));
4741
- config.generatorOptions = config.generatorOptions || {};
4742
- config.generatorOptions.apiRoutesDir = apiRoutesDir;
4743
- fs__namespace.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
4744
- }
4745
- }
4746
4978
  async function initPlugin(ctx) {
4747
- const { rootDir } = ctx;
4748
- const defaultApiDir = path__namespace.resolve(rootDir, 'src/app/api');
4749
- if (fs__namespace.existsSync(defaultApiDir)) {
4750
- // Default src/app/api directory exists, add (generated) to gitignore
4751
- updateGitIgnore(rootDir, 'src/app/api/(generated)');
4752
- } else {
4753
- // Ask user for apiRoutesDir
4754
- const { apiRoutesDir } = await inquirer.prompt([
4755
- {
4756
- type: 'input',
4757
- name: 'apiRoutesDir',
4758
- message: 'Enter the API routes directory path:',
4759
- default: 'src/app/api',
4760
- validate: (input)=>input.trim().length > 0 || 'Please enter a valid directory path'
4761
- }
4762
- ]);
4763
- // Update intrig.config.json with the apiRoutesDir value
4764
- updateIntrigConfig(rootDir, apiRoutesDir);
4765
- // Add the directory with (generated) to gitignore
4766
- updateGitIgnore(rootDir, `${apiRoutesDir}/(generated)`);
4767
- }
4979
+ const { rootDir, options } = ctx;
4980
+ const apiRoutesDir = (options == null ? void 0 : options.apiRoutesDir) || 'src/app/api';
4981
+ // Add the directory with (generated) to gitignore
4982
+ updateGitIgnore(rootDir, `${apiRoutesDir}/(generated)`);
4983
+ return {
4984
+ postInit: ()=>{
4985
+ console.log(chalk.blue('\nšŸ“‹ Next Steps:'));
4986
+ console.log(chalk.white('To complete your Next.js setup, please refer to the post-initialization instructions at:'));
4987
+ console.log(chalk.cyan('https://intrig.dev/docs/next/initialization#3-post-initialization-steps'));
4988
+ console.log(chalk.gray('\nThis guide will show you how to add IntrigProvider to your Next.js application.\n'));
4989
+ }
4990
+ };
4768
4991
  }
4769
4992
 
4770
4993
  async function postBuild(ctx) {
@@ -4859,7 +5082,8 @@ const $generatorSchema = {
4859
5082
  properties: {
4860
5083
  "apiRoutesDir": {
4861
5084
  type: 'string',
4862
- description: 'The directory where the API routes are stored.'
5085
+ description: 'The directory where the API routes are stored.',
5086
+ default: 'src/app/api'
4863
5087
  }
4864
5088
  }
4865
5089
  };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import * as fsx from 'fs-extra';
5
5
  import * as mimeType from 'mime-types';
6
6
  import * as _ from 'lodash';
7
7
  import * as fs from 'fs';
8
- import inquirer from 'inquirer';
8
+ import chalk from 'chalk';
9
9
 
10
10
  class InternalGeneratorContext {
11
11
  getCounter(sourceId) {
@@ -1625,6 +1625,7 @@ function providerHooksTemplate() {
1625
1625
  useMemo,
1626
1626
  useState,
1627
1627
  useRef,
1628
+ useEffect,
1628
1629
  } from 'react';
1629
1630
  import {
1630
1631
  ErrorState,
@@ -1668,6 +1669,16 @@ export function useNetworkState<T>({
1668
1669
  const context = useContext(Context);
1669
1670
 
1670
1671
  const [abortController, setAbortController] = useState<AbortController>();
1672
+
1673
+ const contextRef = useRef(context);
1674
+ const schemaRef = useRef(schema);
1675
+ const errorSchemaRef = useRef(errorSchema);
1676
+
1677
+ useEffect(() => {
1678
+ contextRef.current = context;
1679
+ schemaRef.current = schema;
1680
+ errorSchemaRef.current = errorSchema;
1681
+ });
1671
1682
 
1672
1683
  const networkState = useMemo(() => {
1673
1684
  logger.info(${"`Updating status ${key} ${operation} ${source}`"});
@@ -1676,7 +1687,7 @@ export function useNetworkState<T>({
1676
1687
  (context.state?.[${"`${source}:${operation}:${key}`"}] as NetworkState<T>) ??
1677
1688
  init()
1678
1689
  );
1679
- }, [JSON.stringify(context.state?.[${"`${source}:${operation}:${key}`"}])]);
1690
+ }, [context.state, key, operation, source]);
1680
1691
 
1681
1692
  const dispatch = useCallback(
1682
1693
  (state: NetworkState<T>) => {
@@ -1724,30 +1735,30 @@ export function useNetworkState<T>({
1724
1735
  signal: abortController.signal,
1725
1736
  };
1726
1737
 
1727
- await context.execute(
1738
+ await contextRef.current.execute(
1728
1739
  requestConfig,
1729
1740
  dispatch,
1730
- schema,
1731
- errorSchema as any,
1741
+ schemaRef.current,
1742
+ errorSchemaRef.current as any,
1732
1743
  );
1733
1744
  },
1734
- [networkState, context.dispatch],
1745
+ [dispatch, key, operation, source],
1735
1746
  );
1736
1747
 
1737
1748
  const deboundedExecute = useMemo(
1738
- () => debounce(execute, debounceDelay ?? 0),
1739
- [execute],
1749
+ () => debounce(execute, debounceDelay),
1750
+ [execute, debounceDelay],
1740
1751
  );
1741
1752
 
1742
1753
  const clear = useCallback(() => {
1743
1754
  logger.info(${"`Clearing request ${key} ${operation} ${source}`"});
1744
1755
  dispatch(init());
1745
- setAbortController((abortController) => {
1756
+ setAbortController((prev) => {
1746
1757
  logger.info(${"`Aborting request ${key} ${operation} ${source}`"});
1747
- abortController?.abort();
1758
+ prev?.abort();
1748
1759
  return undefined;
1749
1760
  });
1750
- }, [dispatch, abortController]);
1761
+ }, [dispatch, key, operation, source]);
1751
1762
 
1752
1763
  return [networkState, deboundedExecute, clear, dispatch];
1753
1764
  }
@@ -1764,6 +1775,14 @@ export function useTransitionCall<T>({
1764
1775
  }): [(request: RequestType) => Promise<T>, () => void] {
1765
1776
  const ctx = useContext(Context);
1766
1777
  const controller = useRef<AbortController | undefined>(undefined);
1778
+
1779
+ const schemaRef = useRef(schema);
1780
+ const errorSchemaRef = useRef(errorSchema);
1781
+
1782
+ useEffect(() => {
1783
+ schemaRef.current = schema;
1784
+ errorSchemaRef.current = errorSchema;
1785
+ });
1767
1786
 
1768
1787
  const call = useCallback(
1769
1788
  async (request: RequestType) => {
@@ -1781,12 +1800,12 @@ export function useTransitionCall<T>({
1781
1800
  reject(state.error);
1782
1801
  }
1783
1802
  },
1784
- schema,
1785
- errorSchema,
1803
+ schemaRef.current,
1804
+ errorSchemaRef.current,
1786
1805
  );
1787
1806
  });
1788
1807
  },
1789
- [ctx, schema, errorSchema],
1808
+ [ctx],
1790
1809
  );
1791
1810
 
1792
1811
  const abort = useCallback(() => {
@@ -2422,7 +2441,7 @@ async function requestHookTemplate({ source, data: { paths, operationId, respons
2422
2441
  const modifiedRequestUrl = `${requestUrl == null ? void 0 : requestUrl.replace(/\{/g, "${")}`;
2423
2442
  const imports = new Set();
2424
2443
  imports.add(`import { z } from 'zod'`);
2425
- imports.add(`import { useCallback, useEffect } from 'react'`);
2444
+ imports.add(`import { useCallback, useEffect, useRef } from 'react'`);
2426
2445
  imports.add(`import {useNetworkState, NetworkState, DispatchState, error, successfulDispatch, validationError, encode, requestValidationError} from "@intrig/react"`);
2427
2446
  const { hookShape, optionsShape } = extractHookShapeAndOptionsShape$1(response, requestBody, imports);
2428
2447
  const { paramExpression, paramType } = extractParamDeconstruction$3(variables != null ? variables : [], requestBody);
@@ -2475,6 +2494,11 @@ async function requestHookTemplate({ source, data: { paths, operationId, respons
2475
2494
  schema,
2476
2495
  errorSchema
2477
2496
  });
2497
+
2498
+ const optionsRef = useRef(options);
2499
+ useEffect(() => {
2500
+ optionsRef.current = options;
2501
+ });
2478
2502
 
2479
2503
  const doExecute = useCallback<(${paramType}) => DispatchState<any>>((${paramExpression}) => {
2480
2504
  const { ${paramExplode}} = p
@@ -2500,22 +2524,22 @@ async function requestHookTemplate({ source, data: { paths, operationId, respons
2500
2524
  ${responseTypePart()}
2501
2525
  })
2502
2526
  return successfulDispatch();
2503
- }, [dispatch])
2527
+ }, [dispatch, dispatchState])
2504
2528
 
2505
2529
  useEffect(() => {
2506
- if (options.fetchOnMount) {
2530
+ if (optionsRef.current.fetchOnMount) {
2507
2531
  doExecute(${[
2508
- requestBody ? `options.body!` : undefined,
2509
- "options.params!"
2532
+ requestBody ? `optionsRef.current.body!` : undefined,
2533
+ "optionsRef.current.params!"
2510
2534
  ].filter((a)=>a).join(",")});
2511
2535
  }
2512
2536
 
2513
2537
  return () => {
2514
- if (options.clearOnUnmount) {
2538
+ if (optionsRef.current.clearOnUnmount) {
2515
2539
  clear();
2516
2540
  }
2517
2541
  }
2518
- }, [])
2542
+ }, [doExecute, clear])
2519
2543
 
2520
2544
  return [
2521
2545
  state,
@@ -2812,7 +2836,7 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2812
2836
  const modifiedRequestUrl = `${requestUrl == null ? void 0 : requestUrl.replace(/\{/g, "${")}`;
2813
2837
  const imports = new Set();
2814
2838
  imports.add(`import { z } from 'zod'`);
2815
- imports.add(`import { useCallback, useEffect } from 'react'`);
2839
+ imports.add(`import { useCallback, useEffect, useRef } from 'react'`);
2816
2840
  imports.add(`import {useNetworkState, NetworkState, DispatchState, pending, success, error, init, successfulDispatch, validationError, encode, isSuccess, requestValidationError} from "@intrig/react"`);
2817
2841
  const { hookShape, optionsShape } = extractHookShapeAndOptionsShape(response, requestBody, imports);
2818
2842
  const { paramExpression, paramType } = extractParamDeconstruction$1(variables, requestBody);
@@ -2858,7 +2882,7 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2858
2882
  const source = "${source}"
2859
2883
 
2860
2884
  function use${pascalCase(operationId)}Hook(options: ${optionsShape} = {}): [NetworkState<Response>, (${paramType}) => DispatchState<any>, () => void] {
2861
- let [state, dispatch, clear, dispatchState] = useNetworkState<Response>({
2885
+ const [state, dispatch, clear, dispatchState] = useNetworkState<Response>({
2862
2886
  key: options?.key ?? 'default',
2863
2887
  operation,
2864
2888
  source,
@@ -2866,6 +2890,11 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2866
2890
  errorSchema
2867
2891
  });
2868
2892
 
2893
+ const optionsRef = useRef(options);
2894
+ useEffect(() => {
2895
+ optionsRef.current = options;
2896
+ });
2897
+
2869
2898
  useEffect(() => {
2870
2899
  if (isSuccess(state)) {
2871
2900
  let a = document.createElement('a');
@@ -2898,10 +2927,10 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2898
2927
  document.body.removeChild(a);
2899
2928
  dispatchState(init())
2900
2929
  }
2901
- }, [state])
2930
+ }, [state, dispatchState])
2902
2931
 
2903
- let doExecute = useCallback<(${paramType}) => DispatchState<any>>((${paramExpression}) => {
2904
- let { ${paramExplode}} = p
2932
+ const doExecute = useCallback<(${paramType}) => DispatchState<any>>((${paramExpression}) => {
2933
+ const { ${paramExplode}} = p
2905
2934
 
2906
2935
  ${requestBody ? `
2907
2936
  const validationResult = requestBodySchema.safeParse(data);
@@ -2924,22 +2953,22 @@ async function downloadHookTemplate({ source, data: { paths, operationId, respon
2924
2953
  ${responseTypePart()}
2925
2954
  })
2926
2955
  return successfulDispatch();
2927
- }, [dispatch])
2956
+ }, [dispatch, dispatchState])
2928
2957
 
2929
2958
  useEffect(() => {
2930
- if (options.fetchOnMount) {
2959
+ if (optionsRef.current.fetchOnMount) {
2931
2960
  doExecute(${[
2932
- requestBody ? `options.body!` : undefined,
2933
- "options.params!"
2961
+ requestBody ? `optionsRef.current.body!` : undefined,
2962
+ "optionsRef.current.params!"
2934
2963
  ].filter((a)=>a).join(",")});
2935
2964
  }
2936
2965
 
2937
2966
  return () => {
2938
- if (options.clearOnUnmount) {
2967
+ if (optionsRef.current.clearOnUnmount) {
2939
2968
  clear();
2940
2969
  }
2941
2970
  }
2942
- }, [])
2971
+ }, [doExecute, clear]) // Added proper dependencies
2943
2972
 
2944
2973
  return [
2945
2974
  state,
@@ -3556,6 +3585,217 @@ function handleComplexSchema(schema, imports) {
3556
3585
  };
3557
3586
  }
3558
3587
 
3588
+ function serverFunctionDocs(descriptor) {
3589
+ const md = mdLiteral('server-function.md');
3590
+ var _descriptor_data_variables;
3591
+ // ===== Derived names (preserve these) =====
3592
+ const hasPathParams = ((_descriptor_data_variables = descriptor.data.variables) != null ? _descriptor_data_variables : []).some((v)=>{
3593
+ var _v_in;
3594
+ return ((_v_in = v.in) == null ? void 0 : _v_in.toUpperCase()) === 'PATH';
3595
+ });
3596
+ const actionName = camelCase(descriptor.name) // e.g. getUser
3597
+ ;
3598
+ const executeActionName = `execute${pascalCase(descriptor.name)}` // e.g. executeGetUser
3599
+ ;
3600
+ const requestBodyVar = descriptor.data.requestBody ? camelCase(descriptor.data.requestBody) // e.g. createUser
3601
+ : undefined;
3602
+ const requestBodyType = descriptor.data.requestBody ? pascalCase(descriptor.data.requestBody) // e.g. CreateUser
3603
+ : undefined;
3604
+ const paramsVar = hasPathParams ? `${actionName}Params` : undefined // e.g. getUserParams
3605
+ ;
3606
+ const paramsType = hasPathParams ? `${pascalCase(descriptor.name)}Params` : undefined // e.g. GetUserParams
3607
+ ;
3608
+ const responseTypeName = `${pascalCase(descriptor.name)}Response` // e.g. GetUserResponse
3609
+ ;
3610
+ const callArgs = [
3611
+ requestBodyVar,
3612
+ paramsVar
3613
+ ].filter(Boolean).join(', ');
3614
+ return md`
3615
+ # Server-Side Functions — Quick Guide
3616
+
3617
+ ## Copy-paste starter (fast lane)
3618
+
3619
+ ### 1) Function import (in your Next.js API route or server component)
3620
+ ${"```ts"}
3621
+ import { ${actionName}, ${executeActionName} } from '@intrig/react/${descriptor.path}/server';
3622
+ ${"```"}
3623
+
3624
+ ### 2) Use the async function
3625
+ ${"```ts"}
3626
+ // Simple usage - returns parsed response
3627
+ const result = await ${actionName}(${callArgs});
3628
+
3629
+ // Advanced usage - returns raw data + headers
3630
+ const { data, headers } = await ${executeActionName}(${callArgs});
3631
+ ${"```"}
3632
+
3633
+ Server-side functions are for **Next.js API routes** and **server components**. They return **awaitable promises** that directly call your backend API.
3634
+
3635
+ ---
3636
+
3637
+ ## TL;DR (copy–paste examples)
3638
+
3639
+ ### In API Route (\`pages/api\` or \`app/api\`)
3640
+ ${"```ts"}
3641
+ // pages/api/example.ts or app/api/example/route.ts
3642
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3643
+ import type { NextApiRequest, NextApiResponse } from 'next';
3644
+
3645
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
3646
+ try {
3647
+ const result = await ${actionName}(${callArgs});
3648
+ res.status(200).json(result);
3649
+ } catch (error) {
3650
+ console.error('API call failed:', error);
3651
+ res.status(500).json({ error: 'Internal server error' });
3652
+ }
3653
+ }
3654
+ ${"```"}
3655
+
3656
+ ### In Server Component (App Router)
3657
+ ${"```tsx"}
3658
+ // app/example/page.tsx
3659
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3660
+
3661
+ export default async function ExamplePage() {
3662
+ try {
3663
+ const data = await ${actionName}(${callArgs});
3664
+
3665
+ return (
3666
+ <div>
3667
+ <h1>Server Data</h1>
3668
+ <pre>{JSON.stringify(data, null, 2)}</pre>
3669
+ </div>
3670
+ );
3671
+ } catch (error) {
3672
+ return <div>Error loading data: {error.message}</div>;
3673
+ }
3674
+ }
3675
+ ${"```"}
3676
+
3677
+ ### In Server Action (App Router)
3678
+ ${"```ts"}
3679
+ // app/actions.ts
3680
+ 'use server';
3681
+
3682
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3683
+
3684
+ export async function serverAction(formData: FormData) {
3685
+ try {
3686
+ const result = await ${actionName}(${callArgs});
3687
+ // Process result...
3688
+ return { success: true, data: result };
3689
+ } catch (error) {
3690
+ return { success: false, error: error.message };
3691
+ }
3692
+ }
3693
+ ${"```"}
3694
+
3695
+ ${requestBodyType || paramsType ? `### Optional types (if generated by your build)
3696
+ ${"```ts"}
3697
+ ${requestBodyType ? `import type { ${requestBodyType} } from '@intrig/react/${descriptor.source}/components/schemas/${requestBodyType}';
3698
+ ` : ''}${paramsType ? `import type { ${paramsType} } from '@intrig/react/${descriptor.path}/${pascalCase(descriptor.name)}.params';
3699
+ ` : ''}import type { ${responseTypeName} } from '@intrig/react/${descriptor.path}/${pascalCase(descriptor.name)}.response';
3700
+ ${"```"}
3701
+ ` : ''}
3702
+
3703
+ ---
3704
+
3705
+ ## Function API
3706
+
3707
+ ${"```ts"}
3708
+ // Prefer concrete types if your build emits them:
3709
+ // import type { ${responseTypeName} } from '@intrig/react/${descriptor.path}/${pascalCase(descriptor.name)}.response';
3710
+ // ${paramsType ? `import type { ${paramsType} } from '@intrig/react/${descriptor.path}/${pascalCase(descriptor.name)}.params';` : ''}
3711
+
3712
+ type ${pascalCase(descriptor.name)}Data = ${'unknown'}; // replace with ${responseTypeName} if generated
3713
+ type ${pascalCase(descriptor.name)}Request = {
3714
+ body?: ${requestBodyType != null ? requestBodyType : 'unknown'};
3715
+ params?: ${paramsType != null ? paramsType : 'unknown'};
3716
+ };
3717
+
3718
+ // Main function - returns parsed response
3719
+ declare function ${actionName}(
3720
+ ${requestBodyVar ? `body: ${pascalCase(descriptor.name)}Request['body'], ` : ''}${paramsVar ? `params: ${pascalCase(descriptor.name)}Request['params'], ` : ''}options?: AsyncRequestOptions
3721
+ ): Promise<${pascalCase(descriptor.name)}Data>;
3722
+
3723
+ // Advanced function - returns raw data + headers
3724
+ declare function ${executeActionName}(
3725
+ ${requestBodyVar ? `body: ${pascalCase(descriptor.name)}Request['body'], ` : ''}${paramsVar ? `params: ${pascalCase(descriptor.name)}Request['params'], ` : ''}options?: AsyncRequestOptions
3726
+ ): Promise<{ data: any, headers: any }>;
3727
+ ${"```"}
3728
+
3729
+ ### Why server-side functions?
3730
+ - **Server-only execution:** Perfect for Next.js API routes and server components.
3731
+ - **Direct API calls:** No client-side state management needed.
3732
+ - **SSR/SSG friendly:** Use in \`getServerSideProps\`, \`getStaticProps\`, or server components.
3733
+ - **Built-in error handling:** Automatic network and validation error handling.
3734
+
3735
+ ### Options
3736
+ Both functions accept an optional \`options\` parameter:
3737
+
3738
+ ${"```ts"}
3739
+ type AsyncRequestOptions = {
3740
+ hydrate?: boolean; // Cache response for client-side hydration
3741
+ key?: string; // Custom cache key (when hydrate is true)
3742
+ };
3743
+ ${"```"}
3744
+
3745
+ ### Error Handling
3746
+ Server-side functions throw errors for:
3747
+ - **Network errors:** Connection issues, HTTP error status codes
3748
+ - **Validation errors:** Response doesn't match expected schema
3749
+ - **Request errors:** Invalid request body or parameters
3750
+
3751
+ Always wrap calls in try-catch blocks for production use.
3752
+
3753
+ ---
3754
+
3755
+ ## Next.js Integration Patterns
3756
+
3757
+ ### 1. API Routes (Pages Router)
3758
+ Use server functions in your API routes to proxy requests or process data server-side.
3759
+
3760
+ ### 2. Server Components (App Router)
3761
+ Directly call server functions in your server components for SSR data fetching.
3762
+
3763
+ ### 3. Server Actions (App Router)
3764
+ Use server functions within server actions for form submissions and mutations.
3765
+
3766
+ ### 4. Middleware
3767
+ Server functions can be used in Next.js middleware for request preprocessing.
3768
+
3769
+ ### 5. getServerSideProps / getStaticProps (Pages Router)
3770
+ Perfect for data fetching in traditional Next.js data fetching methods.
3771
+
3772
+ ---
3773
+
3774
+ ## Best Practices
3775
+
3776
+ 1. **Error boundaries:** Always handle errors appropriately for your use case
3777
+ 2. **Caching:** Use the \`hydrate\` option for data that should be available client-side
3778
+ 3. **Types:** Import and use the generated TypeScript types for better DX
3779
+ 4. **Logging:** Server functions include built-in logging for debugging
3780
+
3781
+ ${"```ts"}
3782
+ // Example with proper error handling and types
3783
+ import { ${actionName} } from '@intrig/react/${descriptor.path}/server';
3784
+ ${paramsType ? `import type { ${paramsType} } from '@intrig/react/${descriptor.path}/${pascalCase(descriptor.name)}.params';` : ''}
3785
+ import type { ${responseTypeName} } from '@intrig/react/${descriptor.path}/${pascalCase(descriptor.name)}.response';
3786
+
3787
+ export async function fetchData(${paramsVar ? `params: ${paramsType}` : ''}): Promise<${responseTypeName} | null> {
3788
+ try {
3789
+ return await ${actionName}(${callArgs});
3790
+ } catch (error) {
3791
+ console.error('Failed to fetch data:', error);
3792
+ return null;
3793
+ }
3794
+ }
3795
+ ${"```"}
3796
+ `;
3797
+ }
3798
+
3559
3799
  async function generateCode(ctx) {
3560
3800
  // Root/project files
3561
3801
  await ctx.dump(packageJsonTemplate(ctx));
@@ -3589,6 +3829,7 @@ async function generateCode(ctx) {
3589
3829
  await ctx.dump(paramsTemplate(restDescriptor));
3590
3830
  await ctx.dump(asyncFunctionHookTemplate(restDescriptor, internalGeneratorContext));
3591
3831
  await ctx.dump(nextRequestMethodTemplate(restDescriptor, internalGeneratorContext));
3832
+ await ctx.dump(serverFunctionDocs(restDescriptor));
3592
3833
  if (restDescriptor.data.isDownloadable) {
3593
3834
  await ctx.dump(downloadHookTemplate(restDescriptor, internalGeneratorContext));
3594
3835
  }
@@ -3634,12 +3875,12 @@ Use this TypeScript type anywhere you need static typing for this object shape i
3634
3875
 
3635
3876
  ## Import
3636
3877
  ${'```ts'}
3637
- ${importContent}
3878
+ ${importContent.content}
3638
3879
  ${'```'}
3639
3880
 
3640
3881
  ## Definition
3641
3882
  ${'```ts'}
3642
- ${codeContent}
3883
+ ${codeContent.content}
3643
3884
  ${'```'}
3644
3885
  `;
3645
3886
  }
@@ -3661,12 +3902,12 @@ Use this JSON Schema with tools that consume JSON Schema: UI form builders (e.g.
3661
3902
 
3662
3903
  ## Import
3663
3904
  ${'```ts'}
3664
- ${importContent}
3905
+ ${importContent.content}
3665
3906
  ${'```'}
3666
3907
 
3667
3908
  ## Definition
3668
3909
  ${'```ts'}
3669
- ${codeContent}
3910
+ ${codeContent.content}
3670
3911
  ${'```'}
3671
3912
  `;
3672
3913
  }
@@ -3688,12 +3929,12 @@ Use this Zod schema for runtime validation and parsing: form validation, client/
3688
3929
 
3689
3930
  ## Import
3690
3931
  ${'```ts'}
3691
- ${importContent}
3932
+ ${importContent.content}
3692
3933
  ${'```'}
3693
3934
 
3694
3935
  ## Definition
3695
3936
  ${'```ts'}
3696
- ${codeContent}
3937
+ ${codeContent.content}
3697
3938
  ${'```'}
3698
3939
  `;
3699
3940
  }
@@ -4708,37 +4949,19 @@ function updateGitIgnore(rootDir, entryToAdd) {
4708
4949
  fs.writeFileSync(gitIgnorePath, gitIgnoreContent.join('\n'), 'utf-8');
4709
4950
  }
4710
4951
  }
4711
- function updateIntrigConfig(rootDir, apiRoutesDir) {
4712
- const configPath = path.resolve(rootDir, 'intrig.config.json');
4713
- if (fs.existsSync(configPath)) {
4714
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
4715
- config.generatorOptions = config.generatorOptions || {};
4716
- config.generatorOptions.apiRoutesDir = apiRoutesDir;
4717
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
4718
- }
4719
- }
4720
4952
  async function initPlugin(ctx) {
4721
- const { rootDir } = ctx;
4722
- const defaultApiDir = path.resolve(rootDir, 'src/app/api');
4723
- if (fs.existsSync(defaultApiDir)) {
4724
- // Default src/app/api directory exists, add (generated) to gitignore
4725
- updateGitIgnore(rootDir, 'src/app/api/(generated)');
4726
- } else {
4727
- // Ask user for apiRoutesDir
4728
- const { apiRoutesDir } = await inquirer.prompt([
4729
- {
4730
- type: 'input',
4731
- name: 'apiRoutesDir',
4732
- message: 'Enter the API routes directory path:',
4733
- default: 'src/app/api',
4734
- validate: (input)=>input.trim().length > 0 || 'Please enter a valid directory path'
4735
- }
4736
- ]);
4737
- // Update intrig.config.json with the apiRoutesDir value
4738
- updateIntrigConfig(rootDir, apiRoutesDir);
4739
- // Add the directory with (generated) to gitignore
4740
- updateGitIgnore(rootDir, `${apiRoutesDir}/(generated)`);
4741
- }
4953
+ const { rootDir, options } = ctx;
4954
+ const apiRoutesDir = (options == null ? void 0 : options.apiRoutesDir) || 'src/app/api';
4955
+ // Add the directory with (generated) to gitignore
4956
+ updateGitIgnore(rootDir, `${apiRoutesDir}/(generated)`);
4957
+ return {
4958
+ postInit: ()=>{
4959
+ console.log(chalk.blue('\nšŸ“‹ Next Steps:'));
4960
+ console.log(chalk.white('To complete your Next.js setup, please refer to the post-initialization instructions at:'));
4961
+ console.log(chalk.cyan('https://intrig.dev/docs/next/initialization#3-post-initialization-steps'));
4962
+ console.log(chalk.gray('\nThis guide will show you how to add IntrigProvider to your Next.js application.\n'));
4963
+ }
4964
+ };
4742
4965
  }
4743
4966
 
4744
4967
  async function postBuild(ctx) {
@@ -4833,7 +5056,8 @@ const $generatorSchema = {
4833
5056
  properties: {
4834
5057
  "apiRoutesDir": {
4835
5058
  type: 'string',
4836
- description: 'The directory where the API routes are stored.'
5059
+ description: 'The directory where the API routes are stored.',
5060
+ default: 'src/app/api'
4837
5061
  }
4838
5062
  }
4839
5063
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intrig/plugin-next",
3
- "version": "0.0.2-1",
3
+ "version": "0.0.2-3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -15,9 +15,8 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
- "@intrig/plugin-sdk": "^0.0.2-4",
19
- "@swc/helpers": "~0.5.11",
20
- "inquirer": "^9.0.0"
18
+ "@intrig/plugin-sdk": "^0.0.2-6",
19
+ "@swc/helpers": "~0.5.11"
21
20
  },
22
21
  "files": [
23
22
  "dist",