@pikku/cli 0.12.93 → 0.12.96
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/console-app/assets/{index-CmAplHjZ.js → index-CeQodYfg.js} +149 -149
- package/console-app/assets/{index-BYj7ZbUU.css → index-CyYHTGWZ.css} +1 -1
- package/console-app/index.html +2 -2
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.d.ts +13 -15
- package/dist/.pikku/cli/pikku-cli-channel.js +62 -3
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +14 -4
- package/dist/.pikku/cli/pikku-cli-client.gen.js +20 -10
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +129 -2
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +55 -20
- package/dist/.pikku/function/pikku-function-types.gen.js +27 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +138 -13
- package/dist/.pikku/function/pikku-functions.gen.js +11 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +7 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +13 -3
- package/dist/.pikku/schemas/schemas/PersonaRunInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PersonaSyncInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuPersonasInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuRolesInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/RolesAuditInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/RolesPruneInput.schema.json +1 -0
- package/dist/.pikku/scopes/pikku-personas-meta.gen.json +1 -0
- package/dist/.pikku/scopes/pikku-personas.gen.d.ts +36 -0
- package/dist/.pikku/scopes/pikku-personas.gen.js +17 -0
- package/dist/.pikku/scopes/pikku-roles-meta.gen.json +1 -0
- package/dist/.pikku/scopes/pikku-roles.gen.d.ts +30 -0
- package/dist/.pikku/scopes/pikku-roles.gen.js +18 -0
- package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +4 -2
- package/dist/.pikku/scopes/pikku-scope-types.gen.js +3 -2
- package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +2 -2
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +2 -2
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +2 -2
- package/dist/.pikku/variables/pikku-variable-types.gen.js +2 -2
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/meta/allWorkflow.gen.json +27 -3
- package/dist/.pikku/workflow/pikku-personas.gen.d.ts +15 -0
- package/dist/.pikku/workflow/pikku-personas.gen.js +17 -0
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +96 -19
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +22 -2
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/bin/pikku.js +0 -0
- package/dist/src/cli.wiring.js +101 -2
- package/dist/src/deploy/analyzer/analyzer.js +14 -0
- package/dist/src/deploy/analyzer/manifest.d.ts +11 -0
- package/dist/src/fabric/functions/validate.function.js +4 -4
- package/dist/src/functions/commands/bootstrap.js +3 -0
- package/dist/src/functions/commands/dev-ai-runner.d.ts +16 -4
- package/dist/src/functions/commands/dev-ai-runner.js +63 -29
- package/dist/src/functions/commands/dev.js +9 -4
- package/dist/src/functions/commands/enable.js +15 -19
- package/dist/src/functions/commands/{scenario-environment.d.ts → environment.d.ts} +9 -6
- package/dist/src/functions/commands/{scenario-environment.js → environment.js} +5 -4
- package/dist/src/functions/commands/new-addon.js +12 -12
- package/dist/src/functions/commands/persona-sync.d.ts +33 -0
- package/dist/src/functions/commands/persona-sync.js +151 -0
- package/dist/src/functions/commands/persona.d.ts +58 -0
- package/dist/src/functions/commands/persona.js +217 -0
- package/dist/src/functions/commands/roles-audit.d.ts +1 -0
- package/dist/src/functions/commands/roles-audit.js +37 -0
- package/dist/src/functions/commands/roles-prune.d.ts +16 -0
- package/dist/src/functions/commands/roles-prune.js +52 -0
- package/dist/src/functions/commands/roles-shared.d.ts +40 -0
- package/dist/src/functions/commands/roles-shared.js +77 -0
- package/dist/src/functions/commands/scenario-browser.d.ts +3 -3
- package/dist/src/functions/commands/scenario-browser.js +1 -1
- package/dist/src/functions/commands/scenario-ladder.d.ts +44 -2
- package/dist/src/functions/commands/scenario-ladder.js +51 -2
- package/dist/src/functions/commands/scenario.d.ts +7 -0
- package/dist/src/functions/commands/scenario.js +79 -17
- package/dist/src/functions/commands/scopes-shared.d.ts +8 -0
- package/dist/src/functions/commands/scopes-shared.js +1 -1
- package/dist/src/functions/commands/serve.js +7 -3
- package/dist/src/functions/commands/virtual-user-formatter.d.ts +30 -0
- package/dist/src/functions/commands/virtual-user-formatter.js +65 -0
- package/dist/src/functions/db/local-db.js +38 -1
- package/dist/src/functions/validate/workspace-validate.js +1 -1
- package/dist/src/functions/wirings/ai-agent/pikku-command-public-agent.js +2 -1
- package/dist/src/functions/wirings/ai-agent/serialize-public-agent.js +1 -0
- package/dist/src/functions/wirings/auth/serialize-auth-gen.d.ts +2 -2
- package/dist/src/functions/wirings/auth/serialize-auth-gen.js +8 -8
- package/dist/src/functions/wirings/cli/serialize-channel-cli-client.d.ts +7 -3
- package/dist/src/functions/wirings/cli/serialize-channel-cli-client.js +32 -18
- package/dist/src/functions/wirings/cli/serialize-channel-cli.js +63 -6
- package/dist/src/functions/wirings/console/serialize-console-functions.js +4 -7
- package/dist/src/functions/wirings/functions/serialize-function-types.js +88 -28
- package/dist/src/functions/wirings/middleware/serialize-middleware-imports.js +25 -9
- package/dist/src/functions/wirings/package/serialize-package-types.js +5 -3
- package/dist/src/functions/wirings/personas/pikku-command-personas.d.ts +7 -0
- package/dist/src/functions/wirings/personas/pikku-command-personas.js +43 -0
- package/dist/src/functions/wirings/personas/serialize-personas-types.d.ts +18 -0
- package/dist/src/functions/wirings/personas/serialize-personas-types.js +76 -0
- package/dist/src/functions/wirings/realtime/pikku-command-events-scaffold.js +2 -1
- package/dist/src/functions/wirings/roles/pikku-command-roles.d.ts +7 -0
- package/dist/src/functions/wirings/roles/pikku-command-roles.js +33 -0
- package/dist/src/functions/wirings/roles/serialize-roles-types.d.ts +14 -0
- package/dist/src/functions/wirings/roles/serialize-roles-types.js +55 -0
- package/dist/src/functions/wirings/rpc/pikku-command-public-rpc.js +2 -1
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +3 -3
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +3 -3
- package/dist/src/functions/wirings/scopes/serialize-scopes-types.d.ts +1 -1
- package/dist/src/functions/wirings/scopes/serialize-scopes-types.js +1 -1
- package/dist/src/functions/wirings/user-admin/pikku-command-user-admin-functions.js +2 -1
- package/dist/src/functions/wirings/user-admin/serialize-user-admin-functions.js +2 -2
- package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.js +2 -1
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +13 -13
- package/dist/src/functions/wirings/workflow/serialize-personas.d.ts +10 -0
- package/dist/src/functions/wirings/workflow/serialize-personas.js +46 -0
- package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.js +11 -2
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +165 -29
- package/dist/src/functions/workflows/all.workflow.js +7 -1
- package/dist/src/server/content-signing-jwt.d.ts +13 -0
- package/dist/src/server/content-signing-jwt.js +51 -0
- package/dist/src/server/dev-server-runner.interface.d.ts +10 -2
- package/dist/src/server/node-server-runner.d.ts +2 -2
- package/dist/src/server/node-server-runner.js +2 -1
- package/dist/src/services.d.ts +3 -1
- package/dist/src/services.js +2 -1
- package/dist/src/utils/pikku-cli-config.js +45 -2
- package/dist/src/utils/resolve-personas.d.ts +32 -0
- package/dist/src/utils/resolve-personas.js +46 -0
- package/dist/src/utils/resolve-scaffold-feature.d.ts +19 -0
- package/dist/src/utils/resolve-scaffold-feature.js +49 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -14
- package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +0 -1
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +0 -19
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +0 -17
- package/dist/src/functions/wirings/workflow/serialize-scenario-actors.d.ts +0 -2
- package/dist/src/functions/wirings/workflow/serialize-scenario-actors.js +0 -40
- package/dist/src/utils/resolve-scenario-actors.d.ts +0 -23
- package/dist/src/utils/resolve-scenario-actors.js +0 -74
|
@@ -60,7 +60,7 @@ export function serializeChannelCLI(programName, programMeta, channelFile, funct
|
|
|
60
60
|
import { wireChannel } from '${channelTypesPath}'
|
|
61
61
|
import { pikkuMiddleware${hasAddonFuncs ? ', ref' : ''}, pikkuSessionlessFunc } from '${functionTypesPath}'
|
|
62
62
|
import { generateCommandHelp } from '@pikku/core/cli'
|
|
63
|
-
import { handleRawCLI } from '@pikku/core/cli/channel'
|
|
63
|
+
import { handleRawCLI, type RawCLIFrame } from '@pikku/core/cli/channel'
|
|
64
64
|
import { pikkuState } from '@pikku/core/internal'
|
|
65
65
|
${imports}
|
|
66
66
|
|
|
@@ -97,22 +97,79 @@ export const cliHelp = pikkuSessionlessFunc<{ args?: string[] }, { help: string
|
|
|
97
97
|
},
|
|
98
98
|
})
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Raw entry point: the client forwards argv untouched and this side owns
|
|
102
|
+
* parsing, so a client binary never carries the command tree and its version
|
|
103
|
+
* is free to drift from the server's.
|
|
104
|
+
*
|
|
105
|
+
* Progressive output is streamed on the same channel rather than returned,
|
|
106
|
+
* and the terminating control frame carries the exit code so the client
|
|
107
|
+
* process can exit non-zero.
|
|
108
|
+
*/
|
|
109
|
+
export const cliRaw = pikkuSessionlessFunc<{ args: string[] }, RawCLIFrame>({
|
|
101
110
|
auth: false,
|
|
102
|
-
func: async (services, data: { args: string[] }) => {
|
|
103
|
-
|
|
111
|
+
func: async (services, data: { args: string[] }, { channel, session }) => {
|
|
112
|
+
const { help, result, error, exitCode, commandId } = await handleRawCLI({
|
|
104
113
|
programName: '${programName}',
|
|
105
114
|
args: data.args,
|
|
106
115
|
singletonServices: services as any,
|
|
116
|
+
createWireServices: pikkuState(null, 'package', 'factories')?.createWireServices,
|
|
117
|
+
// The connection authenticated during its upgrade — commands run as it.
|
|
118
|
+
session,
|
|
119
|
+
// The socket the command arrived on, so \`channel.remote(...)\` inside a
|
|
120
|
+
// command reaches the client that invoked it.
|
|
121
|
+
transport: channel,
|
|
122
|
+
onOutput: (output, commandId) =>
|
|
123
|
+
channel?.send({ action: 'cli-output', commandId, data: output }),
|
|
107
124
|
})
|
|
125
|
+
|
|
126
|
+
// A failed parse carries both: the error says what was wrong, the help
|
|
127
|
+
// says what was available. The error goes last so it is the line still on
|
|
128
|
+
// screen after the help text has scrolled past.
|
|
129
|
+
if (help !== undefined) {
|
|
130
|
+
await channel?.send({ action: 'cli-help', help })
|
|
131
|
+
if (error !== undefined) {
|
|
132
|
+
await channel?.send({ action: 'cli-error', error })
|
|
133
|
+
}
|
|
134
|
+
} else if (error !== undefined) {
|
|
135
|
+
await channel?.send({ action: 'cli-error', error })
|
|
136
|
+
} else if (result !== undefined) {
|
|
137
|
+
await channel?.send({ action: 'cli-result', commandId, result })
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Returned rather than sent so the runtime tags it with the routing key,
|
|
141
|
+
// and so the terminal frame cannot be emitted before the ones above it.
|
|
142
|
+
return { action: 'cli-control', event: 'complete', exitCode }
|
|
108
143
|
},
|
|
109
144
|
})
|
|
110
145
|
|
|
146
|
+
${programMeta.auth === true
|
|
147
|
+
? `/**
|
|
148
|
+
* Refuses a connection that arrives without a session.
|
|
149
|
+
*
|
|
150
|
+
* A CLI authenticates once, when it connects — there is no later message that
|
|
151
|
+
* would establish a session, so a connection that starts anonymous can never
|
|
152
|
+
* run anything. Saying so immediately and hanging up gives the caller a
|
|
153
|
+
* non-zero exit instead of a socket that silently refuses every command.
|
|
154
|
+
*/
|
|
155
|
+
export const cliRequireSession = pikkuSessionlessFunc<void, RawCLIFrame | void>({
|
|
156
|
+
auth: false,
|
|
157
|
+
func: async (_services, _data, { channel, session }) => {
|
|
158
|
+
if (session) {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
await channel?.send({ action: 'cli-error', error: 'Authentication required' })
|
|
162
|
+
await channel?.send({ action: 'cli-control', event: 'complete', exitCode: 1 })
|
|
163
|
+
await channel?.close()
|
|
164
|
+
},
|
|
165
|
+
})
|
|
166
|
+
`
|
|
167
|
+
: ''}
|
|
111
168
|
wireChannel({
|
|
112
169
|
name: '${finalChannelName}',
|
|
113
170
|
route: '${finalChannelRoute}',
|
|
114
|
-
auth:
|
|
115
|
-
onMessageWiring: {
|
|
171
|
+
auth: ${programMeta.auth === true},
|
|
172
|
+
${programMeta.auth === true ? ' onConnect: cliRequireSession,\n' : ''} onMessageWiring: {
|
|
116
173
|
command: {
|
|
117
174
|
'__help': {
|
|
118
175
|
func: cliHelp,
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
} from './console.schemas.gen.js'
|
|
41
41
|
|
|
42
42
|
export const pikkuConsoleSetSecret = pikkuFunc({
|
|
43
|
+
secretBroker: true,
|
|
43
44
|
tags: ['pikku'],
|
|
44
45
|
description: 'Set the value of a secret',
|
|
45
46
|
expose: true,
|
|
@@ -89,6 +90,7 @@ export const pikkuConsoleSetVariable = pikkuFunc({
|
|
|
89
90
|
})
|
|
90
91
|
|
|
91
92
|
export const pikkuConsoleHasSecret = pikkuFunc({
|
|
93
|
+
secretBroker: true,
|
|
92
94
|
tags: ['pikku'],
|
|
93
95
|
description: 'Check if a secret exists without reading its value',
|
|
94
96
|
expose: true,
|
|
@@ -101,6 +103,7 @@ export const pikkuConsoleHasSecret = pikkuFunc({
|
|
|
101
103
|
})
|
|
102
104
|
|
|
103
105
|
export const pikkuConsoleGetSecret = pikkuFunc({
|
|
106
|
+
secretBroker: true,
|
|
104
107
|
tags: ['pikku'],
|
|
105
108
|
description: 'Get the current value of a secret',
|
|
106
109
|
expose: true,
|
|
@@ -129,13 +132,7 @@ export const consoleRoutes = defineHTTPRoutes({
|
|
|
129
132
|
},
|
|
130
133
|
})
|
|
131
134
|
|
|
132
|
-
|
|
133
|
-
// gates the whole privileged surface (credential read/write, source editing,
|
|
134
|
-
// package install) with a single package-scoped global permission —
|
|
135
|
-
// addGlobalPermission([isAdmin], '@pikku/addon-console') — which is resolved in
|
|
136
|
-
// the addon's package namespace, so it applies to every one of its functions at
|
|
137
|
-
// once. Apps that don't register one are unaffected (no globals => allow).
|
|
138
|
-
wireAddon({ name: 'console', package: '@pikku/addon-console' })
|
|
135
|
+
wireAddon({ name: 'console', package: '@pikku/addon-console', scopes: ['admin'] })
|
|
139
136
|
wireHTTPRoutes({ basePath: '${globalHTTPPrefix}', routes: { console: consoleRoutes } })
|
|
140
137
|
`;
|
|
141
138
|
return { schemas, functions };
|
|
@@ -7,7 +7,7 @@ export const serializeFunctionTypes = (userSessionTypeImport, userSessionTypeNam
|
|
|
7
7
|
? nodeCategories.map((c) => `'${c}'`).join(' | ')
|
|
8
8
|
: 'string';
|
|
9
9
|
const workflowImport = workflowTypesImport ||
|
|
10
|
-
`import type { TypedWorkflow, TypedScenario,
|
|
10
|
+
`import type { TypedWorkflow, TypedScenario, TypedPersonas } from '../workflow/pikku-workflow-types.gen.js'`;
|
|
11
11
|
// Falls back to `string` when a project has no scopes codegen, so that
|
|
12
12
|
// `scopes` stays usable rather than resolving to an unbound type name.
|
|
13
13
|
const scopesImport = scopesTypeImport || `type ScopeId = string`;
|
|
@@ -15,7 +15,7 @@ export const serializeFunctionTypes = (userSessionTypeImport, userSessionTypeNam
|
|
|
15
15
|
* Core function, middleware, and permission types for all wirings
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type { CorePikkuMiddleware, CorePermissionGroup, ListInput, ListOutput, PikkuWire, PickRequired } from '@pikku/core'
|
|
18
|
+
import type { CorePikkuMiddleware, CorePermissionGroup, ListInput, ListOutput, PikkuWire, PickRequired, SecretlessServices, SecretService } from '@pikku/core'
|
|
19
19
|
import type { CorePikkuFunctionConfig, CorePikkuAuth, CorePikkuAuthConfig, CorePikkuPermission } from '@pikku/core/function'
|
|
20
20
|
import { pikkuAuth as pikkuAuthCore } from '@pikku/core/function'
|
|
21
21
|
import {
|
|
@@ -51,7 +51,20 @@ ${configTypeImport.includes('Config type not found') ? 'export type Config = any
|
|
|
51
51
|
* why an \`if (!service)\` guard inside a function body is always dead code.
|
|
52
52
|
*/
|
|
53
53
|
export type WiredSingletonServices = RequiredSingletonServices & SingletonServices
|
|
54
|
-
export type WiredServices = RequiredSingletonServices & Services
|
|
54
|
+
export type WiredServices = SecretlessServices<RequiredSingletonServices & Services>
|
|
55
|
+
|
|
56
|
+
/** \`WiredSingletonServices\` without \`secrets\`, for auth gates. */
|
|
57
|
+
export type WiredAuthServices = SecretlessServices<WiredSingletonServices>
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* \`WiredServices\` with \`secrets\` restored, for the console's secret-admin
|
|
61
|
+
* functions. Reached by declaring \`secretBroker: true\` on a \`pikkuFunc\` config.
|
|
62
|
+
*
|
|
63
|
+
* Declaring it does not grant the service. The runner hands out the real
|
|
64
|
+
* \`SecretService\` only to the functions the inspector marks as secret brokers;
|
|
65
|
+
* every other function still receives the throwing accessor.
|
|
66
|
+
*/
|
|
67
|
+
export type WiredSecretBrokerServices = WiredServices & { secrets: SecretService }
|
|
55
68
|
|
|
56
69
|
/**
|
|
57
70
|
* Inline node configuration for function definitions.
|
|
@@ -70,7 +83,7 @@ export type NodeConfig = {
|
|
|
70
83
|
* @template In - The input type that the permission check will receive
|
|
71
84
|
* @template RequiredServices - The services required for this permission check
|
|
72
85
|
*/
|
|
73
|
-
export type PikkuPermission<In = unknown, RequiredServices extends Services = WiredServices> = CorePikkuPermission<In, RequiredServices, PikkuWire<In, never, false, Session>>
|
|
86
|
+
export type PikkuPermission<In = unknown, RequiredServices extends SecretlessServices<Services> = WiredServices> = CorePikkuPermission<In, RequiredServices, PikkuWire<In, never, false, Session>>
|
|
74
87
|
|
|
75
88
|
/**
|
|
76
89
|
* Type-safe middleware definition that can access your application's services and session.
|
|
@@ -83,7 +96,7 @@ export type PikkuMiddleware<RequiredServices extends SingletonServices = WiredSi
|
|
|
83
96
|
/**
|
|
84
97
|
* Configuration object for creating a permission with metadata
|
|
85
98
|
*/
|
|
86
|
-
export type PikkuPermissionConfig<In = unknown, RequiredServices extends Services = WiredServices> = {
|
|
99
|
+
export type PikkuPermissionConfig<In = unknown, RequiredServices extends SecretlessServices<Services> = WiredServices> = {
|
|
87
100
|
/** The permission function */
|
|
88
101
|
func: PikkuPermission<In, RequiredServices>
|
|
89
102
|
/** Optional human-readable name for the permission */
|
|
@@ -128,12 +141,12 @@ export const pikkuPermission = <In>(
|
|
|
128
141
|
*
|
|
129
142
|
* @template RequiredServices - The services required for this auth check
|
|
130
143
|
*/
|
|
131
|
-
export type PikkuAuth<RequiredServices extends SingletonServices =
|
|
144
|
+
export type PikkuAuth<RequiredServices extends SecretlessServices<SingletonServices> = WiredAuthServices> = CorePikkuAuth<RequiredServices, Session>
|
|
132
145
|
|
|
133
146
|
/**
|
|
134
147
|
* Configuration object for creating an auth permission with metadata
|
|
135
148
|
*/
|
|
136
|
-
export type PikkuAuthConfig<RequiredServices extends SingletonServices =
|
|
149
|
+
export type PikkuAuthConfig<RequiredServices extends SecretlessServices<SingletonServices> = WiredAuthServices> = CorePikkuAuthConfig<RequiredServices, Session>
|
|
137
150
|
|
|
138
151
|
/**
|
|
139
152
|
* Factory function for creating auth-only permissions with tree-shaking support.
|
|
@@ -155,7 +168,7 @@ export type PikkuAuthConfig<RequiredServices extends SingletonServices = WiredSi
|
|
|
155
168
|
* })
|
|
156
169
|
* \\\`\\\`\\\`
|
|
157
170
|
*/
|
|
158
|
-
export const pikkuAuth = <RequiredServices extends SingletonServices =
|
|
171
|
+
export const pikkuAuth = <RequiredServices extends SecretlessServices<SingletonServices> = WiredAuthServices>(
|
|
159
172
|
auth: PikkuAuth<RequiredServices> | PikkuAuthConfig<RequiredServices>
|
|
160
173
|
): PikkuPermission<any, any> => {
|
|
161
174
|
return pikkuAuthCore(auth as any) as any
|
|
@@ -257,7 +270,7 @@ export const pikkuPermissionFactory = <In = any>(
|
|
|
257
270
|
* @template In - The input type (same as the function it describes)
|
|
258
271
|
* @template RequiredServices - The services required for this description function
|
|
259
272
|
*/
|
|
260
|
-
export type PikkuApprovalDescription<In = unknown, RequiredServices extends Services = WiredServices> = (
|
|
273
|
+
export type PikkuApprovalDescription<In = unknown, RequiredServices extends SecretlessServices<Services> = WiredServices> = (
|
|
261
274
|
services: RequiredServices,
|
|
262
275
|
data: In
|
|
263
276
|
) => Promise<string>
|
|
@@ -275,7 +288,7 @@ export type PikkuApprovalDescription<In = unknown, RequiredServices extends Serv
|
|
|
275
288
|
* )
|
|
276
289
|
* \`\`\`
|
|
277
290
|
*/
|
|
278
|
-
export const pikkuApprovalDescription = <In = unknown, RequiredServices extends Services = WiredServices>(
|
|
291
|
+
export const pikkuApprovalDescription = <In = unknown, RequiredServices extends SecretlessServices<Services> = WiredServices>(
|
|
279
292
|
fn: PikkuApprovalDescription<In, RequiredServices>
|
|
280
293
|
): PikkuApprovalDescription<In, RequiredServices> => {
|
|
281
294
|
return fn
|
|
@@ -293,13 +306,13 @@ export type PikkuFunctionSessionless<
|
|
|
293
306
|
In = unknown,
|
|
294
307
|
Out = never,
|
|
295
308
|
RequiredWires extends keyof PikkuWire = never,
|
|
296
|
-
RequiredServices extends Services = WiredServices
|
|
309
|
+
RequiredServices extends SecretlessServices<Services> = WiredServices
|
|
297
310
|
> = CorePikkuFunctionSessionless<
|
|
298
311
|
In,
|
|
299
312
|
Out,
|
|
300
313
|
RequiredServices,
|
|
301
314
|
Session,
|
|
302
|
-
PickRequired<PikkuWire<In, Out, false, Session, TypedPikkuRPC, null, any, TypedWorkflow, unknown, TypedScenario,
|
|
315
|
+
PickRequired<PikkuWire<In, Out, false, Session, TypedPikkuRPC, null, any, TypedWorkflow, unknown, TypedScenario, TypedPersonas>, RequiredWires>
|
|
303
316
|
>
|
|
304
317
|
|
|
305
318
|
/**
|
|
@@ -314,13 +327,13 @@ export type PikkuFunction<
|
|
|
314
327
|
In = unknown,
|
|
315
328
|
Out = never,
|
|
316
329
|
RequiredWires extends keyof PikkuWire = 'session',
|
|
317
|
-
RequiredServices extends Services = WiredServices
|
|
330
|
+
RequiredServices extends SecretlessServices<Services> = WiredServices
|
|
318
331
|
> = CorePikkuFunction<
|
|
319
332
|
In,
|
|
320
333
|
Out,
|
|
321
334
|
RequiredServices,
|
|
322
335
|
Session,
|
|
323
|
-
PickRequired<PikkuWire<In, Out, true, Session, TypedPikkuRPC, null, any, TypedWorkflow, unknown, TypedScenario,
|
|
336
|
+
PickRequired<PikkuWire<In, Out, true, Session, TypedPikkuRPC, null, any, TypedWorkflow, unknown, TypedScenario, TypedPersonas>, RequiredWires>
|
|
324
337
|
>
|
|
325
338
|
|
|
326
339
|
/**
|
|
@@ -340,7 +353,7 @@ export type PikkuFunctionConfig<
|
|
|
340
353
|
In = unknown,
|
|
341
354
|
Out = unknown,
|
|
342
355
|
RequiredWires extends keyof PikkuWire = never,
|
|
343
|
-
PikkuFunc extends PikkuFunction<In, Out, RequiredWires> | PikkuFunctionSessionless<In, Out, RequiredWires> = PikkuFunction<In, Out, RequiredWires> | PikkuFunctionSessionless<In, Out, RequiredWires>,
|
|
356
|
+
PikkuFunc extends PikkuFunction<In, Out, RequiredWires, any> | PikkuFunctionSessionless<In, Out, RequiredWires, any> = PikkuFunction<In, Out, RequiredWires> | PikkuFunctionSessionless<In, Out, RequiredWires>,
|
|
344
357
|
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
345
358
|
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
346
359
|
> = CorePikkuFunctionConfig<PikkuFunc, PikkuPermission<In>, PikkuMiddleware, InputSchema, OutputSchema, ScopeId>
|
|
@@ -361,11 +374,12 @@ type SchemaInferred<S, Fallback = unknown> = S extends StandardSchemaV1
|
|
|
361
374
|
export type PikkuFunctionConfigWithSchema<
|
|
362
375
|
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
363
376
|
OutputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
364
|
-
RequiredWires extends keyof PikkuWire = never
|
|
377
|
+
RequiredWires extends keyof PikkuWire = never,
|
|
378
|
+
RequiredServices extends SecretlessServices<Services> = WiredServices
|
|
365
379
|
> = Omit<
|
|
366
380
|
CorePikkuFunctionConfig<
|
|
367
|
-
| PikkuFunction<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires>
|
|
368
|
-
| PikkuFunctionSessionless<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires>,
|
|
381
|
+
| PikkuFunction<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires, RequiredServices>
|
|
382
|
+
| PikkuFunctionSessionless<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires, RequiredServices>,
|
|
369
383
|
CorePikkuPermission<any>,
|
|
370
384
|
PikkuMiddleware,
|
|
371
385
|
undefined,
|
|
@@ -375,8 +389,8 @@ export type PikkuFunctionConfigWithSchema<
|
|
|
375
389
|
'func' | 'input' | 'output' | 'permissions' | 'approvalDescription'
|
|
376
390
|
> & {
|
|
377
391
|
func:
|
|
378
|
-
| PikkuFunction<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires>
|
|
379
|
-
| PikkuFunctionSessionless<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires>
|
|
392
|
+
| PikkuFunction<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires, RequiredServices>
|
|
393
|
+
| PikkuFunctionSessionless<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires, RequiredServices>
|
|
380
394
|
input?: InputSchema
|
|
381
395
|
output?: OutputSchema
|
|
382
396
|
permissions?: InputSchema extends StandardSchemaV1
|
|
@@ -413,6 +427,12 @@ export type PikkuFunctionConfigWithSchema<
|
|
|
413
427
|
* })
|
|
414
428
|
* \`\`\`
|
|
415
429
|
*/
|
|
430
|
+
export function pikkuFunc<
|
|
431
|
+
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
432
|
+
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
433
|
+
>(
|
|
434
|
+
config: PikkuFunctionConfigWithSchema<InputSchema, OutputSchema, 'session' | 'rpc', WiredSecretBrokerServices> & { secretBroker: true }
|
|
435
|
+
): PikkuFunctionConfig<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, 'session' | 'rpc'>
|
|
416
436
|
export function pikkuFunc<
|
|
417
437
|
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
418
438
|
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
@@ -464,17 +484,19 @@ export const pikkuListFunc = <
|
|
|
464
484
|
export type PikkuFunctionSessionlessConfigWithSchema<
|
|
465
485
|
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
466
486
|
OutputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
467
|
-
RequiredWires extends keyof PikkuWire = never
|
|
487
|
+
RequiredWires extends keyof PikkuWire = never,
|
|
488
|
+
RequiredServices extends SecretlessServices<Services> = WiredServices
|
|
468
489
|
> = Omit<
|
|
469
490
|
CorePikkuFunctionConfig<
|
|
470
|
-
PikkuFunctionSessionless<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires>
|
|
491
|
+
PikkuFunctionSessionless<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires, RequiredServices>
|
|
471
492
|
>,
|
|
472
493
|
'func' | 'input' | 'output' | 'permissions' | 'approvalDescription'
|
|
473
494
|
> & {
|
|
474
495
|
func: PikkuFunctionSessionless<
|
|
475
496
|
SchemaInferred<InputSchema>,
|
|
476
497
|
SchemaInferred<OutputSchema>,
|
|
477
|
-
RequiredWires
|
|
498
|
+
RequiredWires,
|
|
499
|
+
RequiredServices
|
|
478
500
|
>
|
|
479
501
|
input?: InputSchema
|
|
480
502
|
output?: OutputSchema
|
|
@@ -512,14 +534,15 @@ export type PikkuFunctionSessionlessConfigWithSchema<
|
|
|
512
534
|
*/
|
|
513
535
|
export function pikkuSessionlessFunc<
|
|
514
536
|
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
515
|
-
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
537
|
+
OutputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
538
|
+
RequiredServices extends SecretlessServices<Services> = WiredServices
|
|
516
539
|
>(
|
|
517
|
-
config: PikkuFunctionSessionlessConfigWithSchema<InputSchema, OutputSchema, 'session' | 'rpc'>
|
|
540
|
+
config: PikkuFunctionSessionlessConfigWithSchema<InputSchema, OutputSchema, 'session' | 'rpc', RequiredServices>
|
|
518
541
|
): PikkuFunctionConfig<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, 'session' | 'rpc'>
|
|
519
|
-
export function pikkuSessionlessFunc<In, Out = unknown>(
|
|
542
|
+
export function pikkuSessionlessFunc<In, Out = unknown, RequiredServices extends SecretlessServices<Services> = WiredServices>(
|
|
520
543
|
func:
|
|
521
|
-
| PikkuFunctionSessionless<In, Out, 'session' | 'rpc'>
|
|
522
|
-
| PikkuFunctionConfig<In, Out, 'session' | 'rpc'
|
|
544
|
+
| PikkuFunctionSessionless<In, Out, 'session' | 'rpc', RequiredServices>
|
|
545
|
+
| PikkuFunctionConfig<In, Out, 'session' | 'rpc', PikkuFunctionSessionless<In, Out, 'session' | 'rpc', RequiredServices>>
|
|
523
546
|
): PikkuFunctionConfig<In, Out, 'session' | 'rpc'>
|
|
524
547
|
export function pikkuSessionlessFunc(func: any) {
|
|
525
548
|
return typeof func === 'function' ? { func } : func
|
|
@@ -584,6 +607,43 @@ export const ref = <Name extends keyof FlattenedRPCMap>(
|
|
|
584
607
|
>
|
|
585
608
|
}
|
|
586
609
|
|
|
610
|
+
/**
|
|
611
|
+
* Declares a capability the connected client answers, reachable from any
|
|
612
|
+
* \`wireChannel\` function as \`channel.remote(name, input)\`.
|
|
613
|
+
*
|
|
614
|
+
* There is no \`func\`: this side owns the contract, the client owns the body.
|
|
615
|
+
* The \`description\` is what a person is shown when asked to approve the call,
|
|
616
|
+
* so write it for them rather than for the caller.
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* \`\`\`typescript
|
|
620
|
+
* export const localCheckoutOutput = z.object({ sha: z.string(), branch: z.string() })
|
|
621
|
+
*
|
|
622
|
+
* export const localCheckout = pikkuRemoteChannelFunc({
|
|
623
|
+
* description: 'Read the current commit and branch of your working tree',
|
|
624
|
+
* output: localCheckoutOutput,
|
|
625
|
+
* })
|
|
626
|
+
* \`\`\`
|
|
627
|
+
*/
|
|
628
|
+
export function pikkuRemoteChannelFunc<
|
|
629
|
+
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
630
|
+
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
631
|
+
>(
|
|
632
|
+
config: Omit<
|
|
633
|
+
PikkuFunctionSessionlessConfigWithSchema<InputSchema, OutputSchema, 'session' | 'rpc'>,
|
|
634
|
+
'func'
|
|
635
|
+
>
|
|
636
|
+
): PikkuFunctionConfig<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, 'session' | 'rpc'> {
|
|
637
|
+
return {
|
|
638
|
+
...config,
|
|
639
|
+
func: async (_services: any, _data: any, _wire: any) => {
|
|
640
|
+
throw new Error(
|
|
641
|
+
\`\${config.title ?? 'This'} is a remote channel capability and has no local implementation — reach it with channel.remote() on the channel whose client exposes it.\`
|
|
642
|
+
)
|
|
643
|
+
},
|
|
644
|
+
} as any
|
|
645
|
+
}
|
|
646
|
+
|
|
587
647
|
/**
|
|
588
648
|
* Creates a Pikku config factory.
|
|
589
649
|
* Use this to define your application's configuration factory.
|
|
@@ -2,16 +2,30 @@ import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
|
|
|
2
2
|
const collectFactories = (groupMap, outputPath, packageMappings) => {
|
|
3
3
|
const factories = new Map();
|
|
4
4
|
for (const [, groupMeta] of groupMap.entries()) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
for (const registration of registrationsOf(groupMeta)) {
|
|
6
|
+
if (registration.exportName && registration.isFactory) {
|
|
7
|
+
const filePath = getFileImportRelativePath(outputPath, registration.sourceFile, packageMappings);
|
|
8
|
+
factories.set(registration.exportName, {
|
|
9
|
+
exportName: registration.exportName,
|
|
10
|
+
filePath,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
return factories;
|
|
14
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Every `add*Middleware` call recorded under one pattern or tag.
|
|
19
|
+
*
|
|
20
|
+
* A group is keyed by its pattern, and more than one file may register for the
|
|
21
|
+
* same one. Emitting only the primary registration meant the other file was
|
|
22
|
+
* never imported, so its middleware never registered — which for a session
|
|
23
|
+
* bridge or an auth gate fails open and fails silently.
|
|
24
|
+
*/
|
|
25
|
+
const registrationsOf = (groupMeta) => [
|
|
26
|
+
groupMeta,
|
|
27
|
+
...(groupMeta.additionalRegistrations ?? []),
|
|
28
|
+
];
|
|
15
29
|
export const serializeMiddlewareImports = (outputPath, middlewareState, httpState, packageMappings = {}, fullState) => {
|
|
16
30
|
const serializedImports = [];
|
|
17
31
|
const serializedFactoryCalls = [];
|
|
@@ -24,9 +38,11 @@ export const serializeMiddlewareImports = (outputPath, middlewareState, httpStat
|
|
|
24
38
|
const directImports = new Set();
|
|
25
39
|
const collectDirectImports = (groupMap) => {
|
|
26
40
|
for (const [, groupMeta] of groupMap.entries()) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
for (const registration of registrationsOf(groupMeta)) {
|
|
42
|
+
if (!registration.isFactory) {
|
|
43
|
+
const filePath = getFileImportRelativePath(outputPath, registration.sourceFile, packageMappings);
|
|
44
|
+
directImports.add(filePath);
|
|
45
|
+
}
|
|
30
46
|
}
|
|
31
47
|
}
|
|
32
48
|
};
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
export const serializeSecretDefinitionTypes = () => {
|
|
2
|
-
return `export {
|
|
2
|
+
return `export { defineSecret } from '@pikku/core/secret'
|
|
3
3
|
export type { CoreSecret, SecretDefinitionMeta, SecretDefinitionsMeta } from '@pikku/core/secret'
|
|
4
4
|
`;
|
|
5
5
|
};
|
|
6
6
|
export const serializeScopeDefinitionTypes = () => {
|
|
7
|
-
return `export {
|
|
7
|
+
return `export { defineScope } from '@pikku/core/scope'
|
|
8
8
|
export type { CoreScopes, CoreScopeNode, FlatScope, ScopeDefinitionMeta, ScopeDefinitionsMeta } from '@pikku/core/scope'
|
|
9
|
+
export { defineSystemRole } from '@pikku/core/role'
|
|
10
|
+
export type { CoreSystemRole, CoreSystemRoles, SystemRole, SystemRoleDefinitionMeta, SystemRoleDefinitionsMeta } from '@pikku/core/role'
|
|
9
11
|
`;
|
|
10
12
|
};
|
|
11
13
|
export const serializeVariableDefinitionTypes = () => {
|
|
12
|
-
return `export {
|
|
14
|
+
return `export { defineVariable } from '@pikku/core/variable'
|
|
13
15
|
export type { CoreVariable, VariableDefinitionMeta, VariableDefinitionsMeta } from '@pikku/core/variable'
|
|
14
16
|
`;
|
|
15
17
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const pikkuPersonas: import("#pikku").PikkuFunctionConfig<{
|
|
2
|
+
bootstrap?: boolean;
|
|
3
|
+
}, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<{
|
|
4
|
+
bootstrap?: boolean;
|
|
5
|
+
}, void, "rpc" | "session", import("#pikku").WiredServices> | import("#pikku").PikkuFunction<{
|
|
6
|
+
bootstrap?: boolean;
|
|
7
|
+
}, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { pikkuSessionlessFunc } from '#pikku';
|
|
2
|
+
import { writeFileInDir } from '../../../utils/file-writer.js';
|
|
3
|
+
import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
|
|
4
|
+
import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
|
|
5
|
+
import { serializePersonasTypes } from './serialize-personas-types.js';
|
|
6
|
+
import { personaEnvironmentErrors, validateAndBuildPersonasMeta, } from '@pikku/core/persona';
|
|
7
|
+
export const pikkuPersonas = pikkuSessionlessFunc({
|
|
8
|
+
func: async ({ logger, config, getInspectorState }, data) => {
|
|
9
|
+
const { personasFile, personasMetaJsonFile, rolesFile, packageMappings } = config;
|
|
10
|
+
if (!personasFile) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
// Same cold-start reasoning as Scopes and Roles: on a bare .pikku this
|
|
14
|
+
// runs before the app's own types exist, so it takes the zero state. The
|
|
15
|
+
// file only has to exist so a persona file can import definePersonas.
|
|
16
|
+
const bootstrap = data?.bootstrap ?? false;
|
|
17
|
+
const state = await getInspectorState(false, bootstrap, bootstrap);
|
|
18
|
+
const environments = config.environments ?? {};
|
|
19
|
+
// Before anything is written. A persona that may not run where it says it
|
|
20
|
+
// runs is a declaration to fix, not a file to generate — and generating
|
|
21
|
+
// it anyway would leave a `.pikku` that typechecks while lying.
|
|
22
|
+
const errors = state.personas.definitions.flatMap((persona) => personaEnvironmentErrors(persona.id, persona, environments));
|
|
23
|
+
if (errors.length) {
|
|
24
|
+
throw new Error(errors.join('\n'));
|
|
25
|
+
}
|
|
26
|
+
const content = serializePersonasTypes({
|
|
27
|
+
definitions: state.personas.definitions,
|
|
28
|
+
rolesImportPath: getFileImportRelativePath(personasFile, rolesFile, packageMappings),
|
|
29
|
+
environmentNames: Object.keys(environments),
|
|
30
|
+
});
|
|
31
|
+
await writeFileInDir(logger, personasFile, content);
|
|
32
|
+
if (personasMetaJsonFile) {
|
|
33
|
+
const meta = validateAndBuildPersonasMeta(state.personas.definitions);
|
|
34
|
+
await writeFileInDir(logger, personasMetaJsonFile, JSON.stringify(meta, null, 2));
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
middleware: [
|
|
38
|
+
logCommandInfoAndTime({
|
|
39
|
+
commandStart: 'Creating PikkuPersonas types',
|
|
40
|
+
commandEnd: 'Created PikkuPersonas types',
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PersonaDefinitions } from '@pikku/core/persona';
|
|
2
|
+
export interface SerializePersonasOptions {
|
|
3
|
+
definitions: PersonaDefinitions;
|
|
4
|
+
/** Relative import path to the generated roles file. */
|
|
5
|
+
rolesImportPath: string;
|
|
6
|
+
/** Keys of `environments` in pikku.config.json. */
|
|
7
|
+
environmentNames: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Generates the `PersonaId` union and a `definePersonas` whose `roles` are
|
|
11
|
+
* checked against the declared system roles.
|
|
12
|
+
*
|
|
13
|
+
* The wrapper is why this is generated rather than re-exported: `roles` typed
|
|
14
|
+
* as `string[]` would let a persona name a role nobody declared, and the
|
|
15
|
+
* failure — a scatter of 403s in a run days later — looks nothing like the
|
|
16
|
+
* mistake. Typed as `SystemRoleName[]`, it is a red squiggle in the editor.
|
|
17
|
+
*/
|
|
18
|
+
export declare const serializePersonasTypes: ({ definitions, rolesImportPath, environmentNames, }: SerializePersonasOptions) => string;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const quote = (value) => `'${value.replace(/'/g, "\\'")}'`;
|
|
2
|
+
/**
|
|
3
|
+
* Generates the `PersonaId` union and a `definePersonas` whose `roles` are
|
|
4
|
+
* checked against the declared system roles.
|
|
5
|
+
*
|
|
6
|
+
* The wrapper is why this is generated rather than re-exported: `roles` typed
|
|
7
|
+
* as `string[]` would let a persona name a role nobody declared, and the
|
|
8
|
+
* failure — a scatter of 403s in a run days later — looks nothing like the
|
|
9
|
+
* mistake. Typed as `SystemRoleName[]`, it is a red squiggle in the editor.
|
|
10
|
+
*/
|
|
11
|
+
export const serializePersonasTypes = ({ definitions, rolesImportPath, environmentNames, }) => {
|
|
12
|
+
const ids = [...new Set(definitions.map((d) => d.id))].sort();
|
|
13
|
+
const environmentUnion = environmentNames.length > 0
|
|
14
|
+
? `\n${[...environmentNames].sort().map((name) => ` | ${quote(name)}`).join('\n')}`
|
|
15
|
+
: ' never';
|
|
16
|
+
const union = ids.length > 0
|
|
17
|
+
? `\n${ids.map((id) => ` | ${quote(id)}`).join('\n')}`
|
|
18
|
+
: ' never';
|
|
19
|
+
const runnable = definitions
|
|
20
|
+
.filter((d) => d.runnable)
|
|
21
|
+
.map((d) => d.id)
|
|
22
|
+
.sort();
|
|
23
|
+
const runnableUnion = runnable.length > 0
|
|
24
|
+
? `\n${runnable.map((id) => ` | ${quote(id)}`).join('\n')}`
|
|
25
|
+
: ' never';
|
|
26
|
+
return `/**
|
|
27
|
+
* This file was generated by the @pikku/cli
|
|
28
|
+
*/
|
|
29
|
+
import { definePersonas as definePersonasCore } from '@pikku/core/persona'
|
|
30
|
+
import type { CorePersona, PersonaMeta, PersonasMeta } from '@pikku/core/persona'
|
|
31
|
+
import type { SystemRoleName } from '${rolesImportPath}'
|
|
32
|
+
import definitions from './pikku-personas-meta.gen.json' with { type: 'json' }
|
|
33
|
+
|
|
34
|
+
/** Every declared persona. */
|
|
35
|
+
export type PersonaId =${union}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The personas a virtual user can actually be.
|
|
39
|
+
*
|
|
40
|
+
* Excludes anyone whose only login is a provider account — driving a consent
|
|
41
|
+
* screen needs a human — and anyone declared \`runnable: false\`, who exists to
|
|
42
|
+
* be acted upon rather than to act.
|
|
43
|
+
*/
|
|
44
|
+
export type RunnablePersonaId =${runnableUnion}
|
|
45
|
+
|
|
46
|
+
/** Every environment configured in pikku.config.json. */
|
|
47
|
+
export type EnvironmentName =${environmentUnion}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A persona whose roles are checked against \`defineSystemRole\` and whose
|
|
51
|
+
* environments are checked against the config.
|
|
52
|
+
*
|
|
53
|
+
* Omitting \`environments\` means every environment except the ones flagged
|
|
54
|
+
* \`production: true\`. Naming a production one additionally requires
|
|
55
|
+
* \`disposition: 'accountable'\`, which the type cannot express and \`pikku\`
|
|
56
|
+
* refuses at build time.
|
|
57
|
+
*/
|
|
58
|
+
export type TypedPersona = Omit<CorePersona, 'roles' | 'environments'> & {
|
|
59
|
+
roles?: SystemRoleName[]
|
|
60
|
+
environments?: EnvironmentName[]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Declare the people who use this application.
|
|
65
|
+
*
|
|
66
|
+
* A persona while running is a virtual user; there is no second declaration.
|
|
67
|
+
*/
|
|
68
|
+
export const definePersonas = (personas: Record<string, TypedPersona>): void =>
|
|
69
|
+
definePersonasCore(personas)
|
|
70
|
+
|
|
71
|
+
/** Declared personas, keyed by id. Read by the console and \`pikku persona\`. */
|
|
72
|
+
export const PERSONAS: PersonasMeta = definitions as unknown as PersonasMeta
|
|
73
|
+
|
|
74
|
+
export const PERSONA_LIST: PersonaMeta[] = Object.values(PERSONAS)
|
|
75
|
+
`;
|
|
76
|
+
};
|
|
@@ -4,6 +4,7 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
|
|
|
4
4
|
import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
|
|
5
5
|
import { removeLegacyScaffoldFile } from '../../../utils/remove-legacy-scaffold-file.js';
|
|
6
6
|
import { serializeEventsScaffold } from './serialize-events-scaffold.js';
|
|
7
|
+
import { resolveScaffoldFeature } from '../../../utils/resolve-scaffold-feature.js';
|
|
7
8
|
export const pikkuEventsScaffold = pikkuSessionlessFunc({
|
|
8
9
|
func: async ({ logger, config }) => {
|
|
9
10
|
if (!config.scaffold?.events ||
|
|
@@ -15,7 +16,7 @@ export const pikkuEventsScaffold = pikkuSessionlessFunc({
|
|
|
15
16
|
});
|
|
16
17
|
return false;
|
|
17
18
|
}
|
|
18
|
-
const authRequired = config.scaffold.events
|
|
19
|
+
const authRequired = resolveScaffoldFeature('events', config.scaffold.events).auth;
|
|
19
20
|
const pikkuTypesImportPath = getFileImportRelativePath(config.eventsChannelFile, config.typesDeclarationFile, config.packageMappings);
|
|
20
21
|
const { schemas, functions } = serializeEventsScaffold(authRequired, pikkuTypesImportPath);
|
|
21
22
|
await writeFileInDir(logger, config.eventsSchemasFile, schemas);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const pikkuRoles: import("#pikku").PikkuFunctionConfig<{
|
|
2
|
+
bootstrap?: boolean;
|
|
3
|
+
}, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<{
|
|
4
|
+
bootstrap?: boolean;
|
|
5
|
+
}, void, "rpc" | "session", import("#pikku").WiredServices> | import("#pikku").PikkuFunction<{
|
|
6
|
+
bootstrap?: boolean;
|
|
7
|
+
}, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
|