routesync 1.0.14 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -8689,11 +8689,11 @@ var SDKGenerator = class _SDKGenerator {
8689
8689
  if (r.startsWith("min:")) min = r.split(":")[1];
8690
8690
  if (r.startsWith("max:")) max = r.split(":")[1];
8691
8691
  }
8692
- let zType = "z.any()";
8692
+ let zType = "z.unknown()";
8693
8693
  if (isString) zType = "z.string()";
8694
8694
  else if (isNumeric) zType = "z.number()";
8695
8695
  else if (isBoolean) zType = "z.boolean()";
8696
- else if (isArray) zType = "z.array(z.any())";
8696
+ else if (isArray) zType = "z.array(z.unknown())";
8697
8697
  else if (isEmail) zType = "z.string()";
8698
8698
  if (isEmail && zType === "z.string()") zType += ".email()";
8699
8699
  if (min && !isNaN(Number(min))) zType += `.min(${min})`;
@@ -8742,18 +8742,32 @@ var TypeGenerator = class {
8742
8742
  lines.push(` status?: number`);
8743
8743
  lines.push(`}`);
8744
8744
  lines.push(``);
8745
- const resources = new Set(
8746
- manifest.routes.map((r) => r.path.replace(/^\//, "").split("/")[0])
8747
- );
8748
- for (const resource of resources) {
8749
- const typeName = toTypeName(resource ?? "");
8750
- lines.push(`export interface ${typeName} {`);
8751
- lines.push(` id: number`);
8752
- lines.push(` // TODO: Add ${resource} fields`);
8753
- lines.push(` created_at?: string`);
8754
- lines.push(` updated_at?: string`);
8755
- lines.push(`}`);
8756
- lines.push(``);
8745
+ if (manifest.models && manifest.models.length > 0) {
8746
+ for (const model of manifest.models) {
8747
+ lines.push(`export interface ${model.name} {`);
8748
+ for (const col of model.columns) {
8749
+ if (model.hidden && model.hidden.includes(col.name)) continue;
8750
+ const tsType = this.mapSqlTypeToTs(col.type);
8751
+ const isOptional = col.nullable ? "?" : "";
8752
+ lines.push(` ${col.name}${isOptional}: ${tsType}`);
8753
+ }
8754
+ lines.push(`}`);
8755
+ lines.push(``);
8756
+ }
8757
+ } else {
8758
+ const resources = new Set(
8759
+ manifest.routes.map((r) => r.path.replace(/^\//, "").split("/")[0])
8760
+ );
8761
+ for (const resource of resources) {
8762
+ const typeName = toTypeName(resource ?? "");
8763
+ lines.push(`export interface ${typeName} {`);
8764
+ lines.push(` id: number`);
8765
+ lines.push(` // TODO: Add ${resource} fields`);
8766
+ lines.push(` created_at?: string`);
8767
+ lines.push(` updated_at?: string`);
8768
+ lines.push(`}`);
8769
+ lines.push(``);
8770
+ }
8757
8771
  }
8758
8772
  if (hasSchemas) {
8759
8773
  for (const route of manifest.routes) {
@@ -8773,9 +8787,9 @@ var TypeGenerator = class {
8773
8787
  }
8774
8788
  if (ruleStr.includes("email")) zodRule += ".email()";
8775
8789
  if (ruleStr.includes("url")) zodRule += ".url()";
8776
- const matchMin = ruleStr.match(/min:(\\d+)/);
8790
+ const matchMin = ruleStr.match(/min:(\d+)/);
8777
8791
  if (matchMin) zodRule += ".min(" + matchMin[1] + ")";
8778
- const matchMax = ruleStr.match(/max:(\\d+)/);
8792
+ const matchMax = ruleStr.match(/max:(\d+)/);
8779
8793
  if (matchMax) zodRule += ".max(" + matchMax[1] + ")";
8780
8794
  if (!ruleStr.includes("required")) {
8781
8795
  zodRule += ".optional()";
@@ -8793,6 +8807,13 @@ var TypeGenerator = class {
8793
8807
  }
8794
8808
  await import_fs_extra4.default.writeFile(import_path3.default.join(outputDir, "types.ts"), lines.join("\n"));
8795
8809
  }
8810
+ static mapSqlTypeToTs(sqlType) {
8811
+ const type = sqlType.toLowerCase();
8812
+ if (type.includes("int") || type.includes("decimal") || type.includes("float") || type.includes("double")) return "number";
8813
+ if (type.includes("bool") || type.includes("tinyint(1)")) return "boolean";
8814
+ if (type.includes("json")) return "unknown";
8815
+ return "string";
8816
+ }
8796
8817
  };
8797
8818
 
8798
8819
  // packages/cli/src/generators/HookGenerator.ts
@@ -8805,26 +8826,38 @@ var HookGenerator = class _HookGenerator {
8805
8826
  lines.push(``);
8806
8827
  lines.push(`import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'`);
8807
8828
  lines.push(`import { api } from './api'`);
8829
+ lines.push(`import * as Types from './types'`);
8808
8830
  lines.push(``);
8809
8831
  const grouped = buildGeneratedRoutes(manifest.routes);
8832
+ const modelNames = (manifest.models || []).map((m) => m.name);
8810
8833
  for (const [group, routes] of Object.entries(grouped)) {
8811
8834
  for (const route of routes) {
8812
8835
  const method = route.method.toUpperCase();
8813
8836
  const hookName = _HookGenerator.toHookName(group, route.actionName);
8814
8837
  const queryKey = `['${group}', '${route.actionName}']`;
8838
+ const possibleModel = _HookGenerator.findMatchingModel(group, modelNames);
8839
+ let responseType = "unknown";
8840
+ if (possibleModel) {
8841
+ if (route.actionName === "get" || route.actionName === "index" || !route.runtimePath.includes(":") && method === "GET") {
8842
+ responseType = `Types.${possibleModel}[]`;
8843
+ } else {
8844
+ responseType = `Types.${possibleModel}`;
8845
+ }
8846
+ }
8847
+ const returnType = possibleModel ? `Types.ApiResponse<${responseType}>` : `unknown`;
8815
8848
  if (method === "GET") {
8816
- lines.push(`export function ${hookName}(params?: Record<string, unknown>) {`);
8817
- lines.push(` return useQuery({`);
8849
+ lines.push(`export function ${hookName}<TData = ${returnType}>(params?: Record<string, unknown>) {`);
8850
+ lines.push(` return useQuery<TData>({`);
8818
8851
  lines.push(` queryKey: ${queryKey},`);
8819
- lines.push(` queryFn: () => api.${group}.${route.actionName}({ query: params })`);
8852
+ lines.push(` queryFn: () => api.${group}.${route.actionName}({ query: params }) as Promise<TData>`);
8820
8853
  lines.push(` })`);
8821
8854
  lines.push(`}`);
8822
8855
  lines.push(``);
8823
8856
  } else {
8824
- lines.push(`export function ${hookName}() {`);
8857
+ lines.push(`export function ${hookName}<TData = ${returnType}>() {`);
8825
8858
  lines.push(` const queryClient = useQueryClient()`);
8826
- lines.push(` return useMutation({`);
8827
- lines.push(` mutationFn: (data: Record<string, unknown>) => api.${group}.${route.actionName}({ body: data }),`);
8859
+ lines.push(` return useMutation<TData, Error, Record<string, unknown>>({`);
8860
+ lines.push(` mutationFn: (data: Record<string, unknown>) => api.${group}.${route.actionName}({ body: data }) as Promise<TData>,`);
8828
8861
  lines.push(` onSuccess: () => {`);
8829
8862
  lines.push(` queryClient.invalidateQueries({ queryKey: ['${group}'] })`);
8830
8863
  lines.push(` }`);
@@ -8839,6 +8872,16 @@ var HookGenerator = class _HookGenerator {
8839
8872
  static toHookName(group, actionName) {
8840
8873
  return `use${toTypeName(group)}${toTypeName(actionName)}`;
8841
8874
  }
8875
+ static findMatchingModel(group, modelNames) {
8876
+ const exact = modelNames.find((m) => m.toLowerCase() === group.toLowerCase());
8877
+ if (exact) return exact;
8878
+ const singularGroup = group.toLowerCase().replace(/ies$/, "y").replace(/s$/, "");
8879
+ const singularMatch = modelNames.find((m) => m.toLowerCase() === singularGroup);
8880
+ if (singularMatch) return singularMatch;
8881
+ const prefixMatch = modelNames.find((m) => m.toLowerCase().startsWith(group.toLowerCase()) || m.toLowerCase().startsWith(singularGroup));
8882
+ if (prefixMatch) return prefixMatch;
8883
+ return void 0;
8884
+ }
8842
8885
  };
8843
8886
 
8844
8887
  // packages/cli/src/generators/NextActionGenerator.ts
package/dist/react.d.mts CHANGED
@@ -45,7 +45,7 @@ type CallOptions = {
45
45
  headers?: Record<string, string>;
46
46
  };
47
47
  interface EndpointCallable {
48
- (options?: CallOptions): Promise<any>;
48
+ <TResponse = unknown>(options?: CallOptions): Promise<TResponse>;
49
49
  /** Original RouteDefinition — used by useApiQuery / useApiMutation */
50
50
  $def: RouteDefinition;
51
51
  /** Stable TanStack query key: [group, action] */
package/dist/react.d.ts CHANGED
@@ -45,7 +45,7 @@ type CallOptions = {
45
45
  headers?: Record<string, string>;
46
46
  };
47
47
  interface EndpointCallable {
48
- (options?: CallOptions): Promise<any>;
48
+ <TResponse = unknown>(options?: CallOptions): Promise<TResponse>;
49
49
  /** Original RouteDefinition — used by useApiQuery / useApiMutation */
50
50
  $def: RouteDefinition;
51
51
  /** Stable TanStack query key: [group, action] */
package/dist/sdk.d.mts CHANGED
@@ -106,7 +106,7 @@ type CallOptions = {
106
106
  headers?: Record<string, string>;
107
107
  };
108
108
  interface EndpointCallable {
109
- (options?: CallOptions): Promise<any>;
109
+ <TResponse = unknown>(options?: CallOptions): Promise<TResponse>;
110
110
  /** Original RouteDefinition — used by useApiQuery / useApiMutation */
111
111
  $def: RouteDefinition;
112
112
  /** Stable TanStack query key: [group, action] */
package/dist/sdk.d.ts CHANGED
@@ -106,7 +106,7 @@ type CallOptions = {
106
106
  headers?: Record<string, string>;
107
107
  };
108
108
  interface EndpointCallable {
109
- (options?: CallOptions): Promise<any>;
109
+ <TResponse = unknown>(options?: CallOptions): Promise<TResponse>;
110
110
  /** Original RouteDefinition — used by useApiQuery / useApiMutation */
111
111
  $def: RouteDefinition;
112
112
  /** Stable TanStack query key: [group, action] */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routesync",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "Laravel routes to typed frontend SDKs.",
5
5
  "main": "./dist/sdk.js",
6
6
  "module": "./dist/sdk.mjs",