@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.
Files changed (49) hide show
  1. package/README.md +15 -0
  2. package/dist-cjs/generate-api-clients/api-type-spec-utils.js +160 -0
  3. package/dist-cjs/generate-api-clients/copy-api-client.js +17 -0
  4. package/dist-cjs/generate-api-clients/generate-api-client-class.js +161 -0
  5. package/dist-cjs/generate-api-clients/generate-api-clients.js +70 -0
  6. package/dist-cjs/generate-api-clients/generate-hook.js +71 -0
  7. package/dist-cjs/generate-api-clients/handlebars-helpers.js +14 -0
  8. package/dist-cjs/generate-api-clients/index.js +4 -0
  9. package/dist-cjs/generate-api-clients/parse-discovered-apis.js +125 -0
  10. package/dist-cjs/generate-api-clients/sync-api-clients.js +84 -0
  11. package/dist-cjs/generate-api-clients/template-loader.js +24 -0
  12. package/dist-cjs/generate-api-clients/templates/api-client.hbs +25 -0
  13. package/dist-cjs/generate-api-clients/templates/api-client.ts.template +131 -0
  14. package/dist-cjs/generate-api-clients/templates/hook-mutation.hbs +39 -0
  15. package/dist-cjs/generate-api-clients/templates/hook-query.hbs +28 -0
  16. package/dist-cjs/generate-api-clients/types.js +2 -0
  17. package/dist-cjs/generate-api-clients/utils.js +89 -0
  18. package/dist-cjs/index.js +4 -0
  19. package/dist-es/generate-api-clients/api-type-spec-utils.js +155 -0
  20. package/dist-es/generate-api-clients/copy-api-client.js +12 -0
  21. package/dist-es/generate-api-clients/generate-api-client-class.js +156 -0
  22. package/dist-es/generate-api-clients/generate-api-clients.js +65 -0
  23. package/dist-es/generate-api-clients/generate-hook.js +66 -0
  24. package/dist-es/generate-api-clients/handlebars-helpers.js +9 -0
  25. package/dist-es/generate-api-clients/index.js +1 -0
  26. package/dist-es/generate-api-clients/parse-discovered-apis.js +120 -0
  27. package/dist-es/generate-api-clients/sync-api-clients.js +79 -0
  28. package/dist-es/generate-api-clients/template-loader.js +20 -0
  29. package/dist-es/generate-api-clients/templates/api-client.hbs +25 -0
  30. package/dist-es/generate-api-clients/templates/api-client.ts.template +131 -0
  31. package/dist-es/generate-api-clients/templates/hook-mutation.hbs +39 -0
  32. package/dist-es/generate-api-clients/templates/hook-query.hbs +28 -0
  33. package/dist-es/generate-api-clients/types.js +1 -0
  34. package/dist-es/generate-api-clients/utils.js +79 -0
  35. package/dist-es/index.js +1 -0
  36. package/dist-types/generate-api-clients/api-type-spec-utils.d.ts +4 -0
  37. package/dist-types/generate-api-clients/copy-api-client.d.ts +5 -0
  38. package/dist-types/generate-api-clients/generate-api-client-class.d.ts +11 -0
  39. package/dist-types/generate-api-clients/generate-api-clients.d.ts +2 -0
  40. package/dist-types/generate-api-clients/generate-hook.d.ts +11 -0
  41. package/dist-types/generate-api-clients/handlebars-helpers.d.ts +1 -0
  42. package/dist-types/generate-api-clients/index.d.ts +1 -0
  43. package/dist-types/generate-api-clients/parse-discovered-apis.d.ts +8 -0
  44. package/dist-types/generate-api-clients/sync-api-clients.d.ts +1 -0
  45. package/dist-types/generate-api-clients/template-loader.d.ts +5 -0
  46. package/dist-types/generate-api-clients/types.d.ts +113 -0
  47. package/dist-types/generate-api-clients/utils.d.ts +21 -0
  48. package/dist-types/index.d.ts +1 -0
  49. 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
+ };
@@ -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,5 @@
1
+ export declare const copyApiClient: (options: {
2
+ outputDirectory: string;
3
+ allowOverwrite: boolean;
4
+ verbose: boolean;
5
+ }) => 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,2 @@
1
+ import { APIClientGeneratorOptions } from "./types";
2
+ export declare const generateApiClients: (options?: APIClientGeneratorOptions) => Promise<void>;
@@ -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,5 @@
1
+ /**
2
+ * Loads a template file from the templates directory.
3
+ * Works in both development and production environments.
4
+ */
5
+ export declare function loadTemplate(templateName: string): string;
@@ -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
+ }