api 7.0.0-beta.0 → 7.0.0-beta.1

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 (52) hide show
  1. package/dist/codegen/codegenerator.d.ts +9 -11
  2. package/dist/codegen/codegenerator.d.ts.map +1 -1
  3. package/dist/codegen/codegenerator.js +11 -0
  4. package/dist/codegen/codegenerator.js.map +1 -1
  5. package/dist/codegen/factory.d.ts +19 -3
  6. package/dist/codegen/factory.d.ts.map +1 -1
  7. package/dist/codegen/factory.js +12 -5
  8. package/dist/codegen/factory.js.map +1 -1
  9. package/dist/codegen/languages/typescript/index.d.ts +8 -2
  10. package/dist/codegen/languages/typescript/index.d.ts.map +1 -1
  11. package/dist/codegen/languages/typescript/index.js +61 -15
  12. package/dist/codegen/languages/typescript/index.js.map +1 -1
  13. package/dist/commands/index.d.ts +2 -0
  14. package/dist/commands/index.d.ts.map +1 -1
  15. package/dist/commands/index.js +4 -0
  16. package/dist/commands/index.js.map +1 -1
  17. package/dist/commands/install.d.ts.map +1 -1
  18. package/dist/commands/install.js +5 -5
  19. package/dist/commands/install.js.map +1 -1
  20. package/dist/commands/list.d.ts +4 -0
  21. package/dist/commands/list.d.ts.map +1 -0
  22. package/dist/commands/list.js +37 -0
  23. package/dist/commands/list.js.map +1 -0
  24. package/dist/commands/uninstall.d.ts +4 -0
  25. package/dist/commands/uninstall.d.ts.map +1 -0
  26. package/dist/commands/uninstall.js +72 -0
  27. package/dist/commands/uninstall.js.map +1 -0
  28. package/dist/lockfileSchema.d.ts +125 -0
  29. package/dist/lockfileSchema.d.ts.map +1 -0
  30. package/dist/lockfileSchema.js +78 -0
  31. package/dist/lockfileSchema.js.map +1 -0
  32. package/dist/packageInfo.d.ts +1 -1
  33. package/dist/packageInfo.js +1 -1
  34. package/dist/storage.d.ts +75 -60
  35. package/dist/storage.d.ts.map +1 -1
  36. package/dist/storage.js +85 -25
  37. package/dist/storage.js.map +1 -1
  38. package/package.json +14 -7
  39. package/schema.json +69 -0
  40. package/src/bin.ts +0 -21
  41. package/src/codegen/codegenerator.ts +0 -75
  42. package/src/codegen/factory.ts +0 -23
  43. package/src/codegen/languages/typescript/index.ts +0 -984
  44. package/src/codegen/languages/typescript/util.ts +0 -174
  45. package/src/commands/index.ts +0 -5
  46. package/src/commands/install.ts +0 -196
  47. package/src/fetcher.ts +0 -145
  48. package/src/lib/prompt.ts +0 -29
  49. package/src/logger.ts +0 -10
  50. package/src/packageInfo.ts +0 -3
  51. package/src/storage.ts +0 -333
  52. package/tsconfig.json +0 -10
