quickbase-js 0.1.0-beta.7 → 0.1.0-beta.9
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/CHANGELOG.md +55 -0
- package/README.md +46 -130
- package/dist/esm/quickbase.d.ts +1292 -125
- package/dist/esm/quickbase.js +666 -190
- package/dist/esm/quickbase.js.map +1 -1
- package/dist/esm/quickbase.min.js +1 -1
- package/dist/esm/quickbase.min.js.map +1 -1
- package/dist/umd/quickbase.umd.js +674 -189
- package/dist/umd/quickbase.umd.js.map +1 -1
- package/dist/umd/quickbase.umd.min.js +1 -1
- package/dist/umd/quickbase.umd.min.js.map +1 -1
- package/open-api/fix-spec-main.ts +69 -68
- package/open-api/generate-override-report.ts +214 -0
- package/open-api/generate-unified-interface.ts +162 -103
- package/open-api/output/override-report.html +11 -0
- package/open-api/output/override-report.json +14395 -58
- package/open-api/output/quickbase-fixed.json +583 -2
- package/open-api/schema/tags/fields.ts +331 -16
- package/open-api/schema/tags/index.ts +2 -4
- package/open-api/types/spec.ts +2 -1
- package/open-api/utils/generateJsDoc.ts +96 -0
- package/package.json +33 -33
- package/src/RateLimitError.ts +12 -0
- package/src/ThrottleBucket.ts +41 -0
- package/src/authorizationStrategy.ts +246 -0
- package/src/generated-unified/QuickbaseClient.ts +809 -119
- package/src/invokeMethod.ts +242 -0
- package/src/quickbaseClient.ts +117 -248
- package/src/rateLimiter.ts +25 -0
- package/src/tokenCache.ts +10 -26
- package/tests/setup.ts +2 -0
- package/tests/vitest/qb/apps/getApp.test.ts +6 -2
- package/tests/vitest/qb/apps/getAppEvents.test.ts +67 -0
- package/tests/vitest/qb/apps/updateApp.test.ts +58 -0
- package/tests/vitest/qb/auth/mockQuickbaseServer.ts +60 -0
- package/tests/vitest/qb/auth/retryUserToken401.test.ts +73 -0
- package/tests/vitest/qb/auth/ssoTokenIntegrationWithServer.test.ts +65 -0
- package/tests/vitest/qb/fields/createField.test.ts +1 -2
- package/tests/vitest/qb/fields/deleteFields.test.ts +10 -16
- package/tests/vitest/qb/fields/getFieldUsage.test.ts +58 -150
- package/tests/vitest/qb/fields/updateField.test.ts +93 -0
- package/tests/vitest/qb/formulas/runFormula.test.ts +96 -0
- package/tests/vitest/qb/index.ts +1 -0
- package/tests/vitest/qb/tables/createRelationship.test.ts +102 -0
- package/tests/vitest/qb/tables/deleteRelationship.test.ts +143 -0
- package/tests/vitest/qb/tables/updateRelationship.test.ts +250 -0
- package/tests/vitest/unit/ThrottleBucket.test.ts +95 -0
- package/tests/vitest/unit/apps/copyApp.test.ts +133 -40
- package/tests/vitest/unit/apps/getAppEvents.test.ts +193 -0
- package/tests/vitest/unit/apps/updateApp.test.ts +412 -0
- package/tests/vitest/unit/auth/fetchTempToken401.test.ts +7 -26
- package/tests/vitest/unit/auth/getTempToken.test.ts +42 -18
- package/tests/vitest/unit/auth/retryTempToken401.test.ts +95 -0
- package/tests/vitest/unit/auth/retryTempTokenMaxRetries.test.ts +235 -0
- package/tests/vitest/unit/auth/retryUserToken401.test.ts +69 -0
- package/tests/vitest/unit/auth/ssoTokenRefresh.test.ts +325 -0
- package/tests/vitest/unit/fields/createField.test.ts +180 -120
- package/tests/vitest/unit/fields/getFieldUsage.test.ts +47 -14
- package/tests/vitest/unit/fields/updateField.test.ts +285 -0
- package/tests/vitest/unit/formulas/runFormula.test.ts +205 -0
- package/tests/vitest/unit/index.ts +2 -1
- package/tests/vitest/unit/inferHttpMethod.test.ts +131 -0
- package/tests/vitest/unit/rateLimit.test.ts +191 -0
- package/tests/vitest/unit/tables/createRelationship.test.ts +212 -0
- package/tests/vitest/unit/tables/deleteRelationship.test.ts +97 -0
- package/tests/vitest/unit/tables/updateRelationship.test.ts +307 -0
- package/tests/vitest/unit/tokenLifespan.test.ts +204 -0
- package/tools/log-gen.ts +20 -7
- package/tools/log-gen.yaml +3446 -1848
- package/tsconfig.json +5 -2
- package/vitest.config.ts +2 -2
- package/notes.txt +0 -158
- package/tests/vitest/unit/auth/retryOn401.test.ts +0 -116
- package/tests/vitest/unit/auth/two401s.test.ts +0 -86
- package/tools/generate-types.ts +0 -29
- package/tools/openapi-schema-validator.ts +0 -38
- package/tools/spec-analyzer.ts +0 -163
- package/tools/split-spec.ts +0 -148
- package/tools/test-import.ts +0 -3
- package/tools/validate-spec.ts +0 -40
- /package/tests/playwright/qb/auth/{tokenPrefetch.test.ts → tempTokenPrefetch.test.ts} +0 -0
- /package/tests/playwright/qb/auth/{tokenRenewal.test.ts → tempTokenRenewal.test.ts} +0 -0
package/tools/split-spec.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
// tools/split-spec.ts
|
|
2
|
-
import { promises as fs } from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { fileURLToPath } from "url";
|
|
5
|
-
import * as glob from "glob";
|
|
6
|
-
|
|
7
|
-
interface Parameter {
|
|
8
|
-
name: string;
|
|
9
|
-
in: string;
|
|
10
|
-
required?: boolean;
|
|
11
|
-
type?: string;
|
|
12
|
-
schema?: any;
|
|
13
|
-
example?: any;
|
|
14
|
-
description?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface Operation {
|
|
18
|
-
parameters?: Parameter[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface Spec {
|
|
22
|
-
swagger?: string;
|
|
23
|
-
openapi?: string;
|
|
24
|
-
info: any;
|
|
25
|
-
paths: Record<string, Record<string, Operation>>;
|
|
26
|
-
definitions?: Record<string, any>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function normalizeParameters(parameters: Parameter[] = []): Parameter[] {
|
|
30
|
-
return parameters.map((param) => {
|
|
31
|
-
const normalized: Parameter = {
|
|
32
|
-
name: param.name,
|
|
33
|
-
in: param.in,
|
|
34
|
-
required: param.required,
|
|
35
|
-
description: param.description,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// OpenAPI v2: 'body' parameters use 'schema', others use 'type'
|
|
39
|
-
if (param.in === "body") {
|
|
40
|
-
if (param.schema) {
|
|
41
|
-
normalized.schema = param.schema;
|
|
42
|
-
}
|
|
43
|
-
} else {
|
|
44
|
-
normalized.type = param.type || "string";
|
|
45
|
-
if (param.example !== undefined) {
|
|
46
|
-
delete param.example; // Remove 'example' as it’s not allowed in v2
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Ensure 'in' is valid
|
|
51
|
-
if (
|
|
52
|
-
!["query", "header", "path", "formData", "body"].includes(normalized.in)
|
|
53
|
-
) {
|
|
54
|
-
console.warn(
|
|
55
|
-
`Invalid 'in' value '${normalized.in}' for parameter '${normalized.name}', defaulting to 'query'`
|
|
56
|
-
);
|
|
57
|
-
normalized.in = "query";
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return normalized;
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function splitSpec(): Promise<void> {
|
|
65
|
-
const CODEGEN_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
66
|
-
const SPECS_DIR = path.join(CODEGEN_DIR, "..", "specs");
|
|
67
|
-
const OUTPUT_DIR = path.join(SPECS_DIR, "split");
|
|
68
|
-
|
|
69
|
-
// Find the latest spec file
|
|
70
|
-
const specFiles = glob.sync(path.join(SPECS_DIR, "QuickBase_RESTful_*.json"));
|
|
71
|
-
if (specFiles.length === 0) {
|
|
72
|
-
console.error("No QuickBase_RESTful_*.json files found in specs/ folder.");
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
const inputFile = specFiles.sort().pop() as string;
|
|
76
|
-
const specContent = await fs.readFile(inputFile, "utf8");
|
|
77
|
-
const spec: Spec = JSON.parse(specContent);
|
|
78
|
-
|
|
79
|
-
// Define categories based on endpoint paths
|
|
80
|
-
const categories: Record<string, string[]> = {
|
|
81
|
-
apps: Object.keys(spec.paths).filter((p) => p.startsWith("/apps")),
|
|
82
|
-
auth: Object.keys(spec.paths).filter((p) => p.startsWith("/auth")),
|
|
83
|
-
fields: Object.keys(spec.paths).filter((p) => p.startsWith("/fields")),
|
|
84
|
-
records: Object.keys(spec.paths).filter((p) => p.startsWith("/records")),
|
|
85
|
-
tables: Object.keys(spec.paths).filter((p) => p.startsWith("/tables")),
|
|
86
|
-
reports: Object.keys(spec.paths).filter((p) => p.startsWith("/reports")),
|
|
87
|
-
relationships: Object.keys(spec.paths).filter((p) =>
|
|
88
|
-
p.startsWith("/relationships")
|
|
89
|
-
),
|
|
90
|
-
events: Object.keys(spec.paths).filter((p) => p.startsWith("/events")),
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
await fs.mkdir(OUTPUT_DIR, { recursive: true });
|
|
94
|
-
|
|
95
|
-
// Split spec by category
|
|
96
|
-
for (const [category, paths] of Object.entries(categories)) {
|
|
97
|
-
if (paths.length === 0) continue;
|
|
98
|
-
|
|
99
|
-
const categorySpec: Spec = {
|
|
100
|
-
swagger: "2.0", // OpenAPI v2
|
|
101
|
-
info: spec.info || { title: `${category} API`, version: "1.0.0" },
|
|
102
|
-
paths: {},
|
|
103
|
-
definitions: {},
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// Add relevant paths and normalize parameters
|
|
107
|
-
for (const p of paths) {
|
|
108
|
-
const pathObj = { ...spec.paths[p] };
|
|
109
|
-
for (const method in pathObj) {
|
|
110
|
-
if (pathObj[method].parameters) {
|
|
111
|
-
pathObj[method].parameters = normalizeParameters(
|
|
112
|
-
pathObj[method].parameters
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
categorySpec.paths[p] = pathObj;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Add relevant definitions
|
|
120
|
-
const refs = new Set<string>();
|
|
121
|
-
const refRegex = /#\/definitions\/([^"]+)/g;
|
|
122
|
-
const categorySpecString = JSON.stringify(categorySpec);
|
|
123
|
-
let match;
|
|
124
|
-
while ((match = refRegex.exec(categorySpecString))) {
|
|
125
|
-
refs.add(match[1]);
|
|
126
|
-
}
|
|
127
|
-
if (spec.definitions) {
|
|
128
|
-
for (const ref of refs) {
|
|
129
|
-
if (spec.definitions[ref]) {
|
|
130
|
-
categorySpec.definitions![ref] = spec.definitions[ref];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const outputFile = path.join(OUTPUT_DIR, `${category}.json`);
|
|
136
|
-
await fs.writeFile(
|
|
137
|
-
outputFile,
|
|
138
|
-
JSON.stringify(categorySpec, null, 2),
|
|
139
|
-
"utf8"
|
|
140
|
-
);
|
|
141
|
-
console.log(`Wrote ${outputFile}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
splitSpec().catch((error) => {
|
|
146
|
-
console.error("Failed to split spec:", error);
|
|
147
|
-
process.exit(1);
|
|
148
|
-
});
|
package/tools/test-import.ts
DELETED
package/tools/validate-spec.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// tools/validate-spec.ts
|
|
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 OpenAPISchemaValidatorModule from "openapi-schema-validator";
|
|
7
|
-
|
|
8
|
-
const OpenAPISchemaValidator = OpenAPISchemaValidatorModule.default;
|
|
9
|
-
|
|
10
|
-
async function validateSpecs(): Promise<void> {
|
|
11
|
-
const CODEGEN_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
const SPLIT_DIR = path.join(CODEGEN_DIR, "..", "specs", "split");
|
|
13
|
-
|
|
14
|
-
const specFiles = glob.sync(path.join(SPLIT_DIR, "*.json"));
|
|
15
|
-
if (specFiles.length === 0) {
|
|
16
|
-
console.error("No split spec files found in specs/split/ folder.");
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const validator = new OpenAPISchemaValidator({ version: 2 });
|
|
21
|
-
|
|
22
|
-
for (const specFile of specFiles) {
|
|
23
|
-
console.log(`Validating ${path.basename(specFile)}...`);
|
|
24
|
-
const specContent = await fs.readFile(specFile, "utf8");
|
|
25
|
-
const spec = JSON.parse(specContent);
|
|
26
|
-
|
|
27
|
-
const result = validator.validate(spec);
|
|
28
|
-
if (result.errors.length > 0) {
|
|
29
|
-
console.error(`Validation errors in ${specFile}:`, result.errors);
|
|
30
|
-
process.exit(1);
|
|
31
|
-
} else {
|
|
32
|
-
console.log(`${specFile} is valid.`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
validateSpecs().catch((error) => {
|
|
38
|
-
console.error("Failed to validate specs:", error);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
});
|
|
File without changes
|
|
File without changes
|