quickbase-js 0.1.0-beta.8 → 1.0.0

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 (132) hide show
  1. package/README.md +252 -126
  2. package/dist/esm/quickbase.d.ts +2725 -2689
  3. package/dist/esm/quickbase.js +1763 -3524
  4. package/dist/esm/quickbase.js.map +1 -1
  5. package/dist/esm/quickbase.min.js +1 -1
  6. package/dist/esm/quickbase.min.js.map +1 -1
  7. package/dist/umd/quickbase.umd.js +1762 -3706
  8. package/dist/umd/quickbase.umd.js.map +1 -1
  9. package/dist/umd/quickbase.umd.min.js +1 -1
  10. package/dist/umd/quickbase.umd.min.js.map +1 -1
  11. package/package.json +27 -12
  12. package/CHANGELOG.md +0 -155
  13. package/build-common.js +0 -131
  14. package/build-esm.js +0 -71
  15. package/build-umd.js +0 -69
  16. package/examples/quicbase-jsCDN.html +0 -36
  17. package/examples/react.js +0 -48
  18. package/examples/vanillajs.html +0 -47
  19. package/open-api/fix-spec-main.ts +0 -97
  20. package/open-api/generate-override-report.ts +0 -214
  21. package/open-api/generate-unified-interface.ts +0 -256
  22. package/open-api/output/override-report.html +0 -11
  23. package/open-api/output/override-report.json +0 -14395
  24. package/open-api/output/quickbase-fixed.json +0 -11191
  25. package/open-api/regenerate-client.ts +0 -116
  26. package/open-api/schema/enhance-general.ts +0 -100
  27. package/open-api/schema/fix-arrays.ts +0 -69
  28. package/open-api/schema/tags/apps.ts +0 -90
  29. package/open-api/schema/tags/fields.ts +0 -471
  30. package/open-api/schema/tags/groups.ts +0 -51
  31. package/open-api/schema/tags/index.ts +0 -66
  32. package/open-api/schema/tags/records.ts +0 -115
  33. package/open-api/schema/tags/tables.ts +0 -211
  34. package/open-api/schema/tags/users.ts +0 -47
  35. package/open-api/types/spec.ts +0 -42
  36. package/open-api/utils/infer-schema.ts +0 -40
  37. package/open-api/utils/naming.ts +0 -10
  38. package/playwright.config.ts +0 -37
  39. package/rollup.config.js +0 -114
  40. package/specs/QuickBase_RESTful_API_2025-03-04T06_22_39.725Z.json +0 -46878
  41. package/specs/split/apps.json +0 -1315
  42. package/specs/split/auth.json +0 -191
  43. package/specs/split/fields.json +0 -3869
  44. package/specs/split/records.json +0 -754
  45. package/specs/split/reports.json +0 -619
  46. package/specs/split/tables.json +0 -1605
  47. package/src/RateLimitError.ts +0 -12
  48. package/src/ThrottleBucket.ts +0 -36
  49. package/src/generated-unified/QuickbaseClient.ts +0 -359
  50. package/src/generated-unified/missing-types-report.json +0 -3
  51. package/src/index.ts +0 -1
  52. package/src/invokeMethod.ts +0 -357
  53. package/src/quickbaseClient.ts +0 -244
  54. package/src/tokenCache.ts +0 -51
  55. package/src/utils.ts +0 -7
  56. package/test-esm.js +0 -1
  57. package/test-results.json +0 -2050
  58. package/test-umd.js +0 -1
  59. package/test.ts +0 -1
  60. package/tests/playwright/qb/auth/cacheSwitching.test.ts +0 -159
  61. package/tests/playwright/qb/auth/fetchTempToken401.test.ts +0 -219
  62. package/tests/playwright/qb/auth/getAppWithTempToken.test.ts +0 -162
  63. package/tests/playwright/qb/auth/getAppWithUserToken.test.ts +0 -153
  64. package/tests/playwright/qb/auth/getTempToken.test.ts +0 -152
  65. package/tests/playwright/qb/auth/tempTokenPrefetch.test.ts +0 -179
  66. package/tests/playwright/qb/auth/tempTokenRenewal.test.ts +0 -133
  67. package/tests/setup.ts +0 -53
  68. package/tests/vitest/qb/apps/copyApp.test.ts +0 -76
  69. package/tests/vitest/qb/apps/createApp.test.ts +0 -64
  70. package/tests/vitest/qb/apps/deleteApp.test.ts +0 -76
  71. package/tests/vitest/qb/apps/getApp.test.ts +0 -44
  72. package/tests/vitest/qb/apps/getAppEvents.test.ts +0 -67
  73. package/tests/vitest/qb/apps/updateApp.test.ts +0 -58
  74. package/tests/vitest/qb/auth/retryUserToken401.test.ts +0 -56
  75. package/tests/vitest/qb/fields/createField.test.ts +0 -77
  76. package/tests/vitest/qb/fields/deleteFields.test.ts +0 -83
  77. package/tests/vitest/qb/fields/getField.test.ts +0 -85
  78. package/tests/vitest/qb/fields/getFieldUsage.test.ts +0 -174
  79. package/tests/vitest/qb/fields/getFields.test.ts +0 -232
  80. package/tests/vitest/qb/fields/getFieldsUsage.test.ts +0 -77
  81. package/tests/vitest/qb/fields/updateField.test.ts +0 -93
  82. package/tests/vitest/qb/index.ts +0 -29
  83. package/tests/vitest/qb/records/deleteRecords.test.ts +0 -110
  84. package/tests/vitest/qb/records/runQuery.test.ts +0 -146
  85. package/tests/vitest/qb/records/upsert.test.ts +0 -102
  86. package/tests/vitest/qb/tables/createTable.test.ts +0 -55
  87. package/tests/vitest/qb/tables/deleteTable.test.ts +0 -50
  88. package/tests/vitest/qb/tables/getAppTables.test.ts +0 -46
  89. package/tests/vitest/qb/tables/getRelationships.test.ts +0 -80
  90. package/tests/vitest/qb/tables/getTable.test.ts +0 -26
  91. package/tests/vitest/qb/tables/updateRelationship.test.ts +0 -277
  92. package/tests/vitest/qb/tables/updateTable.test.ts +0 -48
  93. package/tests/vitest/unit/apps/copyApp.test.ts +0 -488
  94. package/tests/vitest/unit/apps/createApp.test.ts +0 -186
  95. package/tests/vitest/unit/apps/deleteApp.test.ts +0 -216
  96. package/tests/vitest/unit/apps/getApp.test.ts +0 -128
  97. package/tests/vitest/unit/apps/getAppEvents.test.ts +0 -193
  98. package/tests/vitest/unit/apps/updateApp.test.ts +0 -381
  99. package/tests/vitest/unit/auth/fetchTempToken401.test.ts +0 -62
  100. package/tests/vitest/unit/auth/getTempToken.test.ts +0 -95
  101. package/tests/vitest/unit/auth/retryTempToken401.test.ts +0 -113
  102. package/tests/vitest/unit/auth/retryTempTokenTwo401.test.ts +0 -81
  103. package/tests/vitest/unit/auth/retryUserToken401.test.ts +0 -56
  104. package/tests/vitest/unit/fields/createField.test.ts +0 -387
  105. package/tests/vitest/unit/fields/deleteFields.test.ts +0 -141
  106. package/tests/vitest/unit/fields/getField.test.ts +0 -189
  107. package/tests/vitest/unit/fields/getFieldUsage.test.ts +0 -166
  108. package/tests/vitest/unit/fields/getFields.test.ts +0 -122
  109. package/tests/vitest/unit/fields/getFieldsUsage.test.ts +0 -160
  110. package/tests/vitest/unit/fields/updateField.test.ts +0 -280
  111. package/tests/vitest/unit/index.ts +0 -33
  112. package/tests/vitest/unit/rateLimit.test.ts +0 -189
  113. package/tests/vitest/unit/records/deleteRecords.test.ts +0 -112
  114. package/tests/vitest/unit/records/runQuery.test.ts +0 -102
  115. package/tests/vitest/unit/records/upsert.test.ts +0 -234
  116. package/tests/vitest/unit/tables/createTable.test.ts +0 -70
  117. package/tests/vitest/unit/tables/deleteTable.test.ts +0 -77
  118. package/tests/vitest/unit/tables/getAppTables.test.ts +0 -85
  119. package/tests/vitest/unit/tables/getRelationships.test.ts +0 -259
  120. package/tests/vitest/unit/tables/getTable.test.ts +0 -233
  121. package/tests/vitest/unit/tables/updateRelationship.test.ts +0 -305
  122. package/tests/vitest/unit/tables/updateTable.test.ts +0 -80
  123. package/tests/vitest/unit/tokenLifespan.test.ts +0 -138
  124. package/tests/vitest/unit/umd.test.ts +0 -8
  125. package/text.txt +0 -104
  126. package/tools/log-gen.ts +0 -235
  127. package/tools/log-gen.yaml +0 -4982
  128. package/tools/openapi-jars/openapi-generator-cli-7.12.0.jar +0 -0
  129. package/tsconfig.build.json +0 -17
  130. package/tsconfig.json +0 -32
  131. package/versionrc.json +0 -9
  132. package/vitest.config.ts +0 -27
