@carthooks/arcubase-cli 0.1.25 → 0.1.26
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/bundle/arcubase-admin.mjs +505 -164
- package/bundle/arcubase.mjs +505 -164
- package/dist/generated/zod_registry.generated.d.ts.map +1 -1
- package/dist/generated/zod_registry.generated.js +3 -3
- package/dist/runtime/dev_sdk_gen.d.ts +7 -2
- package/dist/runtime/dev_sdk_gen.d.ts.map +1 -1
- package/dist/runtime/dev_sdk_gen.js +593 -8
- package/dist/runtime/execute.d.ts.map +1 -1
- package/dist/runtime/execute.js +99 -7
- package/package.json +1 -2
- package/sdk-dist/docs/runtime-reference/dev-sdk-gen.md +14 -10
- package/sdk-dist/generated/zod_registry.generated.ts +3 -3
- package/sdk-dist/types/common.ts +1 -0
- package/sdk-dist/types/ingress.ts +15 -0
- package/sdk-dist/types/user-action.ts +1 -0
- package/src/generated/zod_registry.generated.ts +3 -3
- package/src/runtime/dev_sdk_gen.ts +660 -14
- package/src/runtime/execute.ts +107 -6
- package/src/tests/dev_sdk_gen.test.ts +125 -36
- package/src/tests/help.test.ts +2 -1
- package/src/tests/zod_registry.test.ts +1 -0
package/src/runtime/execute.ts
CHANGED
|
@@ -295,10 +295,10 @@ function renderDevSDKGenHelp(): string {
|
|
|
295
295
|
' - arcubase-admin dev sdk-gen --app-id <app_id> --out src/arcubase',
|
|
296
296
|
'',
|
|
297
297
|
'requirements:',
|
|
298
|
+
' - every generated ingress must have a configured ingress.key; sdk-gen fails fast when keys are missing',
|
|
298
299
|
' - every generated field must have a configured field.key; sdk-gen fails fast when keys are missing',
|
|
299
|
-
' -
|
|
300
|
-
' -
|
|
301
|
-
' - generated code accepts createArcubaseSdk({ baseURL, accessToken, refreshToken })',
|
|
300
|
+
' - ingress.key and field.key values must be stable unique TypeScript identifiers',
|
|
301
|
+
' - generated code accepts createArcubaseClient({ baseURL, accessToken, refreshToken }).ingress("<IngressKey>")',
|
|
302
302
|
].join('\n')
|
|
303
303
|
}
|
|
304
304
|
|
|
@@ -2006,6 +2006,8 @@ type SDKGenEntityRef = {
|
|
|
2006
2006
|
id: string
|
|
2007
2007
|
}
|
|
2008
2008
|
|
|
2009
|
+
type SDKGenIngressRef = Record<string, any>
|
|
2010
|
+
|
|
2009
2011
|
function extractSDKGenAppPayload(payload: unknown): Record<string, any> {
|
|
2010
2012
|
const appPayload = unwrapResponseData(payload)
|
|
2011
2013
|
if (!isRecord(appPayload)) {
|
|
@@ -2085,6 +2087,96 @@ function assertSDKGenFieldKeysPresent(entity: Record<string, any>) {
|
|
|
2085
2087
|
})
|
|
2086
2088
|
}
|
|
2087
2089
|
|
|
2090
|
+
function extractSDKGenIngressRefs(payload: unknown): SDKGenIngressRef[] {
|
|
2091
|
+
const data = unwrapResponseData(payload)
|
|
2092
|
+
const source = Array.isArray(data)
|
|
2093
|
+
? data
|
|
2094
|
+
: isRecord(data) && Array.isArray(data.list)
|
|
2095
|
+
? data.list
|
|
2096
|
+
: []
|
|
2097
|
+
return source.filter((item): item is SDKGenIngressRef => isRecord(item))
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
function ingressKeyOf(ingress: Record<string, any>): string {
|
|
2101
|
+
return typeof ingress.key === 'string' ? ingress.key.trim() : ''
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
function ingressHashIDOf(ingress: Record<string, any>): string {
|
|
2105
|
+
if (typeof ingress.hash_id === 'string' && ingress.hash_id.trim()) {
|
|
2106
|
+
return ingress.hash_id.trim()
|
|
2107
|
+
}
|
|
2108
|
+
if (typeof ingress.hashId === 'string' && ingress.hashId.trim()) {
|
|
2109
|
+
return ingress.hashId.trim()
|
|
2110
|
+
}
|
|
2111
|
+
return ''
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
function assertSDKGenIngressesReady(ingresses: SDKGenIngressRef[]) {
|
|
2115
|
+
if (ingresses.length === 0) {
|
|
2116
|
+
throw new CLIError('SDK_GEN_NO_INGRESSES', 'sdk-gen could not find ingress definitions for this app', 2, {
|
|
2117
|
+
operation: 'dev sdk-gen',
|
|
2118
|
+
suggestions: ['create at least one access rule with a stable ingress.key before running sdk-gen'],
|
|
2119
|
+
})
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
const seen = new Set<string>()
|
|
2123
|
+
const missingKey: SDKGenIngressRef[] = []
|
|
2124
|
+
const missingHash: SDKGenIngressRef[] = []
|
|
2125
|
+
const invalidKey: string[] = []
|
|
2126
|
+
const duplicateKey: string[] = []
|
|
2127
|
+
|
|
2128
|
+
for (const ingress of ingresses) {
|
|
2129
|
+
const key = ingressKeyOf(ingress)
|
|
2130
|
+
if (!key) {
|
|
2131
|
+
missingKey.push(ingress)
|
|
2132
|
+
continue
|
|
2133
|
+
}
|
|
2134
|
+
if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(key)) {
|
|
2135
|
+
invalidKey.push(key)
|
|
2136
|
+
}
|
|
2137
|
+
if (seen.has(key)) {
|
|
2138
|
+
duplicateKey.push(key)
|
|
2139
|
+
}
|
|
2140
|
+
seen.add(key)
|
|
2141
|
+
if (!ingressHashIDOf(ingress)) {
|
|
2142
|
+
missingHash.push(ingress)
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
if (missingKey.length > 0) {
|
|
2147
|
+
const preview = missingKey.slice(0, 8).map((ingress) => String(ingress.name ?? ingress.id ?? 'unnamed ingress'))
|
|
2148
|
+
const suffix = missingKey.length > preview.length ? `, and ${missingKey.length - preview.length} more` : ''
|
|
2149
|
+
throw new CLIError('SDK_GEN_INGRESS_KEY_REQUIRED', `missing ingress.key values: ${preview.join(', ')}${suffix}`, 2, {
|
|
2150
|
+
operation: 'dev sdk-gen',
|
|
2151
|
+
issues: missingKey.map((ingress) => ({
|
|
2152
|
+
path: `ingress.${String(ingress.id ?? 'unknown')}.key`,
|
|
2153
|
+
message: `ingress.key is required for ${String(ingress.name ?? ingress.id ?? 'unnamed ingress')}`,
|
|
2154
|
+
})),
|
|
2155
|
+
suggestions: [
|
|
2156
|
+
'set stable ingress.key values in Arcubase admin before running sdk-gen',
|
|
2157
|
+
'rerun arcubase-admin dev sdk-gen after ingress keys are complete',
|
|
2158
|
+
],
|
|
2159
|
+
})
|
|
2160
|
+
}
|
|
2161
|
+
if (invalidKey.length > 0) {
|
|
2162
|
+
throw new CLIError('SDK_GEN_INVALID_INGRESS_KEY', `invalid ingress.key values: ${invalidKey.join(', ')}`, 2, {
|
|
2163
|
+
operation: 'dev sdk-gen',
|
|
2164
|
+
suggestions: ['use TypeScript identifier keys such as publicEntry or customerPortal'],
|
|
2165
|
+
})
|
|
2166
|
+
}
|
|
2167
|
+
if (duplicateKey.length > 0) {
|
|
2168
|
+
throw new CLIError('SDK_GEN_DUPLICATE_INGRESS_KEY', `duplicate ingress.key values: ${duplicateKey.join(', ')}`, 2, {
|
|
2169
|
+
operation: 'dev sdk-gen',
|
|
2170
|
+
})
|
|
2171
|
+
}
|
|
2172
|
+
if (missingHash.length > 0) {
|
|
2173
|
+
throw new CLIError('SDK_GEN_INGRESS_HASH_ID_REQUIRED', 'sdk-gen expected hash_id for every ingress definition', 2, {
|
|
2174
|
+
operation: 'dev sdk-gen',
|
|
2175
|
+
suggestions: ['upgrade Arcubase server so admin access-rule list returns hash_id'],
|
|
2176
|
+
})
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2088
2180
|
async function executeDevSDKGen(
|
|
2089
2181
|
runtimeEnv: RuntimeEnv,
|
|
2090
2182
|
flags: Record<string, string | boolean>,
|
|
@@ -2116,7 +2208,7 @@ async function executeDevSDKGen(
|
|
|
2116
2208
|
if (entityRefs.length === 0) {
|
|
2117
2209
|
throw new CLIError('SDK_GEN_NO_ENTITIES', 'sdk-gen could not find entities in app detail response', 2)
|
|
2118
2210
|
}
|
|
2119
|
-
const
|
|
2211
|
+
const ingresses: SDKGenIngressRef[] = []
|
|
2120
2212
|
for (const entityRef of entityRefs) {
|
|
2121
2213
|
const entityEndpoint = `/api/apps/${encodeURIComponent(appId)}/entity/${encodeURIComponent(entityRef.id)}`
|
|
2122
2214
|
const entityDetail = await requestJSON(runtimeEnv, 'GET', entityEndpoint, undefined, fetchImpl)
|
|
@@ -2125,12 +2217,21 @@ async function executeDevSDKGen(
|
|
|
2125
2217
|
throw new CLIError('SDK_GEN_INVALID_SCHEMA', 'sdk-gen expected entity detail response data', 2)
|
|
2126
2218
|
}
|
|
2127
2219
|
assertSDKGenFieldKeysPresent(entityPayload)
|
|
2128
|
-
|
|
2220
|
+
const ingressEndpoint = `/api/apps/${encodeURIComponent(appId)}/entity/${encodeURIComponent(entityRef.id)}/ingress`
|
|
2221
|
+
const ingressList = await requestJSON(runtimeEnv, 'GET', ingressEndpoint, undefined, fetchImpl)
|
|
2222
|
+
const entityIngresses = extractSDKGenIngressRefs(ingressList.data).map((ingress) => ({
|
|
2223
|
+
...ingress,
|
|
2224
|
+
hash_id: ingressHashIDOf(ingress),
|
|
2225
|
+
key: ingressKeyOf(ingress),
|
|
2226
|
+
entity: entityPayload,
|
|
2227
|
+
}))
|
|
2228
|
+
ingresses.push(...entityIngresses)
|
|
2129
2229
|
}
|
|
2230
|
+
assertSDKGenIngressesReady(ingresses)
|
|
2130
2231
|
const generated = generateArcubaseProjectSDK({
|
|
2131
2232
|
id: resolveSDKGenAppId(appId, appPayload),
|
|
2132
2233
|
name: typeof appPayload.name === 'string' ? appPayload.name : undefined,
|
|
2133
|
-
|
|
2234
|
+
ingresses,
|
|
2134
2235
|
})
|
|
2135
2236
|
const absoluteOutDir = path.resolve(process.cwd(), outDir)
|
|
2136
2237
|
|
|
@@ -21,7 +21,7 @@ const env = {
|
|
|
21
21
|
function appDetail() {
|
|
22
22
|
return {
|
|
23
23
|
id: 3882856425,
|
|
24
|
-
name: '
|
|
24
|
+
name: 'Demo App',
|
|
25
25
|
entities: {},
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -30,7 +30,7 @@ function entityList() {
|
|
|
30
30
|
return [
|
|
31
31
|
{
|
|
32
32
|
id: 3883547182,
|
|
33
|
-
name: '
|
|
33
|
+
name: 'Records',
|
|
34
34
|
},
|
|
35
35
|
]
|
|
36
36
|
}
|
|
@@ -42,7 +42,7 @@ function appDetailWithEntityList() {
|
|
|
42
42
|
entities: [
|
|
43
43
|
{
|
|
44
44
|
id: 3883547182,
|
|
45
|
-
name: '
|
|
45
|
+
name: 'Records',
|
|
46
46
|
},
|
|
47
47
|
],
|
|
48
48
|
}
|
|
@@ -52,12 +52,11 @@ function entityDetail() {
|
|
|
52
52
|
return {
|
|
53
53
|
id: 3883547182,
|
|
54
54
|
app_id: 3882856425,
|
|
55
|
-
name: '
|
|
56
|
-
key: 'story',
|
|
55
|
+
name: 'Records',
|
|
57
56
|
fields: [
|
|
58
|
-
{ id: 1006, label: '
|
|
59
|
-
{ id: 1013, label: '
|
|
60
|
-
{ id: 1011, label: '
|
|
57
|
+
{ id: 1006, label: 'Title', key: 'title', type: 'text', required: true, options: {} },
|
|
58
|
+
{ id: 1013, label: 'Status', key: 'status', type: 'select', required: false, options: { options: { items: [{ key: 1, value: 'Open' }] } } },
|
|
59
|
+
{ id: 1011, label: 'Notes', key: 'notes', type: 'textarea', required: false, options: {} },
|
|
61
60
|
],
|
|
62
61
|
}
|
|
63
62
|
}
|
|
@@ -70,76 +69,125 @@ function entityDetailWithoutFieldKeys() {
|
|
|
70
69
|
|
|
71
70
|
function sdkSchemaPayload() {
|
|
72
71
|
return {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
id: 3882856425,
|
|
73
|
+
name: 'Demo App',
|
|
74
|
+
ingresses: [ingressDefinition()],
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function ingressDefinition(actions = ['view', 'add', 'edit', 'delete', 'bulk_update', 'export', 'batch_print', 'tag_manage', 'archive']) {
|
|
79
|
+
return {
|
|
80
|
+
id: 9001,
|
|
81
|
+
hash_id: '8WR5Kypbw9KQK20',
|
|
82
|
+
key: 'publicEntry',
|
|
83
|
+
name: 'Public entry',
|
|
84
|
+
entity: entityDetail(),
|
|
85
|
+
options: {
|
|
86
|
+
policy: {
|
|
87
|
+
actions,
|
|
88
|
+
all_fields_read: true,
|
|
89
|
+
all_fields_write: true,
|
|
90
|
+
fields: [],
|
|
78
91
|
},
|
|
79
|
-
|
|
92
|
+
list_options: {},
|
|
93
|
+
},
|
|
80
94
|
}
|
|
81
95
|
}
|
|
82
96
|
|
|
83
|
-
test('generateArcubaseProjectSDK emits typed
|
|
97
|
+
test('generateArcubaseProjectSDK emits typed ingress sdk selected from client.ingress', () => {
|
|
84
98
|
const result = generateArcubaseProjectSDK(sdkSchemaPayload())
|
|
85
99
|
|
|
86
100
|
assert.deepEqual(result.files.map((file) => file.path).sort(), [
|
|
87
101
|
'client.ts',
|
|
88
|
-
'entities/story.ts',
|
|
89
102
|
'index.ts',
|
|
103
|
+
'ingresses/publicEntry.ts',
|
|
90
104
|
'runtime.ts',
|
|
91
105
|
'schema.ts',
|
|
92
106
|
])
|
|
93
107
|
|
|
94
108
|
const client = result.files.find((file) => file.path === 'client.ts')?.contents ?? ''
|
|
95
|
-
assert.match(client, /
|
|
96
|
-
assert.match(client, /
|
|
109
|
+
assert.match(client, /createArcubaseClient/)
|
|
110
|
+
assert.match(client, /ingress<K extends ArcubaseIngressKey>\(key: K\)/)
|
|
111
|
+
assert.match(client, /case ["']publicEntry["']/)
|
|
97
112
|
|
|
98
113
|
const runtime = result.files.find((file) => file.path === 'runtime.ts')?.contents ?? ''
|
|
99
114
|
assert.match(runtime, /accessToken/)
|
|
100
115
|
assert.match(runtime, /refreshToken/)
|
|
101
116
|
|
|
102
|
-
const
|
|
103
|
-
assert.match(
|
|
104
|
-
assert.match(
|
|
105
|
-
assert.match(
|
|
106
|
-
assert.match(
|
|
107
|
-
assert.match(
|
|
108
|
-
assert.match(
|
|
109
|
-
assert.match(
|
|
110
|
-
assert.match(
|
|
111
|
-
assert.match(
|
|
117
|
+
const ingress = result.files.find((file) => file.path === 'ingresses/publicEntry.ts')?.contents ?? ''
|
|
118
|
+
assert.match(ingress, /export type PublicEntryFields =/)
|
|
119
|
+
assert.match(ingress, /title: string/)
|
|
120
|
+
assert.match(ingress, /status\?: number \| string/)
|
|
121
|
+
assert.match(ingress, /notes\?: string/)
|
|
122
|
+
assert.match(ingress, /create\(fields: PublicEntryCreateInput\)/)
|
|
123
|
+
assert.match(ingress, /update\(rowId: string \| number, fields: PublicEntryUpdateInput\)/)
|
|
124
|
+
assert.match(ingress, /query\(params: PublicEntryQueryParams = {}\)/)
|
|
125
|
+
assert.match(ingress, /delete\(selection: PublicEntrySelection\)/)
|
|
126
|
+
assert.match(ingress, /bulkUpdate\(selection: PublicEntrySelection, fields: PublicEntryBulkUpdateField\[\]\)/)
|
|
127
|
+
assert.match(ingress, /exportRows\(options: PublicEntryExportOptions = {}\)/)
|
|
128
|
+
assert.match(ingress, /batchPrint\(selection: PublicEntrySelection/)
|
|
129
|
+
assert.match(ingress, /archive\(selection: PublicEntrySelection\)/)
|
|
130
|
+
assert.match(ingress, /tags:/)
|
|
131
|
+
assert.match(ingress, /policy_id: ingressId/)
|
|
112
132
|
|
|
113
133
|
const schema = result.files.find((file) => file.path === 'schema.ts')?.contents ?? ''
|
|
114
|
-
assert.match(schema, /"
|
|
134
|
+
assert.match(schema, /"publicEntry"/)
|
|
115
135
|
assert.match(schema, /"fieldId": 1011/)
|
|
116
136
|
assert.match(schema, /"entityId": 3883547182/)
|
|
137
|
+
assert.match(schema, /"ingressId": "8WR5Kypbw9KQK20"/)
|
|
138
|
+
assert.doesNotMatch(schema, /entity3883547182/)
|
|
117
139
|
})
|
|
118
140
|
|
|
119
141
|
test('generateArcubaseProjectSDK rejects missing field keys', () => {
|
|
120
142
|
const payload = sdkSchemaPayload()
|
|
121
|
-
payload.
|
|
143
|
+
payload.ingresses[0].entity.fields[1].key = ''
|
|
122
144
|
|
|
123
145
|
assert.throws(() => generateArcubaseProjectSDK(payload), (error: unknown) => {
|
|
124
146
|
assert.ok(error instanceof CLIError)
|
|
125
147
|
assert.equal(error.code, 'SDK_GEN_FIELD_KEY_REQUIRED')
|
|
126
|
-
assert.match(error.message,
|
|
148
|
+
assert.match(error.message, /Status/)
|
|
127
149
|
return true
|
|
128
150
|
})
|
|
129
151
|
})
|
|
130
152
|
|
|
131
153
|
test('generateArcubaseProjectSDK rejects duplicate field keys within an entity', () => {
|
|
132
154
|
const payload = sdkSchemaPayload()
|
|
133
|
-
payload.
|
|
155
|
+
payload.ingresses[0].entity.fields[1].key = 'notes'
|
|
134
156
|
|
|
135
157
|
assert.throws(() => generateArcubaseProjectSDK(payload), (error: unknown) => {
|
|
136
158
|
assert.ok(error instanceof CLIError)
|
|
137
159
|
assert.equal(error.code, 'SDK_GEN_DUPLICATE_FIELD_KEY')
|
|
138
|
-
assert.match(error.message, /
|
|
160
|
+
assert.match(error.message, /notes/)
|
|
161
|
+
return true
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
test('generateArcubaseProjectSDK rejects missing ingress keys', () => {
|
|
166
|
+
const payload = sdkSchemaPayload()
|
|
167
|
+
payload.ingresses[0].key = ''
|
|
168
|
+
|
|
169
|
+
assert.throws(() => generateArcubaseProjectSDK(payload), (error: unknown) => {
|
|
170
|
+
assert.ok(error instanceof CLIError)
|
|
171
|
+
assert.equal(error.code, 'SDK_GEN_INGRESS_KEY_REQUIRED')
|
|
172
|
+
assert.match(error.message, /Public entry/)
|
|
139
173
|
return true
|
|
140
174
|
})
|
|
141
175
|
})
|
|
142
176
|
|
|
177
|
+
test('generateArcubaseProjectSDK only emits methods allowed by ingress actions', () => {
|
|
178
|
+
const payload = {
|
|
179
|
+
id: 3882856425,
|
|
180
|
+
ingresses: [ingressDefinition(['view'])],
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const result = generateArcubaseProjectSDK(payload)
|
|
184
|
+
const ingress = result.files.find((file) => file.path === 'ingresses/publicEntry.ts')?.contents ?? ''
|
|
185
|
+
assert.match(ingress, /query\(params: PublicEntryQueryParams = {}\)/)
|
|
186
|
+
assert.doesNotMatch(ingress, /create\(fields:/)
|
|
187
|
+
assert.doesNotMatch(ingress, /update\(rowId:/)
|
|
188
|
+
assert.doesNotMatch(ingress, /bulkUpdate\(/)
|
|
189
|
+
})
|
|
190
|
+
|
|
143
191
|
test('arcubase-admin dev sdk-gen fetches app schema and writes typed sdk files', async () => {
|
|
144
192
|
const outDir = fs.mkdtempSync(path.join(os.tmpdir(), 'arcubase-sdk-gen-'))
|
|
145
193
|
const calls: Array<{ url: string; method?: string }> = []
|
|
@@ -159,6 +207,9 @@ test('arcubase-admin dev sdk-gen fetches app schema and writes typed sdk files',
|
|
|
159
207
|
if (String(url).endsWith('/api/apps/3882856425/entity/3883547182')) {
|
|
160
208
|
return new Response(JSON.stringify({ data: entityDetail() }), { status: 200 })
|
|
161
209
|
}
|
|
210
|
+
if (String(url).endsWith('/api/apps/3882856425/entity/3883547182/ingress')) {
|
|
211
|
+
return new Response(JSON.stringify({ data: { list: [ingressDefinition()] } }), { status: 200 })
|
|
212
|
+
}
|
|
162
213
|
return new Response(JSON.stringify({ error: { message: `unexpected url ${url}` } }), { status: 404 })
|
|
163
214
|
},
|
|
164
215
|
)
|
|
@@ -171,10 +222,13 @@ test('arcubase-admin dev sdk-gen fetches app schema and writes typed sdk files',
|
|
|
171
222
|
assert.match(calls[1].url, /\/api\/apps\/3882856425\/entities$/)
|
|
172
223
|
assert.equal(calls[2].method, 'GET')
|
|
173
224
|
assert.match(calls[2].url, /\/api\/apps\/3882856425\/entity\/3883547182$/)
|
|
225
|
+
assert.equal(calls[3].method, 'GET')
|
|
226
|
+
assert.match(calls[3].url, /\/api\/apps\/3882856425\/entity\/3883547182\/ingress$/)
|
|
174
227
|
assert.ok(fs.existsSync(path.join(outDir, 'index.ts')))
|
|
175
228
|
assert.ok(fs.existsSync(path.join(outDir, 'client.ts')))
|
|
176
|
-
assert.ok(fs.existsSync(path.join(outDir, '
|
|
177
|
-
assert.match(fs.readFileSync(path.join(outDir, 'client.ts'), 'utf8'), /
|
|
229
|
+
assert.ok(fs.existsSync(path.join(outDir, 'ingresses/publicEntry.ts')))
|
|
230
|
+
assert.match(fs.readFileSync(path.join(outDir, 'client.ts'), 'utf8'), /createArcubaseClient/)
|
|
231
|
+
assert.notEqual(fs.existsSync(path.join(outDir, 'entities')), true)
|
|
178
232
|
})
|
|
179
233
|
|
|
180
234
|
test('arcubase-admin dev sdk-gen fails before generation when field keys are missing', async () => {
|
|
@@ -196,15 +250,50 @@ test('arcubase-admin dev sdk-gen fails before generation when field keys are mis
|
|
|
196
250
|
if (String(url).endsWith('/api/apps/3882856425/entity/3883547182')) {
|
|
197
251
|
return new Response(JSON.stringify({ data: entityDetailWithoutFieldKeys() }), { status: 200 })
|
|
198
252
|
}
|
|
253
|
+
if (String(url).endsWith('/api/apps/3882856425/entity/3883547182/ingress')) {
|
|
254
|
+
return new Response(JSON.stringify({ data: { list: [ingressDefinition()] } }), { status: 200 })
|
|
255
|
+
}
|
|
199
256
|
return new Response(JSON.stringify({ error: { message: `unexpected url ${url}` } }), { status: 404 })
|
|
200
257
|
},
|
|
201
258
|
), (error: unknown) => {
|
|
202
259
|
assert.ok(error instanceof CLIError)
|
|
203
260
|
assert.equal(error.code, 'SDK_GEN_FIELD_KEY_REQUIRED')
|
|
204
|
-
assert.match(error.message,
|
|
261
|
+
assert.match(error.message, /Records\.Title \(1006\)/)
|
|
205
262
|
return true
|
|
206
263
|
})
|
|
207
264
|
|
|
208
265
|
assert.equal(calls.some((call) => call.url.endsWith('/custom-keys')), false)
|
|
209
266
|
assert.equal(fs.existsSync(path.join(outDir, 'index.ts')), false)
|
|
210
267
|
})
|
|
268
|
+
|
|
269
|
+
test('arcubase-admin dev sdk-gen fails before generation when ingress keys are missing', async () => {
|
|
270
|
+
const outDir = fs.mkdtempSync(path.join(os.tmpdir(), 'arcubase-sdk-gen-'))
|
|
271
|
+
|
|
272
|
+
await assert.rejects(() => executeCLI(
|
|
273
|
+
'admin',
|
|
274
|
+
['dev', 'sdk-gen', '--app-id', '3882856425', '--out', outDir],
|
|
275
|
+
env as any,
|
|
276
|
+
async (url) => {
|
|
277
|
+
if (String(url).endsWith('/api/apps/3882856425')) {
|
|
278
|
+
return new Response(JSON.stringify({ data: appDetail() }), { status: 200 })
|
|
279
|
+
}
|
|
280
|
+
if (String(url).endsWith('/api/apps/3882856425/entities')) {
|
|
281
|
+
return new Response(JSON.stringify({ data: entityList() }), { status: 200 })
|
|
282
|
+
}
|
|
283
|
+
if (String(url).endsWith('/api/apps/3882856425/entity/3883547182')) {
|
|
284
|
+
return new Response(JSON.stringify({ data: entityDetail() }), { status: 200 })
|
|
285
|
+
}
|
|
286
|
+
if (String(url).endsWith('/api/apps/3882856425/entity/3883547182/ingress')) {
|
|
287
|
+
return new Response(JSON.stringify({ data: { list: [{ ...ingressDefinition(), key: '' }] } }), { status: 200 })
|
|
288
|
+
}
|
|
289
|
+
return new Response(JSON.stringify({ error: { message: `unexpected url ${url}` } }), { status: 404 })
|
|
290
|
+
},
|
|
291
|
+
), (error: unknown) => {
|
|
292
|
+
assert.ok(error instanceof CLIError)
|
|
293
|
+
assert.equal(error.code, 'SDK_GEN_INGRESS_KEY_REQUIRED')
|
|
294
|
+
assert.match(error.message, /Public entry/)
|
|
295
|
+
return true
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
assert.equal(fs.existsSync(path.join(outDir, 'index.ts')), false)
|
|
299
|
+
})
|
package/src/tests/help.test.ts
CHANGED
|
@@ -36,8 +36,9 @@ test('admin dev sdk-gen help documents typed project sdk generation', async () =
|
|
|
36
36
|
assert.match(commandHelp.text, /arcubase-admin dev sdk-gen/)
|
|
37
37
|
assert.match(commandHelp.text, /--app-id/)
|
|
38
38
|
assert.match(commandHelp.text, /--out/)
|
|
39
|
+
assert.match(commandHelp.text, /ingress\.key/)
|
|
39
40
|
assert.match(commandHelp.text, /field\.key/)
|
|
40
|
-
assert.match(commandHelp.text, /
|
|
41
|
+
assert.match(commandHelp.text, /createArcubaseClient\(\{ baseURL, accessToken, refreshToken \}\)\.ingress\("<IngressKey>"\)/)
|
|
41
42
|
})
|
|
42
43
|
|
|
43
44
|
test('user root help exposes reset surface nouns only', async () => {
|