@workos/oagen-emitters 0.2.0 → 0.3.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.
- package/.husky/pre-commit +1 -0
- package/.oxfmtrc.json +8 -1
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +15 -0
- package/README.md +129 -0
- package/dist/index.d.mts +10 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +11943 -2728
- package/dist/index.mjs.map +1 -1
- package/docs/sdk-architecture/go.md +338 -0
- package/docs/sdk-architecture/php.md +315 -0
- package/docs/sdk-architecture/python.md +511 -0
- package/oagen.config.ts +298 -2
- package/package.json +9 -5
- package/scripts/generate-php.js +13 -0
- package/scripts/git-push-with-published-oagen.sh +21 -0
- package/smoke/sdk-dotnet.ts +17 -3
- package/smoke/sdk-elixir.ts +17 -3
- package/smoke/sdk-go.ts +137 -46
- package/smoke/sdk-kotlin.ts +23 -4
- package/smoke/sdk-node.ts +15 -3
- package/smoke/sdk-php.ts +28 -26
- package/smoke/sdk-python.ts +5 -2
- package/smoke/sdk-ruby.ts +17 -3
- package/smoke/sdk-rust.ts +16 -3
- package/src/go/client.ts +141 -0
- package/src/go/enums.ts +196 -0
- package/src/go/fixtures.ts +212 -0
- package/src/go/index.ts +81 -0
- package/src/go/manifest.ts +36 -0
- package/src/go/models.ts +254 -0
- package/src/go/naming.ts +191 -0
- package/src/go/resources.ts +827 -0
- package/src/go/tests.ts +751 -0
- package/src/go/type-map.ts +82 -0
- package/src/go/wrappers.ts +261 -0
- package/src/index.ts +3 -0
- package/src/node/client.ts +167 -122
- package/src/node/enums.ts +13 -4
- package/src/node/errors.ts +42 -233
- package/src/node/field-plan.ts +726 -0
- package/src/node/fixtures.ts +15 -5
- package/src/node/index.ts +65 -16
- package/src/node/models.ts +264 -96
- package/src/node/naming.ts +52 -25
- package/src/node/resources.ts +621 -172
- package/src/node/sdk-errors.ts +41 -0
- package/src/node/tests.ts +71 -27
- package/src/node/type-map.ts +4 -2
- package/src/node/utils.ts +56 -64
- package/src/node/wrappers.ts +151 -0
- package/src/php/client.ts +171 -0
- package/src/php/enums.ts +67 -0
- package/src/php/errors.ts +9 -0
- package/src/php/fixtures.ts +181 -0
- package/src/php/index.ts +96 -0
- package/src/php/manifest.ts +36 -0
- package/src/php/models.ts +310 -0
- package/src/php/naming.ts +298 -0
- package/src/php/resources.ts +561 -0
- package/src/php/tests.ts +533 -0
- package/src/php/type-map.ts +90 -0
- package/src/php/utils.ts +18 -0
- package/src/php/wrappers.ts +151 -0
- package/src/python/client.ts +337 -0
- package/src/python/enums.ts +313 -0
- package/src/python/fixtures.ts +196 -0
- package/src/python/index.ts +95 -0
- package/src/python/manifest.ts +38 -0
- package/src/python/models.ts +688 -0
- package/src/python/naming.ts +209 -0
- package/src/python/resources.ts +1322 -0
- package/src/python/tests.ts +1335 -0
- package/src/python/type-map.ts +93 -0
- package/src/python/wrappers.ts +191 -0
- package/src/shared/model-utils.ts +255 -0
- package/src/shared/naming-utils.ts +107 -0
- package/src/shared/non-spec-services.ts +54 -0
- package/src/shared/resolved-ops.ts +109 -0
- package/src/shared/wrapper-utils.ts +59 -0
- package/test/go/client.test.ts +92 -0
- package/test/go/enums.test.ts +132 -0
- package/test/go/errors.test.ts +9 -0
- package/test/go/models.test.ts +265 -0
- package/test/go/resources.test.ts +408 -0
- package/test/go/tests.test.ts +143 -0
- package/test/node/client.test.ts +199 -94
- package/test/node/enums.test.ts +75 -3
- package/test/node/errors.test.ts +2 -41
- package/test/node/models.test.ts +109 -20
- package/test/node/naming.test.ts +37 -4
- package/test/node/resources.test.ts +662 -30
- package/test/node/serializers.test.ts +36 -7
- package/test/node/type-map.test.ts +11 -0
- package/test/php/client.test.ts +94 -0
- package/test/php/enums.test.ts +173 -0
- package/test/php/errors.test.ts +9 -0
- package/test/php/models.test.ts +497 -0
- package/test/php/resources.test.ts +644 -0
- package/test/php/tests.test.ts +118 -0
- package/test/python/client.test.ts +200 -0
- package/test/python/enums.test.ts +228 -0
- package/test/python/errors.test.ts +16 -0
- package/test/python/manifest.test.ts +74 -0
- package/test/python/models.test.ts +716 -0
- package/test/python/resources.test.ts +617 -0
- package/test/python/tests.test.ts +202 -0
- package/src/node/common.ts +0 -273
- package/src/node/config.ts +0 -71
- package/src/node/serializers.ts +0 -744
package/test/node/client.test.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
2
2
|
import { generateClient } from '../../src/node/client.js';
|
|
3
3
|
import { isServiceCoveredByExisting } from '../../src/node/utils.js';
|
|
4
4
|
import type { EmitterContext, ApiSpec, Service, Model, Enum } from '@workos/oagen';
|
|
5
|
+
import { defaultSdkBehavior } from '@workos/oagen';
|
|
5
6
|
import type { ApiSurface } from '@workos/oagen/compat';
|
|
6
7
|
|
|
7
8
|
const service: Service = {
|
|
@@ -11,7 +12,13 @@ const service: Service = {
|
|
|
11
12
|
name: 'getOrganization',
|
|
12
13
|
httpMethod: 'get',
|
|
13
14
|
path: '/organizations/{id}',
|
|
14
|
-
pathParams: [
|
|
15
|
+
pathParams: [
|
|
16
|
+
{
|
|
17
|
+
name: 'id',
|
|
18
|
+
type: { kind: 'primitive', type: 'string' },
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
],
|
|
15
22
|
queryParams: [],
|
|
16
23
|
headerParams: [],
|
|
17
24
|
response: { kind: 'model', name: 'Organization' },
|
|
@@ -25,7 +32,11 @@ const model: Model = {
|
|
|
25
32
|
name: 'Organization',
|
|
26
33
|
fields: [
|
|
27
34
|
{ name: 'id', type: { kind: 'primitive', type: 'string' }, required: true },
|
|
28
|
-
{
|
|
35
|
+
{
|
|
36
|
+
name: 'name',
|
|
37
|
+
type: { kind: 'primitive', type: 'string' },
|
|
38
|
+
required: true,
|
|
39
|
+
},
|
|
29
40
|
],
|
|
30
41
|
};
|
|
31
42
|
|
|
@@ -36,6 +47,7 @@ const spec: ApiSpec = {
|
|
|
36
47
|
services: [service],
|
|
37
48
|
models: [model],
|
|
38
49
|
enums: [],
|
|
50
|
+
sdk: defaultSdkBehavior(),
|
|
39
51
|
};
|
|
40
52
|
|
|
41
53
|
const ctx: EmitterContext = {
|
|
@@ -88,21 +100,16 @@ describe('generateClient', () => {
|
|
|
88
100
|
expect(serviceBarrel!.skipIfExists).toBe(true);
|
|
89
101
|
});
|
|
90
102
|
|
|
91
|
-
it('
|
|
103
|
+
it('does not generate package.json, tsconfig.json, or worker barrel (now hand-maintained)', () => {
|
|
92
104
|
const files = generateClient(spec, ctx);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
expect(pkg).toBeDefined();
|
|
97
|
-
expect(pkg!.skipIfExists).toBe(true);
|
|
98
|
-
|
|
99
|
-
expect(tsconfig).toBeDefined();
|
|
100
|
-
expect(tsconfig!.skipIfExists).toBe(true);
|
|
105
|
+
expect(files.find((f) => f.path === 'package.json')).toBeUndefined();
|
|
106
|
+
expect(files.find((f) => f.path === 'tsconfig.json')).toBeUndefined();
|
|
107
|
+
expect(files.find((f) => f.path === 'src/index.worker.ts')).toBeUndefined();
|
|
101
108
|
});
|
|
102
109
|
|
|
103
110
|
it('uses overlay-resolved names for imports and accessors', () => {
|
|
104
111
|
const mfaService: Service = {
|
|
105
|
-
name: '
|
|
112
|
+
name: 'Billing',
|
|
106
113
|
operations: [
|
|
107
114
|
{
|
|
108
115
|
name: 'enrollFactor',
|
|
@@ -120,7 +127,13 @@ describe('generateClient', () => {
|
|
|
120
127
|
|
|
121
128
|
const mfaModel: Model = {
|
|
122
129
|
name: 'AuthenticationFactor',
|
|
123
|
-
fields: [
|
|
130
|
+
fields: [
|
|
131
|
+
{
|
|
132
|
+
name: 'id',
|
|
133
|
+
type: { kind: 'primitive', type: 'string' },
|
|
134
|
+
required: true,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
124
137
|
};
|
|
125
138
|
|
|
126
139
|
const overlaySpec: ApiSpec = {
|
|
@@ -130,6 +143,7 @@ describe('generateClient', () => {
|
|
|
130
143
|
services: [mfaService],
|
|
131
144
|
models: [mfaModel],
|
|
132
145
|
enums: [],
|
|
146
|
+
sdk: defaultSdkBehavior(),
|
|
133
147
|
};
|
|
134
148
|
|
|
135
149
|
const overlayCtx: EmitterContext = {
|
|
@@ -140,7 +154,12 @@ describe('generateClient', () => {
|
|
|
140
154
|
methodByOperation: new Map([
|
|
141
155
|
[
|
|
142
156
|
'POST /auth/factors/enroll',
|
|
143
|
-
{
|
|
157
|
+
{
|
|
158
|
+
className: 'Mfa',
|
|
159
|
+
methodName: 'enrollFactor',
|
|
160
|
+
params: [],
|
|
161
|
+
returnType: 'void',
|
|
162
|
+
},
|
|
144
163
|
],
|
|
145
164
|
]),
|
|
146
165
|
httpKeyByMethod: new Map(),
|
|
@@ -209,14 +228,28 @@ describe('generateClient', () => {
|
|
|
209
228
|
const eventModel: Model = {
|
|
210
229
|
name: 'Event',
|
|
211
230
|
fields: [
|
|
212
|
-
{
|
|
213
|
-
|
|
231
|
+
{
|
|
232
|
+
name: 'id',
|
|
233
|
+
type: { kind: 'primitive', type: 'string' },
|
|
234
|
+
required: true,
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: 'event',
|
|
238
|
+
type: { kind: 'primitive', type: 'string' },
|
|
239
|
+
required: true,
|
|
240
|
+
},
|
|
214
241
|
],
|
|
215
242
|
};
|
|
216
243
|
|
|
217
244
|
const otherModel: Model = {
|
|
218
245
|
name: 'EventCursor',
|
|
219
|
-
fields: [
|
|
246
|
+
fields: [
|
|
247
|
+
{
|
|
248
|
+
name: 'cursor',
|
|
249
|
+
type: { kind: 'primitive', type: 'string' },
|
|
250
|
+
required: true,
|
|
251
|
+
},
|
|
252
|
+
],
|
|
220
253
|
};
|
|
221
254
|
|
|
222
255
|
const eventSpec: ApiSpec = {
|
|
@@ -226,6 +259,7 @@ describe('generateClient', () => {
|
|
|
226
259
|
services: [eventService],
|
|
227
260
|
models: [eventModel, otherModel],
|
|
228
261
|
enums: [],
|
|
262
|
+
sdk: defaultSdkBehavior(),
|
|
229
263
|
};
|
|
230
264
|
|
|
231
265
|
const surface: ApiSurface = {
|
|
@@ -265,9 +299,10 @@ describe('generateClient', () => {
|
|
|
265
299
|
expect(content).not.toContain('export type { Event,');
|
|
266
300
|
expect(content).not.toContain('export type { Event }');
|
|
267
301
|
|
|
268
|
-
// EventCursor is
|
|
269
|
-
//
|
|
270
|
-
expect(content).toContain("export * from './common/interfaces'");
|
|
302
|
+
// EventCursor is unreachable (not referenced by any service), so it should
|
|
303
|
+
// NOT be exported — oagen only generates interface files for reachable models
|
|
304
|
+
expect(content).not.toContain("export * from './common/interfaces'");
|
|
305
|
+
expect(content).not.toContain('EventCursor');
|
|
271
306
|
|
|
272
307
|
// The resource class export should still be present
|
|
273
308
|
expect(content).toContain("export { Events } from './events/events'");
|
|
@@ -289,6 +324,7 @@ describe('generateClient', () => {
|
|
|
289
324
|
],
|
|
290
325
|
},
|
|
291
326
|
],
|
|
327
|
+
sdk: defaultSdkBehavior(),
|
|
292
328
|
};
|
|
293
329
|
|
|
294
330
|
const surface: ApiSurface = {
|
|
@@ -361,17 +397,21 @@ describe('generateClient', () => {
|
|
|
361
397
|
],
|
|
362
398
|
};
|
|
363
399
|
const enumService: Service = {
|
|
364
|
-
name: '
|
|
400
|
+
name: 'Payments',
|
|
365
401
|
operations: [
|
|
366
402
|
{
|
|
367
|
-
name: '
|
|
403
|
+
name: 'listPayments',
|
|
368
404
|
httpMethod: 'get',
|
|
369
|
-
path: '/
|
|
405
|
+
path: '/payments',
|
|
370
406
|
pathParams: [],
|
|
371
407
|
queryParams: [
|
|
372
408
|
{
|
|
373
409
|
name: 'type',
|
|
374
|
-
type: {
|
|
410
|
+
type: {
|
|
411
|
+
kind: 'enum',
|
|
412
|
+
name: 'ConnectionType',
|
|
413
|
+
values: ['ADFSSAML', 'GoogleOAuth'],
|
|
414
|
+
},
|
|
375
415
|
required: false,
|
|
376
416
|
},
|
|
377
417
|
],
|
|
@@ -383,17 +423,21 @@ describe('generateClient', () => {
|
|
|
383
423
|
],
|
|
384
424
|
};
|
|
385
425
|
const dirService: Service = {
|
|
386
|
-
name: '
|
|
426
|
+
name: 'Invoices',
|
|
387
427
|
operations: [
|
|
388
428
|
{
|
|
389
|
-
name: '
|
|
429
|
+
name: 'listInvoices',
|
|
390
430
|
httpMethod: 'get',
|
|
391
|
-
path: '/
|
|
431
|
+
path: '/invoices',
|
|
392
432
|
pathParams: [],
|
|
393
433
|
queryParams: [
|
|
394
434
|
{
|
|
395
435
|
name: 'state',
|
|
396
|
-
type: {
|
|
436
|
+
type: {
|
|
437
|
+
kind: 'enum',
|
|
438
|
+
name: 'DirectoryState',
|
|
439
|
+
values: ['active', 'inactive'],
|
|
440
|
+
},
|
|
397
441
|
required: false,
|
|
398
442
|
},
|
|
399
443
|
],
|
|
@@ -411,6 +455,7 @@ describe('generateClient', () => {
|
|
|
411
455
|
services: [service, enumService, dirService],
|
|
412
456
|
models: [model],
|
|
413
457
|
enums: [enumDef, aliasEnumDef],
|
|
458
|
+
sdk: defaultSdkBehavior(),
|
|
414
459
|
};
|
|
415
460
|
const enumCtx: EmitterContext = {
|
|
416
461
|
namespace: 'workos',
|
|
@@ -439,21 +484,21 @@ describe('generateClient', () => {
|
|
|
439
484
|
|
|
440
485
|
const content = barrel!.content;
|
|
441
486
|
// Both enums are now re-exported via per-service barrel wildcards
|
|
442
|
-
expect(content).toContain("export * from './
|
|
443
|
-
expect(content).toContain("export * from './
|
|
487
|
+
expect(content).toContain("export * from './payments/interfaces'");
|
|
488
|
+
expect(content).toContain("export * from './invoices/interfaces'");
|
|
444
489
|
// Individual enum exports should NOT appear (covered by wildcard)
|
|
445
490
|
expect(content).not.toContain('export { ConnectionType }');
|
|
446
|
-
expect(content).not.toContain('export type {
|
|
491
|
+
expect(content).not.toContain('export type { InvoiceState }');
|
|
447
492
|
});
|
|
448
493
|
|
|
449
494
|
it('skips services whose endpoints are fully covered by existing hand-written services', () => {
|
|
450
495
|
const connectionsService: Service = {
|
|
451
|
-
name: '
|
|
496
|
+
name: 'Payments',
|
|
452
497
|
operations: [
|
|
453
498
|
{
|
|
454
|
-
name: '
|
|
499
|
+
name: 'listPayments',
|
|
455
500
|
httpMethod: 'get',
|
|
456
|
-
path: '/
|
|
501
|
+
path: '/payments',
|
|
457
502
|
pathParams: [],
|
|
458
503
|
queryParams: [],
|
|
459
504
|
headerParams: [],
|
|
@@ -464,8 +509,14 @@ describe('generateClient', () => {
|
|
|
464
509
|
{
|
|
465
510
|
name: 'getConnection',
|
|
466
511
|
httpMethod: 'get',
|
|
467
|
-
path: '/
|
|
468
|
-
pathParams: [
|
|
512
|
+
path: '/payments/{id}',
|
|
513
|
+
pathParams: [
|
|
514
|
+
{
|
|
515
|
+
name: 'id',
|
|
516
|
+
type: { kind: 'primitive', type: 'string' },
|
|
517
|
+
required: true,
|
|
518
|
+
},
|
|
519
|
+
],
|
|
469
520
|
queryParams: [],
|
|
470
521
|
headerParams: [],
|
|
471
522
|
response: { kind: 'model', name: 'Connection' },
|
|
@@ -478,8 +529,16 @@ describe('generateClient', () => {
|
|
|
478
529
|
const connectionModel: Model = {
|
|
479
530
|
name: 'Connection',
|
|
480
531
|
fields: [
|
|
481
|
-
{
|
|
482
|
-
|
|
532
|
+
{
|
|
533
|
+
name: 'id',
|
|
534
|
+
type: { kind: 'primitive', type: 'string' },
|
|
535
|
+
required: true,
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
name: 'name',
|
|
539
|
+
type: { kind: 'primitive', type: 'string' },
|
|
540
|
+
required: true,
|
|
541
|
+
},
|
|
483
542
|
],
|
|
484
543
|
};
|
|
485
544
|
|
|
@@ -502,7 +561,13 @@ describe('generateClient', () => {
|
|
|
502
561
|
|
|
503
562
|
const radarModel: Model = {
|
|
504
563
|
name: 'RadarResult',
|
|
505
|
-
fields: [
|
|
564
|
+
fields: [
|
|
565
|
+
{
|
|
566
|
+
name: 'score',
|
|
567
|
+
type: { kind: 'primitive', type: 'number' },
|
|
568
|
+
required: true,
|
|
569
|
+
},
|
|
570
|
+
],
|
|
506
571
|
};
|
|
507
572
|
|
|
508
573
|
const coveredSpec: ApiSpec = {
|
|
@@ -512,6 +577,7 @@ describe('generateClient', () => {
|
|
|
512
577
|
services: [connectionsService, radarService],
|
|
513
578
|
models: [connectionModel, radarModel],
|
|
514
579
|
enums: [],
|
|
580
|
+
sdk: defaultSdkBehavior(),
|
|
515
581
|
};
|
|
516
582
|
|
|
517
583
|
const coveredCtx: EmitterContext = {
|
|
@@ -600,19 +666,19 @@ describe('generateClient', () => {
|
|
|
600
666
|
expect(barrelContent).not.toContain('export { Sso }');
|
|
601
667
|
expect(barrelContent).not.toContain('export { Connections }');
|
|
602
668
|
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
expect(barrelContent).toContain("export * from './sso/interfaces'");
|
|
669
|
+
// Covered services don't generate barrel exports — their types are
|
|
670
|
+
// already exported by the hand-written service's own barrel.
|
|
671
|
+
expect(barrelContent).not.toContain("export * from './sso/interfaces'");
|
|
606
672
|
});
|
|
607
673
|
|
|
608
674
|
it('does not skip services when only some operations are covered', () => {
|
|
609
675
|
const partialService: Service = {
|
|
610
|
-
name: '
|
|
676
|
+
name: 'Invoices',
|
|
611
677
|
operations: [
|
|
612
678
|
{
|
|
613
|
-
name: '
|
|
679
|
+
name: 'listInvoices',
|
|
614
680
|
httpMethod: 'get',
|
|
615
|
-
path: '/
|
|
681
|
+
path: '/invoices',
|
|
616
682
|
pathParams: [],
|
|
617
683
|
queryParams: [],
|
|
618
684
|
headerParams: [],
|
|
@@ -621,13 +687,13 @@ describe('generateClient', () => {
|
|
|
621
687
|
injectIdempotencyKey: false,
|
|
622
688
|
},
|
|
623
689
|
{
|
|
624
|
-
name: '
|
|
690
|
+
name: 'createInvoice',
|
|
625
691
|
httpMethod: 'post',
|
|
626
|
-
path: '/
|
|
692
|
+
path: '/invoices',
|
|
627
693
|
pathParams: [],
|
|
628
694
|
queryParams: [],
|
|
629
695
|
headerParams: [],
|
|
630
|
-
response: { kind: 'model', name: '
|
|
696
|
+
response: { kind: 'model', name: 'Invoice' },
|
|
631
697
|
errors: [],
|
|
632
698
|
injectIdempotencyKey: false,
|
|
633
699
|
},
|
|
@@ -635,8 +701,14 @@ describe('generateClient', () => {
|
|
|
635
701
|
};
|
|
636
702
|
|
|
637
703
|
const dirModel: Model = {
|
|
638
|
-
name: '
|
|
639
|
-
fields: [
|
|
704
|
+
name: 'Invoice',
|
|
705
|
+
fields: [
|
|
706
|
+
{
|
|
707
|
+
name: 'id',
|
|
708
|
+
type: { kind: 'primitive', type: 'string' },
|
|
709
|
+
required: true,
|
|
710
|
+
},
|
|
711
|
+
],
|
|
640
712
|
};
|
|
641
713
|
|
|
642
714
|
const partialSpec: ApiSpec = {
|
|
@@ -646,6 +718,7 @@ describe('generateClient', () => {
|
|
|
646
718
|
services: [partialService],
|
|
647
719
|
models: [dirModel],
|
|
648
720
|
enums: [],
|
|
721
|
+
sdk: defaultSdkBehavior(),
|
|
649
722
|
};
|
|
650
723
|
|
|
651
724
|
const partialCtx: EmitterContext = {
|
|
@@ -658,14 +731,14 @@ describe('generateClient', () => {
|
|
|
658
731
|
extractedAt: '2024-01-01',
|
|
659
732
|
interfaces: {},
|
|
660
733
|
classes: {
|
|
661
|
-
|
|
662
|
-
name: '
|
|
734
|
+
Billing: {
|
|
735
|
+
name: 'Billing',
|
|
663
736
|
methods: {
|
|
664
|
-
|
|
737
|
+
listInvoices: [
|
|
665
738
|
{
|
|
666
|
-
name: '
|
|
739
|
+
name: 'listInvoices',
|
|
667
740
|
params: [],
|
|
668
|
-
returnType: 'Promise<AutoPaginatable<
|
|
741
|
+
returnType: 'Promise<AutoPaginatable<Invoice>>',
|
|
669
742
|
async: true,
|
|
670
743
|
},
|
|
671
744
|
],
|
|
@@ -681,12 +754,12 @@ describe('generateClient', () => {
|
|
|
681
754
|
overlayLookup: {
|
|
682
755
|
methodByOperation: new Map([
|
|
683
756
|
[
|
|
684
|
-
'GET /
|
|
757
|
+
'GET /invoices',
|
|
685
758
|
{
|
|
686
|
-
className: '
|
|
687
|
-
methodName: '
|
|
759
|
+
className: 'Billing',
|
|
760
|
+
methodName: 'listInvoices',
|
|
688
761
|
params: [],
|
|
689
|
-
returnType: 'Promise<AutoPaginatable<
|
|
762
|
+
returnType: 'Promise<AutoPaginatable<Invoice>>',
|
|
690
763
|
},
|
|
691
764
|
],
|
|
692
765
|
]),
|
|
@@ -704,7 +777,7 @@ describe('generateClient', () => {
|
|
|
704
777
|
const content = workosFile.content;
|
|
705
778
|
|
|
706
779
|
// Service should still be generated because it has an uncovered operation
|
|
707
|
-
expect(content).toContain('
|
|
780
|
+
expect(content).toContain('Billing');
|
|
708
781
|
});
|
|
709
782
|
|
|
710
783
|
it('does not skip services when no overlay is provided', () => {
|
|
@@ -715,7 +788,7 @@ describe('generateClient', () => {
|
|
|
715
788
|
|
|
716
789
|
it('does not skip services when overlay exists but no apiSurface baseline', () => {
|
|
717
790
|
const mfaService: Service = {
|
|
718
|
-
name: '
|
|
791
|
+
name: 'Analytics',
|
|
719
792
|
operations: [
|
|
720
793
|
{
|
|
721
794
|
name: 'enrollFactor',
|
|
@@ -733,7 +806,13 @@ describe('generateClient', () => {
|
|
|
733
806
|
|
|
734
807
|
const mfaModel: Model = {
|
|
735
808
|
name: 'AuthenticationFactor',
|
|
736
|
-
fields: [
|
|
809
|
+
fields: [
|
|
810
|
+
{
|
|
811
|
+
name: 'id',
|
|
812
|
+
type: { kind: 'primitive', type: 'string' },
|
|
813
|
+
required: true,
|
|
814
|
+
},
|
|
815
|
+
],
|
|
737
816
|
};
|
|
738
817
|
|
|
739
818
|
const mfaSpec: ApiSpec = {
|
|
@@ -743,6 +822,7 @@ describe('generateClient', () => {
|
|
|
743
822
|
services: [mfaService],
|
|
744
823
|
models: [mfaModel],
|
|
745
824
|
enums: [],
|
|
825
|
+
sdk: defaultSdkBehavior(),
|
|
746
826
|
};
|
|
747
827
|
|
|
748
828
|
const namingOnlyCtx: EmitterContext = {
|
|
@@ -753,7 +833,12 @@ describe('generateClient', () => {
|
|
|
753
833
|
methodByOperation: new Map([
|
|
754
834
|
[
|
|
755
835
|
'POST /auth/factors/enroll',
|
|
756
|
-
{
|
|
836
|
+
{
|
|
837
|
+
className: 'Analytics',
|
|
838
|
+
methodName: 'enrollFactor',
|
|
839
|
+
params: [],
|
|
840
|
+
returnType: 'void',
|
|
841
|
+
},
|
|
757
842
|
],
|
|
758
843
|
]),
|
|
759
844
|
httpKeyByMethod: new Map(),
|
|
@@ -767,7 +852,7 @@ describe('generateClient', () => {
|
|
|
767
852
|
|
|
768
853
|
const files = generateClient(mfaSpec, namingOnlyCtx);
|
|
769
854
|
const workosFile = files.find((f) => f.path === 'src/workos.ts')!;
|
|
770
|
-
expect(workosFile.content).toContain('readonly
|
|
855
|
+
expect(workosFile.content).toContain('readonly analytics = new Analytics(this);');
|
|
771
856
|
});
|
|
772
857
|
});
|
|
773
858
|
|
|
@@ -779,16 +864,17 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
779
864
|
services: [],
|
|
780
865
|
models: [],
|
|
781
866
|
enums: [],
|
|
867
|
+
sdk: defaultSdkBehavior(),
|
|
782
868
|
};
|
|
783
869
|
|
|
784
870
|
it('returns false when no overlay is provided', () => {
|
|
785
871
|
const svc: Service = {
|
|
786
|
-
name: '
|
|
872
|
+
name: 'Payments',
|
|
787
873
|
operations: [
|
|
788
874
|
{
|
|
789
|
-
name: '
|
|
875
|
+
name: 'listPayments',
|
|
790
876
|
httpMethod: 'get',
|
|
791
|
-
path: '/
|
|
877
|
+
path: '/payments',
|
|
792
878
|
pathParams: [],
|
|
793
879
|
queryParams: [],
|
|
794
880
|
headerParams: [],
|
|
@@ -808,12 +894,12 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
808
894
|
|
|
809
895
|
it('returns false when overlay is empty', () => {
|
|
810
896
|
const svc: Service = {
|
|
811
|
-
name: '
|
|
897
|
+
name: 'Payments',
|
|
812
898
|
operations: [
|
|
813
899
|
{
|
|
814
|
-
name: '
|
|
900
|
+
name: 'listPayments',
|
|
815
901
|
httpMethod: 'get',
|
|
816
|
-
path: '/
|
|
902
|
+
path: '/payments',
|
|
817
903
|
pathParams: [],
|
|
818
904
|
queryParams: [],
|
|
819
905
|
headerParams: [],
|
|
@@ -859,7 +945,13 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
859
945
|
name: 'getConnection',
|
|
860
946
|
httpMethod: 'get',
|
|
861
947
|
path: '/connections/{id}',
|
|
862
|
-
pathParams: [
|
|
948
|
+
pathParams: [
|
|
949
|
+
{
|
|
950
|
+
name: 'id',
|
|
951
|
+
type: { kind: 'primitive', type: 'string' },
|
|
952
|
+
required: true,
|
|
953
|
+
},
|
|
954
|
+
],
|
|
863
955
|
queryParams: [],
|
|
864
956
|
headerParams: [],
|
|
865
957
|
response: { kind: 'model', name: 'Connection' },
|
|
@@ -923,12 +1015,12 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
923
1015
|
|
|
924
1016
|
it('returns false when only some operations are covered', () => {
|
|
925
1017
|
const svc: Service = {
|
|
926
|
-
name: '
|
|
1018
|
+
name: 'Invoices',
|
|
927
1019
|
operations: [
|
|
928
1020
|
{
|
|
929
|
-
name: '
|
|
1021
|
+
name: 'listInvoices',
|
|
930
1022
|
httpMethod: 'get',
|
|
931
|
-
path: '/
|
|
1023
|
+
path: '/invoices',
|
|
932
1024
|
pathParams: [],
|
|
933
1025
|
queryParams: [],
|
|
934
1026
|
headerParams: [],
|
|
@@ -937,13 +1029,13 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
937
1029
|
injectIdempotencyKey: false,
|
|
938
1030
|
},
|
|
939
1031
|
{
|
|
940
|
-
name: '
|
|
1032
|
+
name: 'createInvoice',
|
|
941
1033
|
httpMethod: 'post',
|
|
942
|
-
path: '/
|
|
1034
|
+
path: '/invoices',
|
|
943
1035
|
pathParams: [],
|
|
944
1036
|
queryParams: [],
|
|
945
1037
|
headerParams: [],
|
|
946
|
-
response: { kind: 'model', name: '
|
|
1038
|
+
response: { kind: 'model', name: 'Invoice' },
|
|
947
1039
|
errors: [],
|
|
948
1040
|
injectIdempotencyKey: false,
|
|
949
1041
|
},
|
|
@@ -959,8 +1051,8 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
959
1051
|
extractedAt: '2024-01-01',
|
|
960
1052
|
interfaces: {},
|
|
961
1053
|
classes: {
|
|
962
|
-
|
|
963
|
-
name: '
|
|
1054
|
+
Billing: {
|
|
1055
|
+
name: 'Billing',
|
|
964
1056
|
methods: {},
|
|
965
1057
|
properties: {},
|
|
966
1058
|
constructorParams: [],
|
|
@@ -973,10 +1065,10 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
973
1065
|
overlayLookup: {
|
|
974
1066
|
methodByOperation: new Map([
|
|
975
1067
|
[
|
|
976
|
-
'GET /
|
|
1068
|
+
'GET /invoices',
|
|
977
1069
|
{
|
|
978
|
-
className: '
|
|
979
|
-
methodName: '
|
|
1070
|
+
className: 'Billing',
|
|
1071
|
+
methodName: 'listInvoices',
|
|
980
1072
|
params: [],
|
|
981
1073
|
returnType: 'Promise<AutoPaginatable<Directory>>',
|
|
982
1074
|
},
|
|
@@ -1008,7 +1100,12 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
1008
1100
|
extractedAt: '2024-01-01',
|
|
1009
1101
|
interfaces: {},
|
|
1010
1102
|
classes: {
|
|
1011
|
-
Other: {
|
|
1103
|
+
Other: {
|
|
1104
|
+
name: 'Other',
|
|
1105
|
+
methods: {},
|
|
1106
|
+
properties: {},
|
|
1107
|
+
constructorParams: [],
|
|
1108
|
+
},
|
|
1012
1109
|
},
|
|
1013
1110
|
enums: {},
|
|
1014
1111
|
typeAliases: {},
|
|
@@ -1016,7 +1113,15 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
1016
1113
|
},
|
|
1017
1114
|
overlayLookup: {
|
|
1018
1115
|
methodByOperation: new Map([
|
|
1019
|
-
[
|
|
1116
|
+
[
|
|
1117
|
+
'GET /something',
|
|
1118
|
+
{
|
|
1119
|
+
className: 'Other',
|
|
1120
|
+
methodName: 'doSomething',
|
|
1121
|
+
params: [],
|
|
1122
|
+
returnType: 'void',
|
|
1123
|
+
},
|
|
1124
|
+
],
|
|
1020
1125
|
]),
|
|
1021
1126
|
httpKeyByMethod: new Map(),
|
|
1022
1127
|
interfaceByName: new Map(),
|
|
@@ -1031,12 +1136,12 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
1031
1136
|
|
|
1032
1137
|
it('returns false when overlay covers operations but target class is not in baseline', () => {
|
|
1033
1138
|
const svc: Service = {
|
|
1034
|
-
name: '
|
|
1139
|
+
name: 'Payments',
|
|
1035
1140
|
operations: [
|
|
1036
1141
|
{
|
|
1037
|
-
name: '
|
|
1142
|
+
name: 'listPayments',
|
|
1038
1143
|
httpMethod: 'get',
|
|
1039
|
-
path: '/
|
|
1144
|
+
path: '/payments',
|
|
1040
1145
|
pathParams: [],
|
|
1041
1146
|
queryParams: [],
|
|
1042
1147
|
headerParams: [],
|
|
@@ -1063,10 +1168,10 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
1063
1168
|
overlayLookup: {
|
|
1064
1169
|
methodByOperation: new Map([
|
|
1065
1170
|
[
|
|
1066
|
-
'GET /
|
|
1171
|
+
'GET /payments',
|
|
1067
1172
|
{
|
|
1068
1173
|
className: 'Sso',
|
|
1069
|
-
methodName: '
|
|
1174
|
+
methodName: 'listPayments',
|
|
1070
1175
|
params: [],
|
|
1071
1176
|
returnType: 'Promise<AutoPaginatable<Connection>>',
|
|
1072
1177
|
},
|
|
@@ -1085,12 +1190,12 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
1085
1190
|
|
|
1086
1191
|
it('returns false when no apiSurface is provided', () => {
|
|
1087
1192
|
const svc: Service = {
|
|
1088
|
-
name: '
|
|
1193
|
+
name: 'Payments',
|
|
1089
1194
|
operations: [
|
|
1090
1195
|
{
|
|
1091
|
-
name: '
|
|
1196
|
+
name: 'listPayments',
|
|
1092
1197
|
httpMethod: 'get',
|
|
1093
|
-
path: '/
|
|
1198
|
+
path: '/payments',
|
|
1094
1199
|
pathParams: [],
|
|
1095
1200
|
queryParams: [],
|
|
1096
1201
|
headerParams: [],
|
|
@@ -1107,10 +1212,10 @@ describe('isServiceCoveredByExisting', () => {
|
|
|
1107
1212
|
overlayLookup: {
|
|
1108
1213
|
methodByOperation: new Map([
|
|
1109
1214
|
[
|
|
1110
|
-
'GET /
|
|
1215
|
+
'GET /payments',
|
|
1111
1216
|
{
|
|
1112
1217
|
className: 'Sso',
|
|
1113
|
-
methodName: '
|
|
1218
|
+
methodName: 'listPayments',
|
|
1114
1219
|
params: [],
|
|
1115
1220
|
returnType: 'Promise<AutoPaginatable<Connection>>',
|
|
1116
1221
|
},
|