@pikku/inspector 0.12.24 → 0.12.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/CHANGELOG.md +48 -0
- package/dist/add/add-auth.js +11 -0
- package/dist/add/add-gateway.js +5 -1
- package/dist/add/add-permission.js +5 -1
- package/dist/types.d.ts +6 -0
- package/dist/utils/post-process.js +8 -0
- package/package.json +2 -2
- package/src/add/add-auth.test.ts +50 -0
- package/src/add/add-auth.ts +14 -0
- package/src/add/add-gateway.ts +6 -2
- package/src/add/add-permission-auth.test.ts +59 -0
- package/src/add/add-permission.ts +6 -1
- package/src/types.ts +6 -0
- package/src/utils/compute-diagnostics.test.ts +69 -0
- package/src/utils/post-process.ts +8 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,51 @@
|
|
|
1
|
+
## 0.12.26
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- ed548d5: fix(auth): skip the generated global `betterAuthSession()` when the user registers their own
|
|
6
|
+
|
|
7
|
+
The CLI's `auth.gen.ts` unconditionally wired a global
|
|
8
|
+
`addHTTPMiddleware('*', [betterAuthSession()])` (default map) on the stateful
|
|
9
|
+
path. A project that needs a customized session bridge — `mapSession`,
|
|
10
|
+
`impersonation`, `apiKey` — had to register a second global
|
|
11
|
+
`betterAuthSession({...})`, leaving two in the chain; the generated default ran
|
|
12
|
+
first and short-circuited (`if (session) next()`) so the custom one never took
|
|
13
|
+
effect.
|
|
14
|
+
|
|
15
|
+
The inspector now records `state.auth.hasUserSessionMiddleware` when it sees a
|
|
16
|
+
user-authored **global** `betterAuthSession` registration (route-scoped and
|
|
17
|
+
`.gen.ts` registrations are ignored, so regeneration never self-suppresses).
|
|
18
|
+
The CLI omits its own global `betterAuthSession()` from `auth.gen.ts` when that
|
|
19
|
+
flag is set — exactly one session bridge in the chain, the user's. Mirrors the
|
|
20
|
+
existing stateless skip (`userStatelessSession`, #754).
|
|
21
|
+
|
|
22
|
+
## 0.12.25
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- b6ba601: fix(lint): don't flag pikkuAuth's session param as a non-destructured wire
|
|
27
|
+
|
|
28
|
+
`pikkuAuth`'s handler is `(services, session)` — the second parameter is the
|
|
29
|
+
resolved user session, not a wires bag. The inspector was extracting "wires"
|
|
30
|
+
from that parameter (`extractUsedWires(handler, 1)`), so a permission like
|
|
31
|
+
`pikkuAuth(async ({ logger }, session) => !!session)` tripped
|
|
32
|
+
`wiresNotDestructured` even though `session` cannot be destructured. pikkuAuth
|
|
33
|
+
exposes no user-facing wires parameter, so no wires meta is recorded for it.
|
|
34
|
+
|
|
35
|
+
- ae7fc5d: Include gateway platform and auth fields in inspected gateway metadata.
|
|
36
|
+
- decdad5: fix(lint): don't fail the build on framework-synthesized functions
|
|
37
|
+
|
|
38
|
+
The `servicesNotDestructured`/`wiresNotDestructured` defaults (`error`) were
|
|
39
|
+
tripping on functions the user can't edit: generated `.gen.ts` wrappers (the
|
|
40
|
+
opaque `authHandler`, the cli channel raw dispatcher) and synthetic route→addon
|
|
41
|
+
bridges (`http:<method>:<route>`, no source file). `computeDiagnostics` now skips
|
|
42
|
+
any function without a real, non-generated source file, so the lint only nudges
|
|
43
|
+
hand-written user code. Also destructures the CLI's own `all` command.
|
|
44
|
+
|
|
45
|
+
- Updated dependencies [ae7fc5d]
|
|
46
|
+
- Updated dependencies [fa7a09c]
|
|
47
|
+
- @pikku/core@0.12.37
|
|
48
|
+
|
|
1
49
|
## 0.12.24
|
|
2
50
|
|
|
3
51
|
### Patch Changes
|
package/dist/add/add-auth.js
CHANGED
|
@@ -137,6 +137,17 @@ export const addAuth = (logger, node, _checker, state) => {
|
|
|
137
137
|
isInsideGlobalMiddlewareRegistration(node)) {
|
|
138
138
|
state.auth.userStatelessSession = true;
|
|
139
139
|
}
|
|
140
|
+
// Same rule for the stateful variant: a user-registered global
|
|
141
|
+
// betterAuthSession(...) (custom mapSession/impersonation/apiKey) means the CLI
|
|
142
|
+
// must NOT auto-generate its own default one — the generated one runs first and
|
|
143
|
+
// pre-empts the user's via the `if (session) next()` short-circuit. Stateful
|
|
144
|
+
// analogue of the betterAuthStatelessSession skip above.
|
|
145
|
+
if (ts.isIdentifier(expression) &&
|
|
146
|
+
expression.text === 'betterAuthSession' &&
|
|
147
|
+
!node.getSourceFile().fileName.endsWith('.gen.ts') &&
|
|
148
|
+
isInsideGlobalMiddlewareRegistration(node)) {
|
|
149
|
+
state.auth.hasUserSessionMiddleware = true;
|
|
150
|
+
}
|
|
140
151
|
if (!ts.isIdentifier(expression) || expression.text !== 'pikkuBetterAuth')
|
|
141
152
|
return;
|
|
142
153
|
const sourceFile = node.getSourceFile().fileName;
|
package/dist/add/add-gateway.js
CHANGED
|
@@ -23,6 +23,8 @@ export const addGateway = (logger, node, checker, state, _options) => {
|
|
|
23
23
|
const nameValue = getPropertyValue(obj, 'name');
|
|
24
24
|
const typeValue = getPropertyValue(obj, 'type');
|
|
25
25
|
const routeValue = getPropertyValue(obj, 'route');
|
|
26
|
+
const platformValue = getPropertyValue(obj, 'platform');
|
|
27
|
+
const authValue = getPropertyValue(obj, 'auth');
|
|
26
28
|
const { disabled, tags, summary, description, errors } = getCommonWireMetaData(obj, 'Gateway', nameValue, logger, checker);
|
|
27
29
|
if (disabled)
|
|
28
30
|
return;
|
|
@@ -51,7 +53,9 @@ export const addGateway = (logger, node, checker, state, _options) => {
|
|
|
51
53
|
...(packageName && { packageName }),
|
|
52
54
|
name: nameValue,
|
|
53
55
|
type: typeValue,
|
|
54
|
-
route: routeValue,
|
|
56
|
+
...(routeValue && { route: routeValue }),
|
|
57
|
+
...(platformValue && { platform: platformValue }),
|
|
58
|
+
...(typeof authValue === 'boolean' && { auth: authValue }),
|
|
55
59
|
gateway: true,
|
|
56
60
|
summary,
|
|
57
61
|
description,
|
|
@@ -141,7 +141,11 @@ export const addPermission = (logger, node, checker, state) => {
|
|
|
141
141
|
return;
|
|
142
142
|
}
|
|
143
143
|
const services = extractServicesFromFunction(actualHandler);
|
|
144
|
-
|
|
144
|
+
// pikkuAuth's handler is (services, session) — its second parameter is the
|
|
145
|
+
// resolved user session, NOT a wires bag, so it must not be analyzed (or
|
|
146
|
+
// flagged) as a non-destructured wires parameter. pikkuAuth exposes no
|
|
147
|
+
// user-facing wires parameter.
|
|
148
|
+
const wires = { optimized: true, wires: [] };
|
|
145
149
|
let { pikkuFuncId, exportedName } = extractFunctionName(node, checker, state.rootDir);
|
|
146
150
|
if (pikkuFuncId.startsWith('__temp_')) {
|
|
147
151
|
if (ts.isVariableDeclaration(node.parent) &&
|
package/dist/types.d.ts
CHANGED
|
@@ -436,6 +436,12 @@ export interface InspectorState {
|
|
|
436
436
|
* own default-map stateless middleware, which would otherwise pre-empt the
|
|
437
437
|
* user's custom mapSession (pikkujs/pikku#754). */
|
|
438
438
|
userStatelessSession?: boolean;
|
|
439
|
+
/** True when a user (non-generated) file already registers a global
|
|
440
|
+
* `betterAuthSession(...)`. The CLI then skips auto-generating its own
|
|
441
|
+
* default stateful middleware, which would otherwise run first and pre-empt
|
|
442
|
+
* the user's config (mapSession/impersonation/apiKey). Stateful analogue of
|
|
443
|
+
* `userStatelessSession`. */
|
|
444
|
+
hasUserSessionMiddleware?: boolean;
|
|
439
445
|
};
|
|
440
446
|
secrets: {
|
|
441
447
|
definitions: SecretDefinitions;
|
|
@@ -525,6 +525,14 @@ export function validateSchemaWiringSeparation(logger, state) {
|
|
|
525
525
|
export function computeDiagnostics(state) {
|
|
526
526
|
const diagnostics = [];
|
|
527
527
|
for (const [id, meta] of Object.entries(state.functions.meta)) {
|
|
528
|
+
// Skip framework-synthesized functions: generated wrappers (auth.gen.ts's
|
|
529
|
+
// opaque authHandler, the cli channel's raw dispatcher) and synthetic route
|
|
530
|
+
// bridges that reference addon functions (id `http:<method>:<route>`, no
|
|
531
|
+
// source file). The user can't edit any of these, so a destructure lint
|
|
532
|
+
// meant to nudge them about their own code must not fail the build over them.
|
|
533
|
+
if (!meta.sourceFile || meta.sourceFile.endsWith('.gen.ts')) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
528
536
|
if (meta.services && !meta.services.optimized) {
|
|
529
537
|
diagnostics.push({
|
|
530
538
|
code: ErrorCode.SERVICES_NOT_DESTRUCTURED,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.26",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@openapi-contrib/json-schema-to-openapi-schema": "^4.3.1",
|
|
38
|
-
"@pikku/core": "^0.12.
|
|
38
|
+
"@pikku/core": "^0.12.37",
|
|
39
39
|
"openapi-types": "^12.1.3",
|
|
40
40
|
"path-to-regexp": "^8.3.0",
|
|
41
41
|
"ts-json-schema-generator": "^2.5.0",
|
package/src/add/add-auth.test.ts
CHANGED
|
@@ -616,4 +616,54 @@ describe('addAuth inspector', () => {
|
|
|
616
616
|
await rm(rootDir, { recursive: true, force: true })
|
|
617
617
|
}
|
|
618
618
|
})
|
|
619
|
+
|
|
620
|
+
test('user-registered global betterAuthSession sets hasUserSessionMiddleware', async () => {
|
|
621
|
+
const rootDir = await mkdtemp(join(tmpdir(), 'pikku-add-auth-session-'))
|
|
622
|
+
const file = join(rootDir, 'middleware.ts')
|
|
623
|
+
await writeFile(
|
|
624
|
+
file,
|
|
625
|
+
[
|
|
626
|
+
"import { addHTTPMiddleware } from '#pikku'",
|
|
627
|
+
"import { betterAuthSession } from '@pikku/better-auth'",
|
|
628
|
+
"addHTTPMiddleware('*', [",
|
|
629
|
+
' betterAuthSession({',
|
|
630
|
+
' impersonation: { loadUser: (id: string) => ({ id }) },',
|
|
631
|
+
' }),',
|
|
632
|
+
'])',
|
|
633
|
+
].join('\n')
|
|
634
|
+
)
|
|
635
|
+
const criticals: Array<{ code: ErrorCode; message: string }> = []
|
|
636
|
+
try {
|
|
637
|
+
const state = await inspect(makeLogger(criticals), [file], { rootDir })
|
|
638
|
+
assert.equal(state.auth.hasUserSessionMiddleware, true)
|
|
639
|
+
} finally {
|
|
640
|
+
await rm(rootDir, { recursive: true, force: true })
|
|
641
|
+
}
|
|
642
|
+
})
|
|
643
|
+
|
|
644
|
+
test('betterAuthSession in a .gen.ts file does NOT set hasUserSessionMiddleware', async () => {
|
|
645
|
+
// Critical: the CLI's own auth.gen.ts contains addHTTPMiddleware('*',
|
|
646
|
+
// [betterAuthSession()]). It must not count as a user registration, or it
|
|
647
|
+
// would suppress itself and leave the chain with no session middleware.
|
|
648
|
+
const rootDir = await mkdtemp(join(tmpdir(), 'pikku-add-auth-session-gen-'))
|
|
649
|
+
const file = join(rootDir, 'auth.gen.ts')
|
|
650
|
+
await writeFile(
|
|
651
|
+
file,
|
|
652
|
+
[
|
|
653
|
+
"import { addHTTPMiddleware } from '#pikku'",
|
|
654
|
+
"import { betterAuthSession } from '@pikku/better-auth'",
|
|
655
|
+
"addHTTPMiddleware('*', [betterAuthSession()])",
|
|
656
|
+
].join('\n')
|
|
657
|
+
)
|
|
658
|
+
const criticals: Array<{ code: ErrorCode; message: string }> = []
|
|
659
|
+
try {
|
|
660
|
+
const state = await inspect(makeLogger(criticals), [file], { rootDir })
|
|
661
|
+
assert.ok(
|
|
662
|
+
!state.auth.hasUserSessionMiddleware,
|
|
663
|
+
'generated file must not self-trigger the skip'
|
|
664
|
+
)
|
|
665
|
+
} finally {
|
|
666
|
+
await rm(rootDir, { recursive: true, force: true })
|
|
667
|
+
}
|
|
668
|
+
})
|
|
619
669
|
})
|
package/src/add/add-auth.ts
CHANGED
|
@@ -168,6 +168,20 @@ export const addAuth: AddWiring = (logger, node, _checker, state) => {
|
|
|
168
168
|
state.auth.userStatelessSession = true
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
// Same rule for the stateful variant: a user-registered global
|
|
172
|
+
// betterAuthSession(...) (custom mapSession/impersonation/apiKey) means the CLI
|
|
173
|
+
// must NOT auto-generate its own default one — the generated one runs first and
|
|
174
|
+
// pre-empts the user's via the `if (session) next()` short-circuit. Stateful
|
|
175
|
+
// analogue of the betterAuthStatelessSession skip above.
|
|
176
|
+
if (
|
|
177
|
+
ts.isIdentifier(expression) &&
|
|
178
|
+
expression.text === 'betterAuthSession' &&
|
|
179
|
+
!node.getSourceFile().fileName.endsWith('.gen.ts') &&
|
|
180
|
+
isInsideGlobalMiddlewareRegistration(node)
|
|
181
|
+
) {
|
|
182
|
+
state.auth.hasUserSessionMiddleware = true
|
|
183
|
+
}
|
|
184
|
+
|
|
171
185
|
if (!ts.isIdentifier(expression) || expression.text !== 'pikkuBetterAuth')
|
|
172
186
|
return
|
|
173
187
|
|
package/src/add/add-gateway.ts
CHANGED
|
@@ -43,7 +43,9 @@ export const addGateway: AddWiring = (
|
|
|
43
43
|
|
|
44
44
|
const nameValue = getPropertyValue(obj, 'name') as string | null
|
|
45
45
|
const typeValue = getPropertyValue(obj, 'type') as GatewayTransportType | null
|
|
46
|
-
const routeValue = getPropertyValue(obj, 'route') as string |
|
|
46
|
+
const routeValue = getPropertyValue(obj, 'route') as string | null
|
|
47
|
+
const platformValue = getPropertyValue(obj, 'platform') as string | null
|
|
48
|
+
const authValue = getPropertyValue(obj, 'auth')
|
|
47
49
|
const { disabled, tags, summary, description, errors } =
|
|
48
50
|
getCommonWireMetaData(obj, 'Gateway', nameValue, logger, checker)
|
|
49
51
|
|
|
@@ -94,7 +96,9 @@ export const addGateway: AddWiring = (
|
|
|
94
96
|
...(packageName && { packageName }),
|
|
95
97
|
name: nameValue,
|
|
96
98
|
type: typeValue,
|
|
97
|
-
route: routeValue,
|
|
99
|
+
...(routeValue && { route: routeValue }),
|
|
100
|
+
...(platformValue && { platform: platformValue }),
|
|
101
|
+
...(typeof authValue === 'boolean' && { auth: authValue }),
|
|
98
102
|
gateway: true,
|
|
99
103
|
summary,
|
|
100
104
|
description,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { strict as assert } from 'assert'
|
|
2
|
+
import { describe, test } from 'node:test'
|
|
3
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
4
|
+
import { tmpdir } from 'node:os'
|
|
5
|
+
import { join } from 'node:path'
|
|
6
|
+
import { inspect } from '../inspector.js'
|
|
7
|
+
import { ErrorCode } from '../error-codes.js'
|
|
8
|
+
import type { InspectorLogger } from '../types.js'
|
|
9
|
+
|
|
10
|
+
const makeLogger = (criticals: Array<{ code: ErrorCode; message: string }>) =>
|
|
11
|
+
({
|
|
12
|
+
debug: () => {},
|
|
13
|
+
info: () => {},
|
|
14
|
+
warn: () => {},
|
|
15
|
+
error: () => {},
|
|
16
|
+
diagnostic: ({ code, message }) => {
|
|
17
|
+
criticals.push({ code, message })
|
|
18
|
+
},
|
|
19
|
+
critical: (code: ErrorCode, message: string) => {
|
|
20
|
+
criticals.push({ code, message })
|
|
21
|
+
},
|
|
22
|
+
hasCriticalErrors: () => criticals.length > 0,
|
|
23
|
+
}) satisfies InspectorLogger
|
|
24
|
+
|
|
25
|
+
describe('addPermission — pikkuAuth', () => {
|
|
26
|
+
test('does not record a wires meta for the session parameter', async () => {
|
|
27
|
+
const rootDir = await mkdtemp(join(tmpdir(), 'pikku-auth-wires-'))
|
|
28
|
+
const file = join(rootDir, 'auth.ts')
|
|
29
|
+
|
|
30
|
+
await writeFile(
|
|
31
|
+
file,
|
|
32
|
+
[
|
|
33
|
+
'const pikkuAuth = (x: any) => x',
|
|
34
|
+
'export const isAuthenticated = pikkuAuth(async ({ logger }, session) => {',
|
|
35
|
+
' logger.info({ type: "auth-check" })',
|
|
36
|
+
' return !!session',
|
|
37
|
+
'})',
|
|
38
|
+
].join('\n')
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
const criticals: Array<{ code: ErrorCode; message: string }> = []
|
|
42
|
+
try {
|
|
43
|
+
const state = await inspect(makeLogger(criticals), [file], { rootDir })
|
|
44
|
+
const def = state.permissions.definitions['isAuthenticated']
|
|
45
|
+
assert.ok(def, 'isAuthenticated permission should be recorded')
|
|
46
|
+
// The pikkuAuth handler is (services, session) — session is NOT a wires
|
|
47
|
+
// bag and must not be flagged as a non-destructured wires parameter.
|
|
48
|
+
assert.equal(def.wires, undefined)
|
|
49
|
+
const wireDiag = (state.diagnostics ?? []).find(
|
|
50
|
+
(d) =>
|
|
51
|
+
d.code === ErrorCode.WIRES_NOT_DESTRUCTURED &&
|
|
52
|
+
d.message.includes('isAuthenticated')
|
|
53
|
+
)
|
|
54
|
+
assert.equal(wireDiag, undefined)
|
|
55
|
+
} finally {
|
|
56
|
+
await rm(rootDir, { recursive: true, force: true })
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
+
import type { FunctionWiresMeta } from '@pikku/core'
|
|
2
3
|
import type { AddWiring, InspectorState } from '../types.js'
|
|
3
4
|
import {
|
|
4
5
|
extractFunctionName,
|
|
@@ -195,7 +196,11 @@ export const addPermission: AddWiring = (logger, node, checker, state) => {
|
|
|
195
196
|
}
|
|
196
197
|
|
|
197
198
|
const services = extractServicesFromFunction(actualHandler)
|
|
198
|
-
|
|
199
|
+
// pikkuAuth's handler is (services, session) — its second parameter is the
|
|
200
|
+
// resolved user session, NOT a wires bag, so it must not be analyzed (or
|
|
201
|
+
// flagged) as a non-destructured wires parameter. pikkuAuth exposes no
|
|
202
|
+
// user-facing wires parameter.
|
|
203
|
+
const wires: FunctionWiresMeta = { optimized: true, wires: [] }
|
|
199
204
|
let { pikkuFuncId, exportedName } = extractFunctionName(
|
|
200
205
|
node,
|
|
201
206
|
checker,
|
package/src/types.ts
CHANGED
|
@@ -502,6 +502,12 @@ export interface InspectorState {
|
|
|
502
502
|
* own default-map stateless middleware, which would otherwise pre-empt the
|
|
503
503
|
* user's custom mapSession (pikkujs/pikku#754). */
|
|
504
504
|
userStatelessSession?: boolean
|
|
505
|
+
/** True when a user (non-generated) file already registers a global
|
|
506
|
+
* `betterAuthSession(...)`. The CLI then skips auto-generating its own
|
|
507
|
+
* default stateful middleware, which would otherwise run first and pre-empt
|
|
508
|
+
* the user's config (mapSession/impersonation/apiKey). Stateful analogue of
|
|
509
|
+
* `userStatelessSession`. */
|
|
510
|
+
hasUserSessionMiddleware?: boolean
|
|
505
511
|
}
|
|
506
512
|
secrets: {
|
|
507
513
|
definitions: SecretDefinitions
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { test, describe } from 'node:test'
|
|
2
|
+
import { strict as assert } from 'node:assert'
|
|
3
|
+
import { computeDiagnostics } from './post-process.js'
|
|
4
|
+
import type { InspectorState } from '../types.js'
|
|
5
|
+
import { ErrorCode } from '../error-codes.js'
|
|
6
|
+
|
|
7
|
+
function stateWithFunctions(
|
|
8
|
+
meta: InspectorState['functions']['meta']
|
|
9
|
+
): InspectorState {
|
|
10
|
+
return {
|
|
11
|
+
functions: { meta },
|
|
12
|
+
middleware: { definitions: {} },
|
|
13
|
+
permissions: { definitions: {} },
|
|
14
|
+
} as unknown as InspectorState
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('computeDiagnostics', () => {
|
|
18
|
+
test('flags a user-authored function that does not destructure services', () => {
|
|
19
|
+
const state = stateWithFunctions({
|
|
20
|
+
myFunc: {
|
|
21
|
+
pikkuFuncId: 'myFunc',
|
|
22
|
+
inputSchemaName: null,
|
|
23
|
+
outputSchemaName: null,
|
|
24
|
+
sourceFile: '/project/src/my-func.ts',
|
|
25
|
+
services: { optimized: false, services: ['kysely'] },
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
computeDiagnostics(state)
|
|
29
|
+
assert.equal(state.diagnostics.length, 1)
|
|
30
|
+
assert.equal(
|
|
31
|
+
state.diagnostics[0].code,
|
|
32
|
+
ErrorCode.SERVICES_NOT_DESTRUCTURED
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('does NOT flag a generated .gen.ts function (user cannot edit it)', () => {
|
|
37
|
+
const state = stateWithFunctions({
|
|
38
|
+
cliRaw: {
|
|
39
|
+
pikkuFuncId: 'cliRaw',
|
|
40
|
+
inputSchemaName: null,
|
|
41
|
+
outputSchemaName: null,
|
|
42
|
+
sourceFile: '/project/src/wirings/cli-channel.gen.ts',
|
|
43
|
+
services: { optimized: false, services: ['kysely'] },
|
|
44
|
+
},
|
|
45
|
+
authHandler: {
|
|
46
|
+
pikkuFuncId: 'authHandler',
|
|
47
|
+
inputSchemaName: null,
|
|
48
|
+
outputSchemaName: null,
|
|
49
|
+
sourceFile: '/project/.pikku/auth.gen.ts',
|
|
50
|
+
wires: { optimized: false, wires: ['http'] },
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
computeDiagnostics(state)
|
|
54
|
+
assert.equal(state.diagnostics.length, 0)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('does NOT flag a synthetic route bridge with no source file', () => {
|
|
58
|
+
const state = stateWithFunctions({
|
|
59
|
+
'http:get:/workflow-run/:runId/stream': {
|
|
60
|
+
pikkuFuncId: 'http:get:/workflow-run/:runId/stream',
|
|
61
|
+
inputSchemaName: null,
|
|
62
|
+
outputSchemaName: null,
|
|
63
|
+
services: { optimized: false, services: [] },
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
computeDiagnostics(state)
|
|
67
|
+
assert.equal(state.diagnostics.length, 0)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
@@ -661,6 +661,14 @@ export function computeDiagnostics(state: InspectorState): void {
|
|
|
661
661
|
const diagnostics: InspectorDiagnostic[] = []
|
|
662
662
|
|
|
663
663
|
for (const [id, meta] of Object.entries(state.functions.meta)) {
|
|
664
|
+
// Skip framework-synthesized functions: generated wrappers (auth.gen.ts's
|
|
665
|
+
// opaque authHandler, the cli channel's raw dispatcher) and synthetic route
|
|
666
|
+
// bridges that reference addon functions (id `http:<method>:<route>`, no
|
|
667
|
+
// source file). The user can't edit any of these, so a destructure lint
|
|
668
|
+
// meant to nudge them about their own code must not fail the build over them.
|
|
669
|
+
if (!meta.sourceFile || meta.sourceFile.endsWith('.gen.ts')) {
|
|
670
|
+
continue
|
|
671
|
+
}
|
|
664
672
|
if (meta.services && !meta.services.optimized) {
|
|
665
673
|
diagnostics.push({
|
|
666
674
|
code: ErrorCode.SERVICES_NOT_DESTRUCTURED,
|