@@ -1,97 +0,0 @@
1
- #!/usr/bin/env node
2
- import { promises as fs } from "fs";
3
- import path from "path";
4
- import { fileURLToPath } from "url";
5
- import * as glob from "glob";
6
- import { Spec } from "./types/spec.ts";
7
- import { toCamelCase } from "./utils/naming.ts";
8
-
9
- async function fixQuickBaseSpec(): Promise<void> {
10
- const CODEGEN_DIR = path.dirname(fileURLToPath(import.meta.url));
11
- const SPECS_DIR = path.join(CODEGEN_DIR, "..", "specs");
12
- const OUTPUT_DIR = path.join(CODEGEN_DIR, "output");
13
- console.log("Finding latest QuickBase RESTful API spec...");
14
- const specFiles = glob.sync(path.join(SPECS_DIR, "QuickBase_RESTful_*.json"));
15
- console.log("Spec files:", specFiles);
16
-
17
- if (specFiles.length === 0) {
18
- throw new Error(
19
- "No QuickBase_RESTful_*.json files found in specs/ folder."
20
- );
21
- }
22
-
23
- const inputFile = specFiles.sort().pop() as string;
24
- const outputFile = path.join(OUTPUT_DIR, "quickbase-fixed.json");
25
-
26
- console.log(`Reading ${path.basename(inputFile)} from specs/...`);
27
- const specContent = await fs.readFile(inputFile, "utf8");
28
- console.log("File read successfully");
29
- const spec: Spec = JSON.parse(specContent);
30
- console.log("JSON parsed successfully");
31
-
32
- if (!spec.definitions || typeof spec.definitions !== "object") {
33
- spec.definitions = {};
34
- }
35
- console.log("Spec definitions after initialization:", spec.definitions);
36
-
37
- console.log("Fixing parameters...");
38
- for (const pathKey in spec.paths) {
39
- for (const method in spec.paths[pathKey]) {
40
- const operation = spec.paths[pathKey][method];
41
- if (operation.parameters) {
42
- operation.parameters = operation.parameters
43
- .filter(
44
- (param) =>
45
- !["QB-Realm-Hostname", "Authorization", "User-Agent"].includes(
46
- param.name
47
- )
48
- )
49
- .map((param) => {
50
- param.name = toCamelCase(param.name);
51
- if ("example" in param) delete param.example;
52
- if ("schema" in param && param.in !== "body") delete param.schema;
53
- if (!param.type && param.in !== "body") {
54
- param.type = param.name.includes("Id") ? "string" : "string";
55
- console.log(
56
- `Set default type 'string' for ${pathKey}(${method}).${param.name}`
57
- );
58
- }
59
- return param;
60
- });
61
- }
62
- }
63
- }
64
-
65
- console.log("Spec definitions before enhanceTags:", spec.definitions);
66
- console.log("Enhancing raw spec with tags...");
67
- const { enhanceTags } = await import("./schema/tags/index.ts"); // Updated to index.ts
68
- enhanceTags(spec);
69
- console.log("Enhancing raw spec with general enhancements...");
70
- const { enhanceGeneral } = await import("./schema/enhance-general.ts");
71
- enhanceGeneral(spec);
72
- console.log("Fixing array schemas...");
73
- const { fixArrays } = await import("./schema/fix-arrays.ts");
74
- fixArrays(spec);
75
-
76
- console.log("Removing unexpected top-level attributes...");
77
- delete spec.operations;
78
- delete spec.groups;
79
- delete spec.components;
80
-
81
- console.log(`Writing fixed spec to ${path.basename(outputFile)}...`);
82
- await fs.mkdir(OUTPUT_DIR, { recursive: true });
83
- await fs.writeFile(outputFile, JSON.stringify(spec, null, 2), "utf8");
84
- console.log("Spec fixed successfully! Output written to:", outputFile);
85
- }
86
-
87
- async function main() {
88
- try {
89
- console.log("Starting...");
90
- await fixQuickBaseSpec();
91
- } catch (error) {
92
- console.error("Error:", error);
93
- process.exit(1);
94
- }
95
- }
96
-
97
- main();
@@ -1,214 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { promises as fs } from "fs";
4
- import * as path from "path";
5
- import { fileURLToPath } from "url";
6
- import fastJsonPatch, { AddOperation } from "fast-json-patch";
7
- import { Spec } from "./types/spec";
8
-
9
- const { compare, applyPatch } = fastJsonPatch;
10
-
11
- // Basic CSS for readability
12
- const HTML_STYLE = `
13
- <style>
14
- .jsondiffpatch-delta { font-family: monospace; }
15
- .jsondiffpatch-added { background-color: #e6ffe6; color: #006400; }
16
- .jsondiffpatch-deleted { background-color: #ffe6e6; color: #8b0000; text-decoration: line-through; }
17
- .jsondiffpatch-modified { background-color: #fff3e6; }
18
- .jsondiffpatch-unchanged { color: #666; }
19
- .jsondiffpatch-key { font-weight: bold; }
20
- .jsondiffpatch-tags { color: purple; font-style: italic; }
21
- </style>
22
- `;
23
-
24
- // Helper to decode JSON Pointer paths
25
- function decodeJsonPointer(jsonPointerSegment: string): string {
26
- // Split the full path and decode each segment
27
- const segments = jsonPointerSegment.split("/").filter(Boolean);
28
- const decodedSegments = segments.map((seg) =>
29
- seg.replace("~1", "/").replace("~0", "~")
30
- );
31
- // Remove "paths" prefix and join with a single leading slash
32
- const pathIndex = decodedSegments.indexOf("paths");
33
- const relevantSegments =
34
- pathIndex !== -1 && pathIndex + 1 < decodedSegments.length
35
- ? decodedSegments.slice(pathIndex + 1)
36
- : decodedSegments;
37
- return "/" + relevantSegments.join("/"); // Ensure single leading slash
38
- }
39
-
40
- // Enhanced HTML formatter with clean paths, tags, and old vs. new values
41
- function formatPatchToHtml(patch: any[], spec: Spec): string {
42
- let html = `<html><head><title>Override Report Diff</title>${HTML_STYLE}</head><body><h1>Override Report Diff</h1>`;
43
- patch.forEach((op) => {
44
- const pathParts = op.path.split("/").filter(Boolean);
45
- const lastPart = pathParts[pathParts.length - 1];
46
- let oldValue = "N/A";
47
- let context = decodeJsonPointer(op.path);
48
- let method = op.method ? op.method.toUpperCase() : "";
49
-
50
- if (method) context = context.replace(`/${method}`, "") + ` [${method}]`;
51
-
52
- if (op.op === "replace" || op.op === "remove") {
53
- const reversePatch: AddOperation<any>[] = [
54
- { op: "add", path: op.path, value: op.value },
55
- ];
56
- const tempSpec = JSON.parse(JSON.stringify(spec));
57
- applyPatch(tempSpec, reversePatch);
58
- const pathSegments = op.path.split("/").slice(1);
59
- oldValue =
60
- pathSegments.reduce((obj: any, key: string) => obj?.[key], tempSpec) ||
61
- "N/A";
62
- oldValue = JSON.stringify(oldValue);
63
- }
64
-
65
- const tagDisplay =
66
- op.tags && op.tags.length > 0 ? ` (Tags: ${op.tags.join(", ")})` : "";
67
-
68
- if (op.op === "replace") {
69
- html += `<h2>Path: ${context}${tagDisplay}</h2><p>Modified: <span class="jsondiffpatch-deleted">${oldValue}</span> → <span class="jsondiffpatch-added">${JSON.stringify(
70
- op.value
71
- )}</span></p>`;
72
- } else if (op.op === "add") {
73
- html += `<h2>Path: ${context}${tagDisplay}</h2><p>Added: <span class="jsondiffpatch-added">${JSON.stringify(
74
- op.value
75
- )}</span></p>`;
76
- } else if (op.op === "remove") {
77
- html += `<h2>Path: ${context}${tagDisplay}</h2><p>Removed: <span class="jsondiffpatch-deleted">${oldValue}</span></p>`;
78
- }
79
- });
80
- html += "</body></html>";
81
- return html;
82
- }
83
-
84
- async function generateOverrideReport(): Promise<void> {
85
- try {
86
- const CODEGEN_DIR: string = path.dirname(fileURLToPath(import.meta.url));
87
- const SPECS_DIR: string = path.join(CODEGEN_DIR, "..", "specs");
88
- const OUTPUT_DIR: string = path.join(CODEGEN_DIR, "output");
89
- const RAW_SPEC: string = path.join(
90
- SPECS_DIR,
91
- "QuickBase_RESTful_API_2025-03-04T06_22_39.725Z.json"
92
- );
93
- const FIXED_SPEC: string = path.join(OUTPUT_DIR, "quickbase-fixed.json");
94
- const JSON_OUTPUT_FILE: string = path.join(
95
- OUTPUT_DIR,
96
- "override-report.json"
97
- );
98
- const HTML_OUTPUT_FILE: string = path.join(
99
- OUTPUT_DIR,
100
- "override-report.html"
101
- );
102
-
103
- console.log("Cleaning up old override report...");
104
- if (
105
- await fs
106
- .stat(JSON_OUTPUT_FILE)
107
- .then(() => true)
108
- .catch(() => false)
109
- ) {
110
- await fs.unlink(JSON_OUTPUT_FILE);
111
- console.log(`Removed ${JSON_OUTPUT_FILE}`);
112
- }
113
- if (
114
- await fs
115
- .stat(HTML_OUTPUT_FILE)
116
- .then(() => true)
117
- .catch(() => false)
118
- ) {
119
- await fs.unlink(HTML_OUTPUT_FILE);
120
- console.log(`Removed ${HTML_OUTPUT_FILE}`);
121
- } else {
122
- console.log("No old override reports found to remove.");
123
- }
124
-
125
- if (
126
- !(await fs
127
- .stat(RAW_SPEC)
128
- .then(() => true)
129
- .catch(() => false))
130
- ) {
131
- console.error(`Raw spec ${RAW_SPEC} not found.`);
132
- process.exit(1);
133
- }
134
- if (
135
- !(await fs
136
- .stat(FIXED_SPEC)
137
- .then(() => true)
138
- .catch(() => false))
139
- ) {
140
- console.error(
141
- `Fixed spec ${FIXED_SPEC} not found. Run 'npm run fix-spec' first.`
142
- );
143
- process.exit(1);
144
- }
145
-
146
- console.log(`Reading raw spec from ${RAW_SPEC}...`);
147
- const rawContent = await fs.readFile(RAW_SPEC, "utf8");
148
- const rawSpec: Spec = JSON.parse(rawContent);
149
-
150
- console.log(`Reading fixed spec from ${FIXED_SPEC}...`);
151
- const fixedContent = await fs.readFile(FIXED_SPEC, "utf8");
152
- const fixedSpec: Spec = JSON.parse(fixedContent);
153
-
154
- console.log("Generating patch...");
155
- const patch = compare(rawSpec, fixedSpec);
156
-
157
- // Enhance patch with decoded paths and tags inferred from parent operation
158
- const enhancedPatch = patch.map((op) => {
159
- let decodedPath = decodeJsonPointer(op.path);
160
- let tags: string[] = [];
161
- let method: string = "";
162
-
163
- if (op.path.startsWith("/paths")) {
164
- const pathParts = op.path.split("/").filter(Boolean);
165
- if (
166
- pathParts.length >= 3 &&
167
- ["get", "post", "put", "delete"].includes(pathParts[2].toLowerCase())
168
- ) {
169
- const fullPathSegment = "/paths/" + pathParts[1];
170
- const basePath = decodeJsonPointer(fullPathSegment);
171
- method = pathParts[2];
172
- console.log(`Debug: basePath=${basePath}, method=${method}`); // Debug log
173
- if (rawSpec.paths[basePath]?.[method]?.tags) {
174
- tags = rawSpec.paths[basePath][method].tags || [];
175
- } else if (rawSpec.paths[basePath]?.[method]) {
176
- console.log(`No tags found for ${basePath} [${method}]`);
177
- } else {
178
- console.log(`Operation not found: ${basePath} [${method}]`);
179
- }
180
- }
181
- }
182
-
183
- return {
184
- ...op,
185
- decodedPath,
186
- tags: tags.length > 0 ? tags : undefined,
187
- method,
188
- };
189
- });
190
-
191
- console.log("Writing JSON override report...");
192
- await fs.mkdir(OUTPUT_DIR, { recursive: true });
193
- await fs.writeFile(
194
- JSON_OUTPUT_FILE,
195
- JSON.stringify(enhancedPatch, null, 2),
196
- "utf8"
197
- );
198
-
199
- console.log("Writing HTML override report...");
200
- const htmlContent = formatPatchToHtml(enhancedPatch, rawSpec);
201
- await fs.writeFile(HTML_OUTPUT_FILE, htmlContent, "utf8");
202
-
203
- console.log("Override report generated successfully!");
204
- } catch (error) {
205
- console.error("Failed to generate override report:", error);
206
- process.exit(1);
207
- }
208
- }
209
-
210
- async function main() {
211
- await generateOverrideReport();
212
- }
213
-
214
- main();
@@ -1,256 +0,0 @@
1
- #!/usr/bin/env node
2
- console.log("Script started");
3
-
4
- import {
5
- readFileSync,
6
- writeFileSync,
7
- mkdirSync,
8
- existsSync,
9
- readdirSync,
10
- } from "fs";
11
- console.log("FS modules imported");
12
-
13
- import { join, dirname } from "path";
14
- console.log("Path modules imported");
15
-
16
- import { fileURLToPath } from "url";
17
- console.log("URL module imported");
18
-
19
- import { OpenAPIV2 } from "openapi-types"; // Use module name, not relative path
20
- console.log("openapi-types imported");
21
-
22
- // Temporary simplifyName fallback
23
- const simplifyName = (str: string) => str;
24
-
25
- const __dirname = dirname(fileURLToPath(import.meta.url));
26
- console.log("__dirname set:", __dirname);
27
-
28
- const SPEC_FILE = join(__dirname, "output", "quickbase-fixed.json");
29
- const OUTPUT_DIR = join(__dirname, "..", "src", "generated-unified");
30
- const OUTPUT_FILE = join(OUTPUT_DIR, "QuickbaseClient.ts");
31
- const MODELS_DIR = join(__dirname, "..", "src", "generated", "models");
32
-
33
- function mapOpenApiTypeToTs(
34
- openApiType: string | string[] | undefined
35
- ): string {
36
- const type = Array.isArray(openApiType)
37
- ? openApiType[0]
38
- : openApiType || "any";
39
- switch (type.toLowerCase()) {
40
- case "integer":
41
- case "int":
42
- case "number":
43
- return "number";
44
- case "string":
45
- return "string";
46
- case "boolean":
47
- return "boolean";
48
- default:
49
- return "any";
50
- }
51
- }
52
-
53
- function mapRefToType(
54
- schema: OpenAPIV2.SchemaObject | OpenAPIV2.ReferenceObject | undefined,
55
- modelImports: Set<string>,
56
- spec: OpenAPIV2.Document,
57
- depth: number = 0,
58
- availableModels: string[],
59
- missingTypes: Set<string>
60
- ): string {
61
- if (!schema) return "any";
62
-
63
- if ("$ref" in schema && schema.$ref) {
64
- const refParts = schema.$ref.split("/");
65
- const model = refParts[refParts.length - 1];
66
- const pascalModel = model.charAt(0).toUpperCase() + model.slice(1);
67
- if (availableModels.includes(pascalModel)) {
68
- modelImports.add(pascalModel);
69
- return pascalModel;
70
- }
71
- missingTypes.add(pascalModel);
72
- console.warn(`Type ${pascalModel} not found, defaulting to 'any'`);
73
- return "any";
74
- }
75
-
76
- if ("type" in schema) {
77
- if (schema.type === "object" && schema.properties) {
78
- const props = schema.properties;
79
- const propTypes = Object.entries(props).map(([key, prop]) => {
80
- const propSchema = prop as OpenAPIV2.SchemaObject;
81
- const propType = mapRefToType(
82
- propSchema,
83
- modelImports,
84
- spec,
85
- depth + 1,
86
- availableModels,
87
- missingTypes
88
- );
89
- return `${key}${propSchema.required ? "" : "?"}: ${propType}`;
90
- });
91
- return `{ ${propTypes.join("; ")} }`;
92
- }
93
- if (schema.type === "array" && schema.items) {
94
- const items = schema.items as
95
- | OpenAPIV2.SchemaObject
96
- | OpenAPIV2.ReferenceObject;
97
- const itemType = mapRefToType(
98
- items,
99
- modelImports,
100
- spec,
101
- depth + 1,
102
- availableModels,
103
- missingTypes
104
- );
105
- return `${itemType}[]`;
106
- }
107
- return mapOpenApiTypeToTs(schema.type);
108
- }
109
-
110
- return "any";
111
- }
112
-
113
- function generateInterface() {
114
- console.log("Checking spec file:", SPEC_FILE);
115
- if (!existsSync(SPEC_FILE)) {
116
- console.error(
117
- `Spec file ${SPEC_FILE} not found. Run 'npm run fix-spec' first.`
118
- );
119
- process.exit(1);
120
- }
121
-
122
- console.log("Reading spec file...");
123
- const specContent = readFileSync(SPEC_FILE, "utf8");
124
- const spec = JSON.parse(specContent) as OpenAPIV2.Document;
125
- console.log("Spec parsed, keys:", Object.keys(spec));
126
-
127
- const { paths } = spec;
128
- if (!paths) {
129
- console.error("No 'paths' in spec");
130
- process.exit(1);
131
- }
132
-
133
- console.log("Checking models directory:", MODELS_DIR);
134
- if (!existsSync(MODELS_DIR)) {
135
- console.error(
136
- `Models directory ${MODELS_DIR} not found. Run 'npm run gen:openapi' first.`
137
- );
138
- process.exit(1);
139
- }
140
- const availableModels = readdirSync(MODELS_DIR)
141
- .filter((file) => file.endsWith(".ts") && !file.startsWith("index"))
142
- .map((file) => file.replace(".ts", ""));
143
- console.log("Available models:", availableModels);
144
-
145
- const modelImports = new Set<string>();
146
- const missingTypes = new Set<string>();
147
- const methods: string[] = [];
148
-
149
- for (const [path, methodsObj] of Object.entries(
150
- paths as OpenAPIV2.PathsObject
151
- )) {
152
- if (!methodsObj) continue;
153
- for (const [method, operation] of Object.entries(
154
- methodsObj as OpenAPIV2.PathItemObject
155
- )) {
156
- const op = operation as OpenAPIV2.OperationObject | undefined;
157
- if (!op || !op.operationId) continue;
158
-
159
- const opId = simplifyName(op.operationId);
160
- const summary = op.summary || "No description.";
161
- const params = (op.parameters || [])
162
- .filter((p: OpenAPIV2.ParameterObject | OpenAPIV2.ReferenceObject) => {
163
- const param = p as OpenAPIV2.ParameterObject;
164
- return !["QB-Realm-Hostname", "Authorization", "User-Agent"].includes(
165
- param.name || ""
166
- );
167
- })
168
- .map((param: OpenAPIV2.ParameterObject | OpenAPIV2.ReferenceObject) => {
169
- const p = param as OpenAPIV2.ParameterObject;
170
- if (!p.name) return "";
171
- let type = "any";
172
- if ("schema" in p && p.schema) {
173
- type = mapRefToType(
174
- p.schema,
175
- modelImports,
176
- spec,
177
- 1,
178
- availableModels,
179
- missingTypes
180
- );
181
- } else if ("type" in p && p.type) {
182
- type = mapOpenApiTypeToTs(p.type);
183
- }
184
- const paramName = p.in === "body" ? "body" : p.name;
185
- return `${paramName}${p.required ? "" : "?"}: ${type}`;
186
- })
187
- .filter((param) => param !== "")
188
- .join("; ");
189
-
190
- const returnTypes = ["200", "207"]
191
- .map(
192
- (code) => op.responses?.[code] as OpenAPIV2.ResponseObject | undefined
193
- )
194
- .filter((response) => response?.schema)
195
- .map((response) =>
196
- mapRefToType(
197
- response!.schema,
198
- modelImports,
199
- spec,
200
- 1,
201
- availableModels,
202
- missingTypes
203
- )
204
- );
205
- const returnType =
206
- returnTypes.length > 1
207
- ? returnTypes.join(" | ")
208
- : returnTypes[0] || "void";
209
-
210
- const jsDoc = [
211
- ` /**`,
212
- ` * ${summary}`,
213
- ` * @param params - Parameters for ${opId}`,
214
- ` * @returns Promise resolving to ${opId} response`,
215
- ` */`,
216
- ].join("\n");
217
-
218
- methods.push(
219
- `${jsDoc}\n ${opId}: (params: { ${params} }) => Promise<${returnType}>;`
220
- );
221
- }
222
- }
223
-
224
- console.log("Writing missing types report...");
225
- writeFileSync(
226
- join(OUTPUT_DIR, "missing-types-report.json"),
227
- JSON.stringify({ missingTypes: Array.from(missingTypes) }, null, 2)
228
- );
229
-
230
- const importStatement =
231
- modelImports.size > 0
232
- ? `import { ${Array.from(modelImports)
233
- .sort()
234
- .join(", ")} } from "../generated/models";`
235
- : "";
236
- const interfaceContent = `// Generated on ${new Date().toISOString()}\n${importStatement}\n\nexport interface QuickbaseClient {\n${methods.join(
237
- "\n"
238
- )}\n}\n`;
239
-
240
- console.log("Ensuring output directory exists...");
241
- if (!existsSync(OUTPUT_DIR)) {
242
- mkdirSync(OUTPUT_DIR, { recursive: true });
243
- }
244
- writeFileSync(OUTPUT_FILE, interfaceContent, "utf8");
245
- console.log("Generated:", OUTPUT_FILE);
246
- }
247
-
248
- console.log("Entering try block");
249
- try {
250
- generateInterface();
251
- } catch (error) {
252
- console.error("Error in generateInterface:", error);
253
- process.exit(1);
254
- }
255
-
256
- console.log("Script completed");