package/src/storage.ts DELETED
@@ -1,333 +0,0 @@
1
- import type { OASDocument } from 'oas/rmoas.types';
2
-
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
-
6
- import ssri from 'ssri';
7
- import validateNPMPackageName from 'validate-npm-package-name';
8
-
9
- import Fetcher from './fetcher.js';
10
- import { PACKAGE_VERSION } from './packageInfo.js';
11
-
12
- export default class Storage {
13
- static dir: string;
14
-
15
- static lockfile: false | Lockfile;
16
-
17
- /**
18
- * This is the original source that the file came from (relative/absolute file path, URL, ReadMe
19
- * registry UUID, etc.).
20
- */
21
- source: string;
22
-
23
- identifier!: string;
24
-
25
- fetcher: Fetcher;
26
-
27
- constructor(source: string, identifier?: string) {
28
- Storage.setStorageDir();
29
-
30
- this.fetcher = new Fetcher(source);
31
-
32
- this.source = source;
33
- if (identifier) {
34
- this.identifier = identifier;
35
- }
36
-
37
- // This should default to false so we have awareness if we've looked at the lockfile yet.
38
- Storage.lockfile = false;
39
- }
40
-
41
- static getLockfilePath() {
42
- return path.join(Storage.dir, 'api.json');
43
- }
44
-
45
- static getAPIsDir() {
46
- return path.join(Storage.dir, 'apis');
47
- }
48
-
49
- static setStorageDir(dir?: string) {
50
- if (dir) {
51
- Storage.dir = dir;
52
- return;
53
- } else if (Storage.dir) {
54
- // If we already have a storage dir set and aren't explicitly it to something new then we
55
- // shouldn't overwrite what we've already got.
56
- return;
57
- }
58
-
59
- Storage.dir = path.join(process.cwd(), '.api');
60
-
61
- fs.mkdirSync(Storage.dir, { recursive: true });
62
- fs.mkdirSync(Storage.getAPIsDir(), { recursive: true });
63
- }
64
-
65
- /**
66
- * Reset the state of the entire storage system.
67
- *
68
- * This will completely destroy the contents of the `.api/` directory!
69
- */
70
- static async reset() {
71
- if (Storage.getLockfilePath()) {
72
- await fs.promises.writeFile(Storage.getLockfilePath(), JSON.stringify(Storage.getDefaultLockfile(), null, 2));
73
- }
74
-
75
- if (Storage.getAPIsDir()) {
76
- await fs.promises.rm(Storage.getAPIsDir(), { recursive: true });
77
- await fs.promises.mkdir(Storage.getAPIsDir(), { recursive: true });
78
- }
79
- }
80
-
81
- static getDefaultLockfile(): Lockfile {
82
- return {
83
- version: '1.0',
84
- apis: [],
85
- };
86
- }
87
-
88
- static generateIntegrityHash(definition: OASDocument) {
89
- return ssri
90
- .fromData(JSON.stringify(definition), {
91
- algorithms: ['sha512'],
92
- })
93
- .toString();
94
- }
95
-
96
- static getLockfile() {
97
- if (typeof Storage.lockfile === 'object') {
98
- return Storage.lockfile;
99
- }
100
-
101
- if (fs.existsSync(Storage.getLockfilePath())) {
102
- const file = fs.readFileSync(Storage.getLockfilePath(), 'utf8');
103
- Storage.lockfile = JSON.parse(file) as Lockfile;
104
- } else {
105
- Storage.lockfile = Storage.getDefaultLockfile();
106
- }
107
-
108
- return Storage.lockfile;
109
- }
110
-
111
- static isIdentifierValid(identifier: string, prefixWithAPINamespace?: boolean) {
112
- // Is this identifier already in storage?
113
- if (Storage.isInLockFile({ identifier })) {
114
- throw new Error(`"${identifier}" is already taken in your \`.api/\` directory. Please try another identifier.`);
115
- }
116
-
117
- const isValidForNPM = validateNPMPackageName(prefixWithAPINamespace ? `@api/${identifier}` : identifier);
118
- if (!isValidForNPM.validForNewPackages) {
119
- // `prompts` doesn't support surfacing multiple errors in a `validate` call so we can only
120
- // surface the first to the user.
121
- throw new Error(
122
- `Identifier cannot be used for an NPM package: ${isValidForNPM?.errors?.[0] || '[error unavailable]'}`,
123
- );
124
- }
125
-
126
- return true;
127
- }
128
-
129
- static isInLockFile(search: { identifier?: string; source?: string }) {
130
- // Because this method may run before we initialize a new storage object we should make sure
131
- // that we have a storage directory present.
132
- Storage.setStorageDir();
133
-
134
- if (!search.identifier && !search.source) {
135
- throw new TypeError('An `identifier` or `source` must be supplied to this method to search in the lockfile.');
136
- }
137
-
138
- const lockfile = Storage.getLockfile();
139
- if (typeof lockfile !== 'object' || lockfile === null || !lockfile.apis) {
140
- return false;
141
- }
142
-
143
- const res = lockfile.apis.find(a => {
144
- if (search.identifier) {
145
- return a.identifier === search.identifier;
146
- }
147
-
148
- return a.source === search.source;
149
- });
150
-
151
- return res === undefined ? false : res;
152
- }
153
-
154
- setIdentifier(identifier: string) {
155
- this.identifier = identifier;
156
- }
157
-
158
- /**
159
- * Determine if the current spec + identifier we're working with is already in the lockfile.
160
- */
161
- isInLockfile() {
162
- return Boolean(this.getFromLockfile());
163
- }
164
-
165
- /**
166
- * Retrieve the lockfile record for the current spec + identifier if it exists in the lockfile.
167
- */
168
- getFromLockfile() {
169
- const lockfile = Storage.getLockfile();
170
- return lockfile.apis.find(a => a.identifier === this.identifier);
171
- }
172
-
173
- getIdentifierStorageDir() {
174
- if (!this.isInLockfile()) {
175
- throw new Error(`${this.source} has not been saved to storage yet and must do so before being retrieved.`);
176
- }
177
-
178
- return path.join(Storage.getAPIsDir(), this.identifier);
179
- }
180
-
181
- getAPIDefinition() {
182
- const file = fs.readFileSync(path.join(this.getIdentifierStorageDir(), 'openapi.json'), 'utf8');
183
-
184
- return JSON.parse(file);
185
- }
186
-
187
- saveSourceFiles(files: Record<string, string>) {
188
- if (!this.isInLockfile()) {
189
- throw new Error(`${this.source} has not been saved to storage yet and must do so before being retrieved.`);
190
- }
191
-
192
- return new Promise(resolve => {
193
- const savedSource: string[] = [];
194
- Object.entries(files).forEach(([fileName, contents]) => {
195
- const sourceFilePath = path.join(this.getIdentifierStorageDir(), fileName);
196
-
197
- // If this file is stored in a subdirectory then we need to create it.
198
- if (path.dirname(fileName) !== '.') {
199
- const dir = path.dirname(fileName);
200
- const dirPath = path.join(this.getIdentifierStorageDir(), dir);
201
- if (!fs.existsSync(dirPath)) {
202
- fs.mkdirSync(dirPath);
203
- }
204
- }
205
-
206
- fs.writeFileSync(sourceFilePath, contents);
207
-
208
- savedSource.push(sourceFilePath);
209
- });
210
-
211
- resolve(savedSource);
212
- });
213
- }
214
-
215
- async load(shouldSave: boolean = true) {
216
- return this.fetcher.load().then(async spec => {
217
- if (shouldSave) {
218
- return this.save(spec);
219
- }
220
-
221
- return spec;
222
- });
223
- }
224
-
225
- /**
226
- * @example <caption>Storage directory structure</caption>
227
- * .api/
228
- * ├── api.json // The `package-lock.json` equivalent that records everything that's
229
- * | // installed, when it was installed, what the original source was,
230
- * | // and what version of `api` was used.
231
- * └── apis/
232
- * ├── readme/
233
- * | ├── node_modules/
234
- * │ ├── index.js // We may offer the option to export a raw TS file for folks who want
235
- * | | // that, but for now it'll be a compiled JS file.
236
- * │ ├── index.d.ts // All types for their SDK, ready to use in an IDE.
237
- * │ |── openapi.json
238
- * │ └── package.json
239
- * └── petstore/
240
- * ├── node_modules/
241
- * ├── index.js
242
- * ├── index.d.ts
243
- * ├── openapi.json
244
- * └── package.json
245
- *
246
- */
247
- save(spec: OASDocument) {
248
- if (!this.identifier) {
249
- throw new TypeError('An identifier must be set before saving the API definition into storage.');
250
- }
251
-
252
- // Create our main `.api/` directory.
253
- if (!fs.existsSync(Storage.dir)) {
254
- fs.mkdirSync(Storage.dir, { recursive: true });
255
- }
256
-
257
- // Create the `.api/apis/` diretory where we'll be storing API definitions.
258
- if (!fs.existsSync(Storage.getAPIsDir())) {
259
- fs.mkdirSync(Storage.getAPIsDir(), { recursive: true });
260
- }
261
-
262
- if (!this.isInLockfile()) {
263
- // This API doesn't exist within our storage system yet so we need to record it in the
264
- // lockfile.
265
- const identifierStorageDir = path.join(Storage.getAPIsDir(), this.identifier);
266
- const saved = JSON.stringify(spec, null, 2);
267
-
268
- // Create the `.api/apis/<identifier>` directory where we'll be storing this API definition
269
- // and eventually its codegen'd SDK.
270
- if (!fs.existsSync(identifierStorageDir)) {
271
- fs.mkdirSync(identifierStorageDir, { recursive: true });
272
- }
273
-
274
- (Storage.lockfile as Lockfile).apis.push({
275
- identifier: this.identifier,
276
- source: this.source,
277
- integrity: Storage.generateIntegrityHash(spec),
278
- installerVersion: PACKAGE_VERSION,
279
- } as LockfileAPI);
280
-
281
- fs.writeFileSync(path.join(identifierStorageDir, 'openapi.json'), saved);
282
- fs.writeFileSync(Storage.getLockfilePath(), JSON.stringify(Storage.lockfile, null, 2));
283
- } else {
284
- // Is this the same spec that we already have? Should we update it? // @todo
285
- }
286
-
287
- return spec;
288
- }
289
- }
290
-
291
- interface Lockfile {
292
- apis: LockfileAPI[];
293
-
294
- /**
295
- * The `api.json` schema version. This will only ever change if we introduce breaking changes to
296
- * this store.
297
- */
298
- version: '1.0';
299
- }
300
-
301
- interface LockfileAPI {
302
- /**
303
- * A unique identifier of the API. This'll be used to do requires on `@api/<identifier>` and also
304
- * where the SDK code will be located in `.api/apis/<identifier>`.
305
- *
306
- * @example petstore
307
- */
308
- identifier: string;
309
-
310
- /**
311
- * The version of `api` that was used to install this SDK.
312
- *
313
- * @example 5.0.0
314
- */
315
- installerVersion: string;
316
-
317
- /**
318
- * An integrity hash that will be used to determine on `npx api update` calls if the API has
319
- * changed since the SDK was last generated.
320
- *
321
- * @example sha512-ld+djZk8uRWmzXC+JYla1PTBScg0NjP/8x9vOOKRW+DuJ3NNMRjrpfbY7T77Jgnc87dZZsU49robbQfYe3ukug==
322
- */
323
- integrity: string;
324
-
325
- /**
326
- * The original source that was used to generate the SDK with.
327
- *
328
- * @example https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore-simple.json
329
- * @example ./petstore.json
330
- * @example @developers/v2.0#nysezql0wwo236
331
- */
332
- source: string;
333
- }
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "lib": ["DOM", "DOM.Iterable", "ES2023"],
5
- "module": "NodeNext",
6
- "outDir": "dist/",
7
- "resolveJsonModule": true
8
- },
9
- "include": ["./src/**/*"]
10
- }