@itzworking/devkit 0.0.198-canary.20250707-e7f7621
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist-cjs/generate-api-clients/api-type-spec-utils.js +160 -0
- package/dist-cjs/generate-api-clients/copy-api-client.js +17 -0
- package/dist-cjs/generate-api-clients/generate-api-client-class.js +161 -0
- package/dist-cjs/generate-api-clients/generate-api-clients.js +70 -0
- package/dist-cjs/generate-api-clients/generate-hook.js +71 -0
- package/dist-cjs/generate-api-clients/handlebars-helpers.js +14 -0
- package/dist-cjs/generate-api-clients/index.js +4 -0
- package/dist-cjs/generate-api-clients/parse-discovered-apis.js +125 -0
- package/dist-cjs/generate-api-clients/sync-api-clients.js +84 -0
- package/dist-cjs/generate-api-clients/template-loader.js +24 -0
- package/dist-cjs/generate-api-clients/templates/api-client.hbs +25 -0
- package/dist-cjs/generate-api-clients/templates/api-client.ts.template +131 -0
- package/dist-cjs/generate-api-clients/templates/hook-mutation.hbs +39 -0
- package/dist-cjs/generate-api-clients/templates/hook-query.hbs +28 -0
- package/dist-cjs/generate-api-clients/types.js +2 -0
- package/dist-cjs/generate-api-clients/utils.js +89 -0
- package/dist-cjs/index.js +4 -0
- package/dist-es/generate-api-clients/api-type-spec-utils.js +155 -0
- package/dist-es/generate-api-clients/copy-api-client.js +12 -0
- package/dist-es/generate-api-clients/generate-api-client-class.js +156 -0
- package/dist-es/generate-api-clients/generate-api-clients.js +65 -0
- package/dist-es/generate-api-clients/generate-hook.js +66 -0
- package/dist-es/generate-api-clients/handlebars-helpers.js +9 -0
- package/dist-es/generate-api-clients/index.js +1 -0
- package/dist-es/generate-api-clients/parse-discovered-apis.js +120 -0
- package/dist-es/generate-api-clients/sync-api-clients.js +79 -0
- package/dist-es/generate-api-clients/template-loader.js +20 -0
- package/dist-es/generate-api-clients/templates/api-client.hbs +25 -0
- package/dist-es/generate-api-clients/templates/api-client.ts.template +131 -0
- package/dist-es/generate-api-clients/templates/hook-mutation.hbs +39 -0
- package/dist-es/generate-api-clients/templates/hook-query.hbs +28 -0
- package/dist-es/generate-api-clients/types.js +1 -0
- package/dist-es/generate-api-clients/utils.js +79 -0
- package/dist-es/index.js +1 -0
- package/dist-types/generate-api-clients/api-type-spec-utils.d.ts +4 -0
- package/dist-types/generate-api-clients/copy-api-client.d.ts +5 -0
- package/dist-types/generate-api-clients/generate-api-client-class.d.ts +11 -0
- package/dist-types/generate-api-clients/generate-api-clients.d.ts +2 -0
- package/dist-types/generate-api-clients/generate-hook.d.ts +11 -0
- package/dist-types/generate-api-clients/handlebars-helpers.d.ts +1 -0
- package/dist-types/generate-api-clients/index.d.ts +1 -0
- package/dist-types/generate-api-clients/parse-discovered-apis.d.ts +8 -0
- package/dist-types/generate-api-clients/sync-api-clients.d.ts +1 -0
- package/dist-types/generate-api-clients/template-loader.d.ts +5 -0
- package/dist-types/generate-api-clients/types.d.ts +113 -0
- package/dist-types/generate-api-clients/utils.d.ts +21 -0
- package/dist-types/index.d.ts +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// prettier-ignore
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
{{#each imports}}
|
|
6
|
+
import { {{names}} } from "{{path}}";
|
|
7
|
+
{{/each}}
|
|
8
|
+
|
|
9
|
+
export const {{hookName}} = () => {
|
|
10
|
+
const queryClient = useQueryClient();
|
|
11
|
+
const useMutationResult = useMutation({
|
|
12
|
+
mutationFn: ({{mutationParams}}){{#if outputType}}: Promise<{{outputType.typeName}}>{{/if}} => {{apiClassName}}.{{actionName}}({{#if mutationParams}}variables{{/if}}),
|
|
13
|
+
onMutate: async (variables) => {
|
|
14
|
+
// A mutation is about to happen!
|
|
15
|
+
},
|
|
16
|
+
onError: async (err, variables, context) => {
|
|
17
|
+
// An error happened!
|
|
18
|
+
},
|
|
19
|
+
onSuccess: async (data, variables, context) => {
|
|
20
|
+
// Boom baby!
|
|
21
|
+
},
|
|
22
|
+
onSettled: async () => {
|
|
23
|
+
// Error or success... doesn't matter!
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
{{actionName}}: useMutationResult.mutate,
|
|
29
|
+
{{actionName}}Async: useMutationResult.mutateAsync,
|
|
30
|
+
is{{apiClassName}}Error: useMutationResult.isError,
|
|
31
|
+
is{{apiClassName}}Idle: useMutationResult.isIdle,
|
|
32
|
+
is{{apiClassName}}Paused: useMutationResult.isPaused,
|
|
33
|
+
is{{apiClassName}}Pending: useMutationResult.isPending,
|
|
34
|
+
is{{apiClassName}}Success: useMutationResult.isSuccess,
|
|
35
|
+
{{actionName}}Status: useMutationResult.status,
|
|
36
|
+
{{actionName}}Error: useMutationResult.error,
|
|
37
|
+
reset{{apiClassName}}: useMutationResult.reset
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// prettier-ignore
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
import { useQuery } from "@tanstack/react-query";
|
|
5
|
+
{{#each imports}}
|
|
6
|
+
import { {{names}} } from "{{path}}";
|
|
7
|
+
{{/each}}
|
|
8
|
+
|
|
9
|
+
export const {{relatedDataName}}QueryKey = ({{queryKeyParams}}) => [
|
|
10
|
+
{{{queryKeyArray}}}
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const {{hookName}} = ({{queryKeyParams}}) => {
|
|
14
|
+
const useQueryResult = useQuery({
|
|
15
|
+
queryKey: {{relatedDataName}}QueryKey({{queryKeyInput}}),
|
|
16
|
+
queryFn: (){{#if outputType}}: Promise<{{outputType.typeName}}>{{/if}} => {{apiClassName}}.{{actionName}}({{queryKeyInput}})
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
{{relatedDataName}}: useQueryResult.data,
|
|
21
|
+
{{relatedDataName}}UpdatedAt: useQueryResult.dataUpdatedAt,
|
|
22
|
+
{{actionName}}Error: useQueryResult.error,
|
|
23
|
+
is{{actionClassName}}Loading: useQueryResult.isLoading,
|
|
24
|
+
is{{actionClassName}}Fetching: useQueryResult.isFetching,
|
|
25
|
+
refetch{{actionClassName}}: useQueryResult.refetch,
|
|
26
|
+
{{actionName}}Status: useQueryResult.status
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
export const getITzWorkingResources = ({ resourcesFilePath, }) => {
|
|
4
|
+
if (!fs.existsSync(resourcesFilePath)) {
|
|
5
|
+
console.error(`${resourcesFilePath} file not found. Please deploy your application.`);
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
const data = fs.readFileSync(resourcesFilePath, "utf-8");
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(data);
|
|
11
|
+
}
|
|
12
|
+
catch (e) {
|
|
13
|
+
console.error(`Error parsing ${resourcesFilePath} file. Please ensure it is a valid JSON file.`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export const prepareImports = (apis, options) => {
|
|
18
|
+
const formatedApis = Array.isArray(apis) ? apis : [apis];
|
|
19
|
+
const imports = [];
|
|
20
|
+
const importMap = {};
|
|
21
|
+
if (options.typeResolutionMode === "source-imports") {
|
|
22
|
+
for (const api of formatedApis) {
|
|
23
|
+
for (const [importPath, importNames] of Object.entries(api.imports)) {
|
|
24
|
+
if (!importMap[importPath])
|
|
25
|
+
importMap[importPath] = new Set();
|
|
26
|
+
importNames.forEach((name) => importMap[importPath].add(name));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (options.typeResolutionMode === "inline-types") {
|
|
31
|
+
for (const api of formatedApis) {
|
|
32
|
+
const typeSpecs = [api.inputType, api.outputType];
|
|
33
|
+
for (const typeSpec of typeSpecs) {
|
|
34
|
+
if (!typeSpec || !typeSpec.importPath)
|
|
35
|
+
continue;
|
|
36
|
+
if (!importMap["./types"])
|
|
37
|
+
importMap["./types"] = new Set();
|
|
38
|
+
importMap["./types"].add(typeSpec.typeName);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
throw new Error(`Unsupported typeResolutionMode: ${options.typeResolutionMode}.`);
|
|
44
|
+
}
|
|
45
|
+
for (const importPath of Object.keys(importMap).sort()) {
|
|
46
|
+
imports.push({
|
|
47
|
+
path: importPath,
|
|
48
|
+
names: Array.from(importMap[importPath]).sort().join(", "),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return imports.sort((a, b) => b.path.localeCompare(a.path));
|
|
52
|
+
};
|
|
53
|
+
export const toPropertyName = (s) => {
|
|
54
|
+
return s
|
|
55
|
+
.replace(/([^a-zA-Z0-9])+(.)?/g, (_, __, chr) => chr ? chr.toUpperCase() : "")
|
|
56
|
+
.replace(/[^a-zA-Z\d]/g, "")
|
|
57
|
+
.replace(/^([A-Z])/, (m) => m.toLowerCase());
|
|
58
|
+
};
|
|
59
|
+
export const toClassName = (s) => {
|
|
60
|
+
const propertyName = toPropertyName(s);
|
|
61
|
+
return propertyName.charAt(0).toUpperCase() + propertyName.slice(1);
|
|
62
|
+
};
|
|
63
|
+
export const toFileName = (s) => {
|
|
64
|
+
return s
|
|
65
|
+
.replace(/([a-z\d])([A-Z])/g, "$1_$2")
|
|
66
|
+
.toLowerCase()
|
|
67
|
+
.replace(/(?!^_)[ _]/g, "-");
|
|
68
|
+
};
|
|
69
|
+
export const writeFile = (params) => {
|
|
70
|
+
const { filePath, content, allowOverwrite } = params;
|
|
71
|
+
const dir = path.dirname(filePath);
|
|
72
|
+
if (!fs.existsSync(dir)) {
|
|
73
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
if (fs.existsSync(filePath) && !allowOverwrite) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
fs.writeFileSync(filePath, content);
|
|
79
|
+
};
|
package/dist-es/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./generate-api-clients";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { APITypeSpec } from "./types";
|
|
2
|
+
import { SourceFile } from "ts-morph";
|
|
3
|
+
export declare const setTypeKind: (type: APITypeSpec | null, sourceFile: SourceFile) => void;
|
|
4
|
+
export declare const extractTypeDefinition: (type: APITypeSpec | null, sourceFile: SourceFile) => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { APIDetails } from "./types";
|
|
2
|
+
export declare const generateApiClientClass: ({ basePath, apis, }: {
|
|
3
|
+
basePath: string;
|
|
4
|
+
apis: APIDetails[];
|
|
5
|
+
}, options: {
|
|
6
|
+
typeResolutionMode: string;
|
|
7
|
+
verbose: boolean;
|
|
8
|
+
}) => {
|
|
9
|
+
apiClientClassFile: string;
|
|
10
|
+
apiTypesFile: string;
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { APIDetails } from "./types";
|
|
2
|
+
export declare const generateHook: ({ basePath, api, }: {
|
|
3
|
+
basePath: string;
|
|
4
|
+
api: APIDetails;
|
|
5
|
+
}, options: {
|
|
6
|
+
typeResolutionMode: string;
|
|
7
|
+
verbose: boolean;
|
|
8
|
+
}) => {
|
|
9
|
+
hookName: string;
|
|
10
|
+
hookFile: string;
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const handlebarsHelpers: () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./generate-api-clients";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { APIDetails, ITzDiscoveredResources } from "./types";
|
|
2
|
+
export declare const parseDiscoveredApis: (resources: ITzDiscoveredResources, options: {
|
|
3
|
+
tsConfigPath: string;
|
|
4
|
+
typeResolutionMode: string;
|
|
5
|
+
verbose: boolean;
|
|
6
|
+
}) => {
|
|
7
|
+
[basePath: string]: APIDetails[];
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const syncApiClients: (webappDataPath: string) => void;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for generating TypeScript API clients and React Query hooks
|
|
3
|
+
* from discovered AWS Lambda handlers via itzworking deployment resources
|
|
4
|
+
*/
|
|
5
|
+
export interface APIClientGeneratorOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Path to the TypeScript configuration file for parsing Lambda handlers
|
|
8
|
+
* Used to resolve type imports and compile backend code analysis
|
|
9
|
+
* @default "tsconfig.json"
|
|
10
|
+
*/
|
|
11
|
+
tsConfigPath?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Target type system for generated API clients
|
|
14
|
+
* Determines how Lambda handler types are transformed for frontend consumption
|
|
15
|
+
* - "preserve-backend": Maintain the same type system as the backend
|
|
16
|
+
* - "zod-schema": Convert all types to Zod schemas for runtime validation
|
|
17
|
+
* - "decorated-class": Convert all types to @itzworking/decorated-class format
|
|
18
|
+
* @default "preserve-backend"
|
|
19
|
+
*/
|
|
20
|
+
targetTypeSystem?: "preserve-backend" | "zod-schemas" | "decorated-classes";
|
|
21
|
+
/**
|
|
22
|
+
* Strategy for resolving type definitions in generated clients
|
|
23
|
+
* Controls how backend types are made available to the frontend
|
|
24
|
+
* - "source-imports": Import types directly from Lambda source files (requires monorepo setup)
|
|
25
|
+
* - "inline-types": Recreate and embed all type definitions within generated clients
|
|
26
|
+
* @default "source-imports"
|
|
27
|
+
*/
|
|
28
|
+
typeResolutionMode?: "source-imports" | "inline-types";
|
|
29
|
+
/**
|
|
30
|
+
* Enable detailed logging for debugging and development
|
|
31
|
+
* Provides comprehensive information about:
|
|
32
|
+
* - Lambda handler discovery and parsing
|
|
33
|
+
* - Type resolution and transformation
|
|
34
|
+
* - File generation and output processes
|
|
35
|
+
* - Import path resolution
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
verbose?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Allow overwriting existing files in the output directory
|
|
41
|
+
* When false, generation will fail if target files already exist
|
|
42
|
+
* Useful for preventing accidental overwrites in production workflows
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
allowOverwrite?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Remove all existing files from output directory before generation
|
|
48
|
+
* Ensures clean generation and removes any orphaned files
|
|
49
|
+
* Recommended when API structure changes frequently
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
cleanOutputDir?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Directory path where generated API clients will be written
|
|
55
|
+
* Should point to your frontend application's API client directory
|
|
56
|
+
* @default "out/apis"
|
|
57
|
+
*/
|
|
58
|
+
outputDirectory?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Path to the itzworking resources file containing API endpoint mappings
|
|
61
|
+
* This file is generated by itzworking deployment and contains
|
|
62
|
+
* the relationship between API routes and Lambda handlers
|
|
63
|
+
* @default "cdk.itzworking.json"
|
|
64
|
+
*/
|
|
65
|
+
resourcesFilePath?: string;
|
|
66
|
+
}
|
|
67
|
+
export type Handler = {
|
|
68
|
+
id: string;
|
|
69
|
+
folderPath: string;
|
|
70
|
+
description: string;
|
|
71
|
+
};
|
|
72
|
+
export type APIHandler = Handler & {
|
|
73
|
+
method: string;
|
|
74
|
+
authorizerId?: string;
|
|
75
|
+
};
|
|
76
|
+
export type ITzDiscoveredResources = {
|
|
77
|
+
discoveredResources: {
|
|
78
|
+
[key: string]: {
|
|
79
|
+
apis: APIHandler[];
|
|
80
|
+
events: Handler[];
|
|
81
|
+
"step-functions": Handler[];
|
|
82
|
+
handlers: Handler[];
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
export type APITypeSpec = {
|
|
87
|
+
typeName: string;
|
|
88
|
+
importPath: string | null;
|
|
89
|
+
typeDefinition: {
|
|
90
|
+
allowedImports: {
|
|
91
|
+
namespaceImport: boolean;
|
|
92
|
+
importPath: string;
|
|
93
|
+
importNames: string[];
|
|
94
|
+
}[];
|
|
95
|
+
inlinedFiles: {
|
|
96
|
+
filePath: string;
|
|
97
|
+
text: string;
|
|
98
|
+
}[];
|
|
99
|
+
};
|
|
100
|
+
structure: any;
|
|
101
|
+
kind: "decorated-class" | "zod-schema" | "unknown";
|
|
102
|
+
};
|
|
103
|
+
export type APIDetails = {
|
|
104
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | string;
|
|
105
|
+
fullPath: string;
|
|
106
|
+
actionName: string;
|
|
107
|
+
relatedDataName: string;
|
|
108
|
+
inputType: APITypeSpec | null;
|
|
109
|
+
outputType: APITypeSpec | null;
|
|
110
|
+
imports: {
|
|
111
|
+
[path: string]: string[];
|
|
112
|
+
};
|
|
113
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { APIDetails, ITzDiscoveredResources } from "./types";
|
|
2
|
+
export declare const getITzWorkingResources: ({ resourcesFilePath, }: {
|
|
3
|
+
resourcesFilePath: string;
|
|
4
|
+
verbose: boolean;
|
|
5
|
+
}) => ITzDiscoveredResources;
|
|
6
|
+
export declare const prepareImports: (apis: APIDetails | APIDetails[], options: {
|
|
7
|
+
typeResolutionMode: string;
|
|
8
|
+
verbose: boolean;
|
|
9
|
+
}) => {
|
|
10
|
+
path: string;
|
|
11
|
+
names: string;
|
|
12
|
+
}[];
|
|
13
|
+
export declare const toPropertyName: (s: string) => string;
|
|
14
|
+
export declare const toClassName: (s: string) => string;
|
|
15
|
+
export declare const toFileName: (s: string) => string;
|
|
16
|
+
export declare const writeFile: (params: {
|
|
17
|
+
filePath: string;
|
|
18
|
+
content: string;
|
|
19
|
+
allowOverwrite: boolean;
|
|
20
|
+
verbose: boolean;
|
|
21
|
+
}) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./generate-api-clients";
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@itzworking/devkit",
|
|
3
|
+
"version": "0.0.198-canary.20250707-e7f7621",
|
|
4
|
+
"main": "./dist-cjs/index.js",
|
|
5
|
+
"module": "./dist-es/index.js",
|
|
6
|
+
"types": "./dist-types/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build:all": "concurrently \"npm run build:cjs\" \"npm run build:es\" \"npm run build:types\"",
|
|
9
|
+
"build:cjs": "tsc -p tsconfig.cjs.json && npm run copy:templates",
|
|
10
|
+
"build:es": "tsc -p tsconfig.es.json && npm run copy:templates",
|
|
11
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
12
|
+
"copy:templates": "node scripts/copy-templates.js"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18.0.0"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist-*/**",
|
|
19
|
+
"!**/*.tsbuildinfo"
|
|
20
|
+
],
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"ts-morph": "26.0.0"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"tslib": "^2.3.0"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://itzworking.io",
|
|
28
|
+
"nx": {
|
|
29
|
+
"targets": {
|
|
30
|
+
"publish": {
|
|
31
|
+
"dependsOn": [
|
|
32
|
+
"build:all"
|
|
33
|
+
],
|
|
34
|
+
"executor": "nx:run-commands",
|
|
35
|
+
"options": {
|
|
36
|
+
"command": "node scripts/ci/publish.mjs {projectRoot}"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"tags": [
|
|
41
|
+
"type:lib"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
}
|