@pikku/inspector 0.12.68 → 0.12.70
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 +35 -0
- package/dist/add/add-auth.js +7 -7
- package/dist/utils/filter-inspector-state.js +21 -4
- package/package.json +3 -3
- package/src/add/add-auth.test.ts +2 -2
- package/src/add/add-auth.ts +7 -7
- package/src/utils/filter-inspector-state.test.ts +53 -0
- package/src/utils/filter-inspector-state.ts +26 -4
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
## 0.12.70
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- d64db40: Prune a filtered-out workflow's file entry, not just its meta.
|
|
6
|
+
|
|
7
|
+
`filterInspectorState` deleted a pruned workflow from `workflows.graphMeta` and `workflows.meta` but left it in `workflows.files`, which is what the wiring generator iterates. Per-unit deploy codegen therefore registered every workflow in the project into every unit, and — because a scenario is told apart from an app workflow by `graphMeta[name].source === 'scenario'`, which the same prune had just removed — each scenario was reclassified as an app workflow. That pulled scenario bodies, their steps, and whatever those import into deployed bundles; on Cloudflare a step reading a fixture off disk failed the whole publish with `No such module "node:fs"`.
|
|
8
|
+
|
|
9
|
+
## 0.12.69
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 32d1280: Prefix the better-auth plugin factories with `pikku`: `pikkuActor`, `pikkuBan`,
|
|
14
|
+
`pikkuFabric`, `pikkuDelegatedAuth` and `pikkuCredentialOAuth`.
|
|
15
|
+
|
|
16
|
+
A `betterAuth({ plugins: [...] })` array mixes this package's plugins with
|
|
17
|
+
better-auth's own, and until now nothing at the call site told them apart —
|
|
18
|
+
`plugins: [actor(...), ban(), fabric(...), organization()]` reads as four
|
|
19
|
+
plugins from one place when only the last is better-auth's. The prefix says
|
|
20
|
+
which package a plugin came from where it is actually wired.
|
|
21
|
+
|
|
22
|
+
The old names are still exported as deprecated aliases bound to the same
|
|
23
|
+
functions, so no import has to change. Nothing about the plugins themselves
|
|
24
|
+
moved: the `id` each registers under — `pikku-ban`, `actor`, `fabric`,
|
|
25
|
+
`delegated-auth`, `credential-oauth` — is unchanged, so no deployed database or
|
|
26
|
+
session is affected.
|
|
27
|
+
|
|
28
|
+
The pieces that read a plugin's _export_ name rather than its id accept both:
|
|
29
|
+
`PLUGIN_REGISTRY` is keyed under the prefixed and the bare name, and the
|
|
30
|
+
`pikku validate` ban/actor checks and the `scaffold.userAdmin` ban check count
|
|
31
|
+
either spelling as wired. Their messages now point at the new names.
|
|
32
|
+
|
|
33
|
+
- Updated dependencies [a0ed1e8]
|
|
34
|
+
- @pikku/core@0.12.100
|
|
35
|
+
|
|
1
36
|
## 0.12.68
|
|
2
37
|
|
|
3
38
|
### Patch Changes
|
package/dist/add/add-auth.js
CHANGED
|
@@ -86,7 +86,7 @@ const readPluginBindings = (source) => {
|
|
|
86
86
|
};
|
|
87
87
|
/**
|
|
88
88
|
* Read a `plugins: [...]` entry. better-auth plugins are factory calls —
|
|
89
|
-
* `bearer()`, `twoFactor({ ... })`, `
|
|
89
|
+
* `bearer()`, `twoFactor({ ... })`, `pikkuBan()`, or `plugins.bearer()` through a
|
|
90
90
|
* namespace import; non-call entries are ignored. `betterAuthExport` is the
|
|
91
91
|
* name better-auth exports the plugin under, and is absent for a plugin that
|
|
92
92
|
* came from somewhere else, which no policy here applies to.
|
|
@@ -148,10 +148,10 @@ const isInsideGlobalMiddlewareRegistration = (node) => {
|
|
|
148
148
|
* every one of its endpoints underneath. Pikku dropped that projection: user
|
|
149
149
|
* management is `@pikku/addon-admin`'s scoped RPCs, and the one capability
|
|
150
150
|
* `admin()` had that nothing else did — refusing a session to a banned user —
|
|
151
|
-
* is `
|
|
151
|
+
* is `pikkuBan()`.
|
|
152
152
|
*
|
|
153
153
|
* Thrown rather than warned because the failure it prevents is silent. An app
|
|
154
|
-
* that drops `admin()` without wiring `
|
|
154
|
+
* that drops `admin()` without wiring `pikkuBan()` keeps its ban columns and its
|
|
155
155
|
* UI, and simply stops enforcing bans.
|
|
156
156
|
*/
|
|
157
157
|
const UNSUPPORTED_ADMIN_PLUGIN = (sourceFile) => `better-auth's admin() plugin is not supported by pikku (${sourceFile}).
|
|
@@ -160,12 +160,12 @@ It authorizes against a 'user.role' column, while pikku authorizes on scopes —
|
|
|
160
160
|
wiring both means one has to be projected onto the other, and the projection is
|
|
161
161
|
coarser than the scopes it stands in for.
|
|
162
162
|
|
|
163
|
-
Use
|
|
163
|
+
Use pikkuBan() instead:
|
|
164
164
|
|
|
165
|
-
import {
|
|
166
|
-
betterAuth({ plugins: [
|
|
165
|
+
import { pikkuBan } from '@pikku/better-auth'
|
|
166
|
+
betterAuth({ plugins: [pikkuBan()] })
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
pikkuBan() keeps the part of admin() that pikku cannot supply from outside
|
|
169
169
|
better-auth — the banned/banReason/banExpires columns and the session hook that
|
|
170
170
|
refuses a banned user a session. Everything else admin() offered is already
|
|
171
171
|
scoped RPCs in @pikku/addon-admin: list, create, ban, remove, revoke sessions
|
|
@@ -2,6 +2,23 @@ import { parseVersionedId } from '@pikku/core/utils';
|
|
|
2
2
|
import { makeContextBasedId } from './extract-function-name.js';
|
|
3
3
|
import { aggregateRequiredServices } from './post-process.js';
|
|
4
4
|
import { IncompatibleDeployTargetError, resolveDeployTarget, } from './resolve-deploy-target.js';
|
|
5
|
+
/**
|
|
6
|
+
* Drop a workflow from every map that describes it. `files` and `graphFiles`
|
|
7
|
+
* are what the wiring generator iterates, and `graphMeta` is what tells a
|
|
8
|
+
* scenario apart from an app workflow — leaving a pruned workflow's file entry
|
|
9
|
+
* behind registers it anyway, and a scenario whose graphMeta has gone reads as
|
|
10
|
+
* an app workflow, which is how scenario steps reached deployed bundles.
|
|
11
|
+
*/
|
|
12
|
+
const pruneWorkflow = (workflows, name, pikkuFuncId) => {
|
|
13
|
+
delete workflows.graphMeta[name];
|
|
14
|
+
delete workflows.meta[name];
|
|
15
|
+
workflows.files.delete(name);
|
|
16
|
+
workflows.graphFiles.delete(name);
|
|
17
|
+
if (pikkuFuncId) {
|
|
18
|
+
workflows.files.delete(pikkuFuncId);
|
|
19
|
+
workflows.graphFiles.delete(pikkuFuncId);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
5
22
|
// Module-level Set to track warned groups across multiple filter calls
|
|
6
23
|
const globalWarnedGroups = new Set();
|
|
7
24
|
/**
|
|
@@ -334,6 +351,8 @@ export function filterInspectorState(state, filters, logger) {
|
|
|
334
351
|
...state.workflows,
|
|
335
352
|
graphMeta: JSON.parse(JSON.stringify(state.workflows?.graphMeta ?? {})),
|
|
336
353
|
meta: JSON.parse(JSON.stringify(state.workflows?.meta ?? {})),
|
|
354
|
+
files: new Map(state.workflows?.files ?? []),
|
|
355
|
+
graphFiles: new Map(state.workflows?.graphFiles ?? []),
|
|
337
356
|
},
|
|
338
357
|
channels: {
|
|
339
358
|
...state.channels,
|
|
@@ -768,13 +787,11 @@ export function filterInspectorState(state, filters, logger) {
|
|
|
768
787
|
const pikkuFuncId = graphMeta?.pikkuFuncId ?? workflowMeta?.pikkuFuncId;
|
|
769
788
|
if (pikkuFuncId &&
|
|
770
789
|
!filteredState.serviceAggregation.usedFunctions.has(pikkuFuncId)) {
|
|
771
|
-
|
|
772
|
-
delete filteredState.workflows.meta[name];
|
|
790
|
+
pruneWorkflow(filteredState.workflows, name, pikkuFuncId);
|
|
773
791
|
}
|
|
774
792
|
else if (!pikkuFuncId) {
|
|
775
793
|
// No function ID found — prune it
|
|
776
|
-
|
|
777
|
-
delete filteredState.workflows.meta[name];
|
|
794
|
+
pruneWorkflow(filteredState.workflows, name, pikkuFuncId);
|
|
778
795
|
}
|
|
779
796
|
}
|
|
780
797
|
// Prune RPC meta to only include entries whose target function survived
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.70",
|
|
4
4
|
"description": "TypeScript inspector for Pikku — discovers functions and wirings to drive code generation",
|
|
5
5
|
"author": "yasser.fadl@gmail.com",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"zod-to-ts": "^2.1.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@pikku/core": "^0.12.
|
|
48
|
+
"@pikku/core": "^0.12.100"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@pikku/core": "^0.12.
|
|
51
|
+
"@pikku/core": "^0.12.100",
|
|
52
52
|
"@types/node": "^24.13.3"
|
|
53
53
|
},
|
|
54
54
|
"engines": {
|
package/src/add/add-auth.test.ts
CHANGED
|
@@ -217,7 +217,7 @@ describe('addAuth inspector', () => {
|
|
|
217
217
|
}
|
|
218
218
|
})
|
|
219
219
|
|
|
220
|
-
test('refuses better-auth admin() and points at
|
|
220
|
+
test('refuses better-auth admin() and points at pikkuBan()', async () => {
|
|
221
221
|
const rootDir = await mkdtemp(join(tmpdir(), 'pikku-add-auth-admin-'))
|
|
222
222
|
const file = join(rootDir, 'auth.ts')
|
|
223
223
|
|
|
@@ -241,7 +241,7 @@ describe('addAuth inspector', () => {
|
|
|
241
241
|
() => inspect(makeLogger(criticals), [file], { rootDir }),
|
|
242
242
|
(error: Error) => {
|
|
243
243
|
assert.match(error.message, /admin\(\) plugin is not supported/)
|
|
244
|
-
assert.match(error.message, /
|
|
244
|
+
assert.match(error.message, /pikkuBan\(\)/)
|
|
245
245
|
assert.match(error.message, /@pikku\/addon-admin/)
|
|
246
246
|
return true
|
|
247
247
|
}
|
package/src/add/add-auth.ts
CHANGED
|
@@ -128,7 +128,7 @@ const readPluginBindings = (source: ts.SourceFile): PluginBindings => {
|
|
|
128
128
|
|
|
129
129
|
/**
|
|
130
130
|
* Read a `plugins: [...]` entry. better-auth plugins are factory calls —
|
|
131
|
-
* `bearer()`, `twoFactor({ ... })`, `
|
|
131
|
+
* `bearer()`, `twoFactor({ ... })`, `pikkuBan()`, or `plugins.bearer()` through a
|
|
132
132
|
* namespace import; non-call entries are ignored. `betterAuthExport` is the
|
|
133
133
|
* name better-auth exports the plugin under, and is absent for a plugin that
|
|
134
134
|
* came from somewhere else, which no policy here applies to.
|
|
@@ -194,10 +194,10 @@ const isInsideGlobalMiddlewareRegistration = (node: ts.Node): boolean => {
|
|
|
194
194
|
* every one of its endpoints underneath. Pikku dropped that projection: user
|
|
195
195
|
* management is `@pikku/addon-admin`'s scoped RPCs, and the one capability
|
|
196
196
|
* `admin()` had that nothing else did — refusing a session to a banned user —
|
|
197
|
-
* is `
|
|
197
|
+
* is `pikkuBan()`.
|
|
198
198
|
*
|
|
199
199
|
* Thrown rather than warned because the failure it prevents is silent. An app
|
|
200
|
-
* that drops `admin()` without wiring `
|
|
200
|
+
* that drops `admin()` without wiring `pikkuBan()` keeps its ban columns and its
|
|
201
201
|
* UI, and simply stops enforcing bans.
|
|
202
202
|
*/
|
|
203
203
|
const UNSUPPORTED_ADMIN_PLUGIN = (sourceFile: string): string =>
|
|
@@ -207,12 +207,12 @@ It authorizes against a 'user.role' column, while pikku authorizes on scopes —
|
|
|
207
207
|
wiring both means one has to be projected onto the other, and the projection is
|
|
208
208
|
coarser than the scopes it stands in for.
|
|
209
209
|
|
|
210
|
-
Use
|
|
210
|
+
Use pikkuBan() instead:
|
|
211
211
|
|
|
212
|
-
import {
|
|
213
|
-
betterAuth({ plugins: [
|
|
212
|
+
import { pikkuBan } from '@pikku/better-auth'
|
|
213
|
+
betterAuth({ plugins: [pikkuBan()] })
|
|
214
214
|
|
|
215
|
-
|
|
215
|
+
pikkuBan() keeps the part of admin() that pikku cannot supply from outside
|
|
216
216
|
better-auth — the banned/banReason/banExpires columns and the session hook that
|
|
217
217
|
refuses a banned user a session. Everything else admin() offered is already
|
|
218
218
|
scoped RPCs in @pikku/addon-admin: list, create, ban, remove, revoke sessions
|
|
@@ -2010,3 +2010,56 @@ describe('invokedFunctionsByFile serialization', () => {
|
|
|
2010
2010
|
assert.strictEqual(restored.rpc.invokedFunctionsByFile.size, 0)
|
|
2011
2011
|
})
|
|
2012
2012
|
})
|
|
2013
|
+
|
|
2014
|
+
describe('Workflow file pruning', () => {
|
|
2015
|
+
const workflowState = () => {
|
|
2016
|
+
const state = createMockInspectorState()
|
|
2017
|
+
state.workflows.meta = {
|
|
2018
|
+
moveOut: { pikkuFuncId: 'getUsers' } as any,
|
|
2019
|
+
theMoveOutScenario: { pikkuFuncId: 'createUser' } as any,
|
|
2020
|
+
}
|
|
2021
|
+
state.workflows.graphMeta = {
|
|
2022
|
+
moveOut: { pikkuFuncId: 'getUsers' } as any,
|
|
2023
|
+
theMoveOutScenario: {
|
|
2024
|
+
pikkuFuncId: 'createUser',
|
|
2025
|
+
source: 'scenario',
|
|
2026
|
+
} as any,
|
|
2027
|
+
}
|
|
2028
|
+
state.workflows.files = new Map([
|
|
2029
|
+
[
|
|
2030
|
+
'moveOut',
|
|
2031
|
+
{
|
|
2032
|
+
path: '/test/project/src/wirings/move-out.workflow.ts',
|
|
2033
|
+
exportedName: 'moveOut',
|
|
2034
|
+
},
|
|
2035
|
+
],
|
|
2036
|
+
[
|
|
2037
|
+
'theMoveOutScenario',
|
|
2038
|
+
{
|
|
2039
|
+
path: '/test/project/test/scenarios/the-move-out.scenario.ts',
|
|
2040
|
+
exportedName: 'theMoveOutScenario',
|
|
2041
|
+
},
|
|
2042
|
+
],
|
|
2043
|
+
])
|
|
2044
|
+
return state
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
test('drops the file entry of a pruned workflow', () => {
|
|
2048
|
+
const result = filterInspectorState(
|
|
2049
|
+
workflowState(),
|
|
2050
|
+
{ names: ['getUsers'] },
|
|
2051
|
+
mockLogger
|
|
2052
|
+
)
|
|
2053
|
+
|
|
2054
|
+
assert.deepEqual(Object.keys(result.workflows.graphMeta), ['moveOut'])
|
|
2055
|
+
assert.deepEqual([...result.workflows.files.keys()], ['moveOut'])
|
|
2056
|
+
})
|
|
2057
|
+
|
|
2058
|
+
test('leaves the original state untouched', () => {
|
|
2059
|
+
const state = workflowState()
|
|
2060
|
+
filterInspectorState(state, { names: ['getUsers'] }, mockLogger)
|
|
2061
|
+
|
|
2062
|
+
assert.equal(state.workflows.files.size, 2)
|
|
2063
|
+
assert.equal(Object.keys(state.workflows.graphMeta).length, 2)
|
|
2064
|
+
})
|
|
2065
|
+
})
|
|
@@ -21,6 +21,28 @@ type DeployFilter = {
|
|
|
21
21
|
has(pikkuFuncId: string): boolean
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Drop a workflow from every map that describes it. `files` and `graphFiles`
|
|
26
|
+
* are what the wiring generator iterates, and `graphMeta` is what tells a
|
|
27
|
+
* scenario apart from an app workflow — leaving a pruned workflow's file entry
|
|
28
|
+
* behind registers it anyway, and a scenario whose graphMeta has gone reads as
|
|
29
|
+
* an app workflow, which is how scenario steps reached deployed bundles.
|
|
30
|
+
*/
|
|
31
|
+
const pruneWorkflow = (
|
|
32
|
+
workflows: InspectorState['workflows'],
|
|
33
|
+
name: string,
|
|
34
|
+
pikkuFuncId: string | undefined
|
|
35
|
+
) => {
|
|
36
|
+
delete workflows.graphMeta[name]
|
|
37
|
+
delete workflows.meta[name]
|
|
38
|
+
workflows.files.delete(name)
|
|
39
|
+
workflows.graphFiles.delete(name)
|
|
40
|
+
if (pikkuFuncId) {
|
|
41
|
+
workflows.files.delete(pikkuFuncId)
|
|
42
|
+
workflows.graphFiles.delete(pikkuFuncId)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
// Module-level Set to track warned groups across multiple filter calls
|
|
25
47
|
const globalWarnedGroups = new Set<string>()
|
|
26
48
|
|
|
@@ -449,6 +471,8 @@ export function filterInspectorState(
|
|
|
449
471
|
...state.workflows,
|
|
450
472
|
graphMeta: JSON.parse(JSON.stringify(state.workflows?.graphMeta ?? {})),
|
|
451
473
|
meta: JSON.parse(JSON.stringify(state.workflows?.meta ?? {})),
|
|
474
|
+
files: new Map(state.workflows?.files ?? []),
|
|
475
|
+
graphFiles: new Map(state.workflows?.graphFiles ?? []),
|
|
452
476
|
},
|
|
453
477
|
channels: {
|
|
454
478
|
...state.channels,
|
|
@@ -1098,12 +1122,10 @@ export function filterInspectorState(
|
|
|
1098
1122
|
pikkuFuncId &&
|
|
1099
1123
|
!filteredState.serviceAggregation.usedFunctions.has(pikkuFuncId)
|
|
1100
1124
|
) {
|
|
1101
|
-
|
|
1102
|
-
delete filteredState.workflows.meta[name]
|
|
1125
|
+
pruneWorkflow(filteredState.workflows, name, pikkuFuncId)
|
|
1103
1126
|
} else if (!pikkuFuncId) {
|
|
1104
1127
|
// No function ID found — prune it
|
|
1105
|
-
|
|
1106
|
-
delete filteredState.workflows.meta[name]
|
|
1128
|
+
pruneWorkflow(filteredState.workflows, name, pikkuFuncId)
|
|
1107
1129
|
}
|
|
1108
1130
|
}
|
|
1109
1131
|
|