Skip to content

Commit 11c6ab4

Browse files
Merge branch 'main' of github.com:seamapi/blueprint into require-route-path
2 parents b82dda8 + 3011d95 commit 11c6ab4

File tree

7 files changed

+158
-5
lines changed

7 files changed

+158
-5
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@seamapi/blueprint",
3-
"version": "0.34.0",
3+
"version": "0.35.0",
44
"description": "Build tools for the Seam API using this blueprint.",
55
"type": "module",
66
"main": "index.js",

src/lib/blueprint.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ interface ResourceResponse extends BaseResponse {
193193
responseType: 'resource'
194194
responseKey: string
195195
resourceType: string
196+
actionAttemptType?: string
196197
}
197198

198199
interface ResourceListResponse extends BaseResponse {
@@ -276,6 +277,7 @@ export type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
276277

277278
interface Context extends Required<BlueprintOptions> {
278279
codeSampleDefinitions: CodeSampleDefinition[]
280+
// actionAttempts: ActionAttempt[]
279281
}
280282

281283
export const TypesModuleSchema = z.object({
@@ -304,17 +306,22 @@ export const createBlueprint = async (
304306
const context = {
305307
codeSampleDefinitions,
306308
formatCode,
309+
// actionAttempts,
307310
}
308311

309312
const routes = await createRoutes(openapi.paths, context)
310313
const resources = createResources(openapi.components.schemas, routes)
314+
const actionAttempts = createActionAttempts(
315+
openapi.components.schemas,
316+
routes,
317+
)
311318

312319
return {
313320
title: openapi.info.title,
314321
routes,
315322
resources,
316323
events: createEvents(openapi.components.schemas, resources, routes),
317-
actionAttempts: createActionAttempts(openapi.components.schemas, routes),
324+
actionAttempts,
318325
}
319326
}
320327

@@ -524,7 +531,7 @@ const createEndpointFromOperation = async (
524531
const draftMessage = parsedOperation['x-draft']
525532

526533
const request = createRequest(methods, operation, path)
527-
const response = createResponse(operation, path)
534+
const response = createResponse(operation, path, context)
528535

529536
const operationAuthMethods = parsedOperation.security.map(
530537
(securitySchema) => {
@@ -868,6 +875,7 @@ const validateRoutePath = (
868875
const createResponse = (
869876
operation: OpenapiOperation,
870877
path: string,
878+
context: Context,
871879
): Response => {
872880
if (!('responses' in operation) || operation.responses == null) {
873881
throw new Error(
@@ -945,6 +953,12 @@ const createResponse = (
945953
)
946954
}
947955

956+
const actionAttemptType = validateActionAttemptType(
957+
parsedOperation['x-action-attempt-type'],
958+
responseKey,
959+
path,
960+
context,
961+
)
948962
const refKey = responseKey
949963

950964
if (refKey != null && properties[refKey] != null) {
@@ -956,6 +970,7 @@ const createResponse = (
956970
responseKey: refKey,
957971
resourceType: refString?.split('/').at(-1) ?? 'unknown',
958972
description,
973+
...(actionAttemptType != null && { actionAttemptType }),
959974
}
960975
}
961976
}
@@ -966,6 +981,37 @@ const createResponse = (
966981
}
967982
}
968983

984+
const validateActionAttemptType = (
985+
actionAttemptType: string | undefined,
986+
responseKey: string,
987+
path: string,
988+
context: Context,
989+
): string | undefined => {
990+
const excludedPaths = ['/action_attempts']
991+
const isPathExcluded = excludedPaths.some((p) => path.startsWith(p))
992+
993+
if (
994+
actionAttemptType == null &&
995+
responseKey === 'action_attempt' &&
996+
!isPathExcluded
997+
) {
998+
throw new Error(`Missing action_attempt_type for path ${path}`)
999+
}
1000+
1001+
// if (
1002+
// actionAttemptType != null &&
1003+
// !context.actionAttempts.some(
1004+
// (attempt) => attempt.actionAttemptType === actionAttemptType,
1005+
// )
1006+
// ) {
1007+
// throw new Error(
1008+
// `Invalid action_attempt_type '${actionAttemptType}' for path ${path}`,
1009+
// )
1010+
// }
1011+
1012+
return actionAttemptType
1013+
}
1014+
9691015
export const createProperties = (
9701016
properties: Record<string, OpenapiSchema>,
9711017
parentPaths: string[],

src/lib/openapi/schemas.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export const OpenapiOperationSchema = z.object({
8181
'x-undocumented': z.string().default(''),
8282
'x-deprecated': z.string().default(''),
8383
'x-draft': z.string().default(''),
84+
'x-action-attempt-type': z.string().optional(),
8485
})
8586

8687
export const EnumValueSchema = z.object({

test/fixtures/types/openapi.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,38 @@ export default {
320320
'x-title': 'Get a foo',
321321
},
322322
},
323+
'/foos/create': {
324+
post: {
325+
operationId: 'foosCreatePost',
326+
responses: {
327+
200: {
328+
content: {
329+
'application/json': {
330+
schema: {
331+
properties: {
332+
ok: { type: 'boolean' },
333+
action_attempt: {
334+
$ref: '#/components/schemas/action_attempt',
335+
},
336+
},
337+
required: ['action_attempt', 'ok'],
338+
type: 'object',
339+
},
340+
},
341+
},
342+
description: 'Create a foo.',
343+
},
344+
400: { description: 'Bad Request' },
345+
401: { description: 'Unauthorized' },
346+
},
347+
security: [],
348+
summary: '/foos/create',
349+
tags: ['/foos'],
350+
'x-response-key': 'action_attempt',
351+
'x-action-attempt-type': 'CREATE_FOO',
352+
'x-title': 'Create a foo',
353+
},
354+
},
323355
'/foos/list': {
324356
get: {
325357
operationId: 'foosListGet',

test/snapshots/blueprint.test.ts.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,36 @@ Generated by [AVA](https://avajs.dev).
601601
undocumentedMessage: '',
602602
workspaceScope: 'required',
603603
},
604+
{
605+
authMethods: [],
606+
codeSamples: [],
607+
deprecationMessage: '',
608+
description: '',
609+
draftMessage: '',
610+
isDeprecated: false,
611+
isDraft: false,
612+
isUndocumented: false,
613+
name: 'create',
614+
path: '/foos/create',
615+
request: {
616+
methods: [
617+
'POST',
618+
],
619+
parameters: [],
620+
preferredMethod: 'POST',
621+
semanticMethod: 'POST',
622+
},
623+
response: {
624+
actionAttemptType: 'CREATE_FOO',
625+
description: 'Create a foo.',
626+
resourceType: 'action_attempt',
627+
responseKey: 'action_attempt',
628+
responseType: 'resource',
629+
},
630+
title: 'Create a foo',
631+
undocumentedMessage: '',
632+
workspaceScope: 'none',
633+
},
604634
{
605635
authMethods: [
606636
'api_key',
@@ -1769,6 +1799,36 @@ Generated by [AVA](https://avajs.dev).
17691799
undocumentedMessage: '',
17701800
workspaceScope: 'required',
17711801
},
1802+
{
1803+
authMethods: [],
1804+
codeSamples: [],
1805+
deprecationMessage: '',
1806+
description: '',
1807+
draftMessage: '',
1808+
isDeprecated: false,
1809+
isDraft: false,
1810+
isUndocumented: false,
1811+
name: 'create',
1812+
path: '/foos/create',
1813+
request: {
1814+
methods: [
1815+
'POST',
1816+
],
1817+
parameters: [],
1818+
preferredMethod: 'POST',
1819+
semanticMethod: 'POST',
1820+
},
1821+
response: {
1822+
actionAttemptType: 'CREATE_FOO',
1823+
description: 'Create a foo.',
1824+
resourceType: 'action_attempt',
1825+
responseKey: 'action_attempt',
1826+
responseType: 'resource',
1827+
},
1828+
title: 'Create a foo',
1829+
undocumentedMessage: '',
1830+
workspaceScope: 'none',
1831+
},
17721832
{
17731833
authMethods: [
17741834
'api_key',

test/snapshots/seam-blueprint.test.ts.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18790,6 +18790,7 @@ Generated by [AVA](https://avajs.dev).
1879018790
semanticMethod: 'POST',
1879118791
},
1879218792
response: {
18793+
actionAttemptType: 'CREATE_ACCESS_CODE',
1879318794
description: 'OK',
1879418795
resourceType: 'access_code',
1879518796
responseKey: 'access_code',
@@ -21992,6 +21993,7 @@ Generated by [AVA](https://avajs.dev).
2199221993
semanticMethod: 'POST',
2199321994
},
2199421995
response: {
21996+
actionAttemptType: 'ENCODE_CREDENTIAL',
2199521997
description: 'OK',
2199621998
resourceType: 'action_attempt',
2199721999
responseKey: 'action_attempt',
@@ -22070,6 +22072,7 @@ Generated by [AVA](https://avajs.dev).
2207022072
semanticMethod: 'POST',
2207122073
},
2207222074
response: {
22075+
actionAttemptType: 'SCAN_CREDENTIAL',
2207322076
description: 'OK',
2207422077
resourceType: 'action_attempt',
2207522078
responseKey: 'action_attempt',
@@ -28373,6 +28376,7 @@ Generated by [AVA](https://avajs.dev).
2837328376
semanticMethod: 'POST',
2837428377
},
2837528378
response: {
28379+
actionAttemptType: 'LOCK_DOOR',
2837628380
description: 'OK',
2837728381
resourceType: 'action_attempt',
2837828382
responseKey: 'action_attempt',
@@ -28433,6 +28437,7 @@ Generated by [AVA](https://avajs.dev).
2843328437
semanticMethod: 'POST',
2843428438
},
2843528439
response: {
28440+
actionAttemptType: 'UNLOCK_DOOR',
2843628441
description: 'OK',
2843728442
resourceType: 'action_attempt',
2843828443
responseKey: 'action_attempt',
@@ -29220,6 +29225,7 @@ Generated by [AVA](https://avajs.dev).
2922029225
semanticMethod: 'POST',
2922129226
},
2922229227
response: {
29228+
actionAttemptType: 'CREATE_NOISE_THRESHOLD',
2922329229
description: 'OK',
2922429230
resourceType: 'noise_threshold',
2922529231
responseKey: 'noise_threshold',
@@ -30025,6 +30031,7 @@ Generated by [AVA](https://avajs.dev).
3002530031
semanticMethod: 'POST',
3002630032
},
3002730033
response: {
30034+
actionAttemptType: 'ACTIVATE_CLIMATE_PRESET',
3002830035
description: 'OK',
3002930036
resourceType: 'action_attempt',
3003030037
responseKey: 'action_attempt',
@@ -30111,6 +30118,7 @@ Generated by [AVA](https://avajs.dev).
3011130118
semanticMethod: 'POST',
3011230119
},
3011330120
response: {
30121+
actionAttemptType: 'SET_HVAC_MODE',
3011430122
description: 'OK',
3011530123
resourceType: 'action_attempt',
3011630124
responseKey: 'action_attempt',
@@ -30549,6 +30557,7 @@ Generated by [AVA](https://avajs.dev).
3054930557
semanticMethod: 'POST',
3055030558
},
3055130559
response: {
30560+
actionAttemptType: 'SET_HVAC_MODE',
3055230561
description: 'OK',
3055330562
resourceType: 'action_attempt',
3055430563
responseKey: 'action_attempt',
@@ -30661,6 +30670,7 @@ Generated by [AVA](https://avajs.dev).
3066130670
semanticMethod: 'POST',
3066230671
},
3066330672
response: {
30673+
actionAttemptType: 'SET_HVAC_MODE',
3066430674
description: 'OK',
3066530675
resourceType: 'action_attempt',
3066630676
responseKey: 'action_attempt',
@@ -31273,6 +31283,7 @@ Generated by [AVA](https://avajs.dev).
3127331283
semanticMethod: 'POST',
3127431284
},
3127531285
response: {
31286+
actionAttemptType: 'SET_HVAC_MODE',
3127631287
description: 'OK',
3127731288
resourceType: 'action_attempt',
3127831289
responseKey: 'action_attempt',
@@ -31480,6 +31491,7 @@ Generated by [AVA](https://avajs.dev).
3148031491
semanticMethod: 'POST',
3148131492
},
3148231493
response: {
31494+
actionAttemptType: 'SET_FAN_MODE',
3148331495
description: 'OK',
3148431496
resourceType: 'action_attempt',
3148531497
responseKey: 'action_attempt',
@@ -31513,6 +31525,7 @@ Generated by [AVA](https://avajs.dev).
3151331525
semanticMethod: 'POST',
3151431526
},
3151531527
response: {
31528+
actionAttemptType: 'SET_HVAC_MODE',
3151631529
description: 'OK',
3151731530
resourceType: 'action_attempt',
3151831531
responseKey: 'action_attempt',
@@ -33809,6 +33822,7 @@ Generated by [AVA](https://avajs.dev).
3380933822
semanticMethod: 'POST',
3381033823
},
3381133824
response: {
33825+
actionAttemptType: 'RESET_SANDBOX_WORKSPACE',
3381233826
description: 'OK',
3381333827
resourceType: 'action_attempt',
3381433828
responseKey: 'action_attempt',

0 commit comments

Comments
 (0)