@pikku/cli 0.12.81 → 0.12.83
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/cli.schema.json +1 -1
- package/console-app/assets/{index-NmNeixvK.js → index-CN_U0k_D.js} +154 -144
- package/console-app/assets/{index-DwyRdRuZ.css → index-CpHRlBt-.css} +1 -1
- package/console-app/index.html +2 -2
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +3 -2
- 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.js +21 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- 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 +60 -3
- 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 +6 -12
- package/dist/.pikku/function/pikku-function-types.gen.js +3 -12
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +190 -12
- package/dist/.pikku/function/pikku-functions.gen.js +15 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +2 -24
- package/dist/.pikku/http/pikku-http-types.gen.js +2 -24
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.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.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 +4 -1
- package/dist/.pikku/pikku-services.gen.js +3 -0
- package/dist/.pikku/pikku-types.gen.d.ts +2 -1
- package/dist/.pikku/pikku-types.gen.js +3 -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 +9 -0
- 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 -1
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuGraphWiringsOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuImportN8nInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuScopesInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuWebhookOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/ScopesAuditInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/ScopesPruneInput.schema.json +1 -0
- package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +5 -0
- package/dist/.pikku/scopes/pikku-scope-types.gen.js +4 -0
- package/dist/.pikku/scopes/pikku-scopes-meta.gen.json +1 -0
- package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +35 -0
- package/dist/.pikku/scopes/pikku-scopes.gen.js +27 -0
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets-meta.gen.json +1 -0
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +11 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +11 -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 +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables-meta.gen.json +1 -0
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +11 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +13 -3
- package/dist/.pikku/workflow/meta/allWorkflow.gen.json +48 -6
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +4 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- 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/src/cli.wiring.js +47 -4
- package/dist/src/deploy/analyzer/analyzer.js +6 -0
- package/dist/src/fabric/fabric-commands.d.ts +3 -3
- package/dist/src/fabric/functions/llm-key.function.d.ts +4 -4
- package/dist/src/fabric/functions/validate.function.js +42 -2
- package/dist/src/functions/commands/bootstrap.js +3 -0
- package/dist/src/functions/commands/dev.js +14 -3
- package/dist/src/functions/commands/enable.d.ts +1 -0
- package/dist/src/functions/commands/enable.js +10 -5
- package/dist/src/functions/commands/import-n8n.d.ts +10 -0
- package/dist/src/functions/commands/import-n8n.js +130 -0
- package/dist/src/functions/commands/info.js +0 -13
- package/dist/src/functions/commands/new-addon.js +33 -35
- package/dist/src/functions/commands/pikku-command-bootstrap.js +6 -0
- package/dist/src/functions/commands/scopes-audit.d.ts +1 -0
- package/dist/src/functions/commands/scopes-audit.js +37 -0
- package/dist/src/functions/commands/scopes-prune.d.ts +14 -0
- package/dist/src/functions/commands/scopes-prune.js +50 -0
- package/dist/src/functions/commands/scopes-shared.d.ts +39 -0
- package/dist/src/functions/commands/scopes-shared.js +83 -0
- package/dist/src/functions/commands/serve.js +4 -2
- package/dist/src/functions/commands/skills.js +18 -10
- package/dist/src/functions/wirings/ai-agent/serialize-ai-agent-types.js +2 -1
- package/dist/src/functions/wirings/console/serialize-console-functions.js +6 -0
- package/dist/src/functions/wirings/credentials/serialize-credentials-types.js +22 -0
- package/dist/src/functions/wirings/functions/pikku-command-function-types-split.js +1 -1
- package/dist/src/functions/wirings/functions/pikku-command-function-types.js +2 -2
- package/dist/src/functions/wirings/functions/serialize-function-types.d.ts +1 -1
- package/dist/src/functions/wirings/functions/serialize-function-types.js +14 -16
- package/dist/src/functions/wirings/functions/serialize-pikku-types-hub.d.ts +1 -1
- package/dist/src/functions/wirings/functions/serialize-pikku-types-hub.js +6 -2
- package/dist/src/functions/wirings/graph/pikku-command-graph-wirings.d.ts +1 -0
- package/dist/src/functions/wirings/graph/pikku-command-graph-wirings.js +21 -0
- package/dist/src/functions/wirings/graph/serialize-graph-wirings.d.ts +5 -0
- package/dist/src/functions/wirings/graph/serialize-graph-wirings.js +14 -0
- package/dist/src/functions/wirings/http/serialize-http-types.js +2 -30
- package/dist/src/functions/wirings/package/pikku-command-package-types.d.ts +1 -0
- package/dist/src/functions/wirings/package/pikku-command-package-types.js +14 -1
- package/dist/src/functions/wirings/package/serialize-package-types.d.ts +1 -0
- package/dist/src/functions/wirings/package/serialize-package-types.js +5 -0
- package/dist/src/functions/wirings/permissions/pikku-command-permissions.js +1 -3
- package/dist/src/functions/wirings/permissions/serialize-permissions-imports.d.ts +6 -1
- package/dist/src/functions/wirings/permissions/serialize-permissions-imports.js +7 -64
- package/dist/src/functions/wirings/rpc/pikku-command-rpc-map.d.ts +5 -0
- package/dist/src/functions/wirings/rpc/pikku-command-rpc-map.js +20 -0
- package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.d.ts +1 -0
- package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.js +8 -3
- package/dist/src/functions/wirings/scopes/pikku-command-scopes.d.ts +7 -0
- package/dist/src/functions/wirings/scopes/pikku-command-scopes.js +34 -0
- package/dist/src/functions/wirings/scopes/serialize-scopes-types.d.ts +15 -0
- package/dist/src/functions/wirings/scopes/serialize-scopes-types.js +86 -0
- package/dist/src/functions/wirings/secrets/serialize-secrets-types.js +13 -0
- package/dist/src/functions/wirings/variables/serialize-variables-types.js +15 -2
- package/dist/src/functions/wirings/webhook/pikku-command-webhook.d.ts +1 -0
- package/dist/src/functions/wirings/webhook/pikku-command-webhook.js +25 -0
- package/dist/src/functions/wirings/webhook/serialize-webhook.d.ts +14 -0
- package/dist/src/functions/wirings/webhook/serialize-webhook.js +34 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-routes.js +29 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +3 -0
- package/dist/src/functions/workflows/all.workflow.js +23 -3
- package/dist/src/services.d.ts +1 -0
- package/dist/src/services.js +1 -0
- package/dist/src/utils/pikku-cli-config.js +20 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -8
- package/skills/pikku-addon/SKILL.md +7 -3
- package/skills/pikku-ai-agent/SKILL.md +6 -3
- package/skills/pikku-ai-vercel/SKILL.md +6 -3
- package/skills/pikku-ai-voice/SKILL.md +6 -3
- package/skills/pikku-audit/SKILL.md +10 -3
- package/skills/pikku-aws/SKILL.md +9 -5
- package/skills/pikku-backblaze/SKILL.md +4 -3
- package/skills/pikku-better-auth/SKILL.md +10 -5
- package/skills/pikku-cli/SKILL.md +6 -3
- package/skills/pikku-concepts/SKILL.md +9 -4
- package/skills/pikku-concepts/references/concept-mapping.md +12 -10
- package/skills/pikku-config/SKILL.md +9 -5
- package/skills/pikku-cron/SKILL.md +6 -3
- package/skills/pikku-deploy-azure/SKILL.md +5 -3
- package/skills/pikku-deploy-cloudflare/SKILL.md +5 -3
- package/skills/pikku-deploy-express/SKILL.md +6 -3
- package/skills/pikku-deploy-fastify/SKILL.md +6 -3
- package/skills/pikku-deploy-lambda/SKILL.md +6 -3
- package/skills/pikku-deploy-nextjs/SKILL.md +5 -3
- package/skills/pikku-deploy-uws/SKILL.md +7 -4
- package/skills/pikku-deps/SKILL.md +13 -6
- package/skills/pikku-emails/SKILL.md +10 -5
- package/skills/pikku-feature/SKILL.md +1 -1
- package/skills/pikku-gateway-slack/SKILL.md +6 -3
- package/skills/pikku-http/SKILL.md +15 -21
- package/skills/pikku-http/references/http-options.md +0 -2
- package/skills/pikku-info/SKILL.md +9 -4
- package/skills/pikku-jose/SKILL.md +6 -3
- package/skills/pikku-kysely/SKILL.md +13 -5
- package/skills/pikku-machine-auth/SKILL.md +9 -3
- package/skills/pikku-mcp/SKILL.md +7 -3
- package/skills/pikku-middleware/SKILL.md +11 -6
- package/skills/pikku-mongodb/SKILL.md +8 -5
- package/skills/pikku-n8n-import/SKILL.md +109 -0
- package/skills/pikku-n8n-import/SPEC.md +84 -0
- package/skills/pikku-n8n-import/references/addon-mapping.md +121 -0
- package/skills/pikku-n8n-import/references/code-translation.md +121 -0
- package/skills/pikku-n8n-import/references/loops-and-control.md +87 -0
- package/skills/pikku-permissions/SKILL.md +26 -15
- package/skills/pikku-pino/SKILL.md +5 -3
- package/skills/pikku-product-second-opinion/README.md +43 -0
- package/skills/pikku-product-second-opinion/SKILL.md +158 -0
- package/skills/pikku-product-second-opinion/example/sample-report.md +90 -0
- package/skills/pikku-product-second-opinion/references/report-template.md +73 -0
- package/skills/pikku-queue/SKILL.md +7 -4
- package/skills/pikku-redis/SKILL.md +9 -6
- package/skills/pikku-rpc/SKILL.md +7 -4
- package/skills/pikku-rtl/SKILL.md +1 -1
- package/skills/pikku-scenario/SKILL.md +215 -0
- package/skills/pikku-schedule/SKILL.md +6 -3
- package/skills/pikku-schema-ajv/SKILL.md +5 -3
- package/skills/pikku-schema-cfworker/SKILL.md +6 -3
- package/skills/pikku-security/SKILL.md +8 -4
- package/skills/pikku-services/SKILL.md +8 -4
- package/skills/pikku-software-archaeology/README.md +70 -0
- package/skills/pikku-software-archaeology/SKILL.md +186 -0
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +625 -0
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +49 -0
- package/skills/pikku-software-archaeology/scripts/validate.mjs +173 -0
- package/skills/pikku-template-clone/SKILL.md +1 -1
- package/skills/pikku-trigger/SKILL.md +7 -3
- package/skills/pikku-versioning/SKILL.md +7 -3
- package/skills/pikku-websocket/SKILL.md +8 -4
- package/skills/pikku-workflow/SKILL.md +7 -3
- package/skills/pikku-ws/SKILL.md +5 -3
- package/skills/pikku-n8n-addon-map/SKILL.md +0 -178
- package/skills/pikku-n8n-code-translate/SKILL.md +0 -166
- package/skills/pikku-testing/SKILL.md +0 -328
- package/skills/pikku-testing/references/cucumber-bdd-testing.md +0 -176
|
@@ -159,19 +159,6 @@ export const pikkuInfoTags = pikkuSessionlessFunc({
|
|
|
159
159
|
tagMap.get(tag).middlewareNames.push(...(group.instanceIds ?? []));
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
const tagPermissions = state.permissions?.tagPermissions;
|
|
163
|
-
if (tagPermissions) {
|
|
164
|
-
for (const [tag, group] of tagPermissions) {
|
|
165
|
-
if (!tagMap.has(tag)) {
|
|
166
|
-
tagMap.set(tag, {
|
|
167
|
-
funcIds: [],
|
|
168
|
-
middlewareNames: [],
|
|
169
|
-
permissionNames: [],
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
tagMap.get(tag).permissionNames.push(...(group.instanceIds ?? []));
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
162
|
const tags = [...tagMap.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
176
163
|
if (tags.length === 0) {
|
|
177
164
|
console.log('No tags found.');
|
|
@@ -227,18 +227,28 @@ export const createWireServices = pikkuAddonWireServices(
|
|
|
227
227
|
`;
|
|
228
228
|
}
|
|
229
229
|
else if (flags.oauth || flags.credential === 'oauth2') {
|
|
230
|
+
// The OAuth2 access token is owned and refreshed by the platform credential
|
|
231
|
+
// service (better-auth). Resolve a ready token per-request via the wire and
|
|
232
|
+
// hand it to the service — the addon does not do its own token exchange.
|
|
230
233
|
files['src/services.ts'] =
|
|
231
|
-
`import {
|
|
232
|
-
import {
|
|
234
|
+
`import { UnauthorizedError } from '@pikku/core/errors'
|
|
235
|
+
import { ${pascalName}Service } from './${name}-api.service.js'
|
|
236
|
+
import { pikkuAddonWireServices } from '#pikku'
|
|
233
237
|
|
|
234
|
-
export const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
238
|
+
export const createWireServices = pikkuAddonWireServices(
|
|
239
|
+
async ({ variables }, wire) => {
|
|
240
|
+
if (!wire.getCredential) {
|
|
241
|
+
throw new Error('Credential resolution is not available in this runtime')
|
|
242
|
+
}
|
|
243
|
+
const cred = await wire.getCredential<{ accessToken: string }>('${camelName}')
|
|
244
|
+
if (!cred?.accessToken) {
|
|
245
|
+
throw new UnauthorizedError('No ${displayName} connection — connect ${displayName} first')
|
|
246
|
+
}
|
|
247
|
+
const ${camelName} = new ${pascalName}Service(cred, variables)
|
|
239
248
|
|
|
240
|
-
|
|
241
|
-
}
|
|
249
|
+
return { ${camelName} }
|
|
250
|
+
}
|
|
251
|
+
)
|
|
242
252
|
`;
|
|
243
253
|
}
|
|
244
254
|
else if (flags.secret) {
|
|
@@ -329,41 +339,30 @@ export class ${pascalName}Service {
|
|
|
329
339
|
`;
|
|
330
340
|
}
|
|
331
341
|
else if (flags.oauth) {
|
|
342
|
+
// The access token is resolved (and refreshed) by the platform credential
|
|
343
|
+
// service and injected via createWireServices — this service just uses it.
|
|
332
344
|
files[`src/${name}-api.service.ts`] =
|
|
333
|
-
`import {
|
|
334
|
-
import type { TypedSecretService } from '#pikku/secrets/pikku-secrets.gen.js'
|
|
345
|
+
`import type { TypedVariablesService } from '#pikku/variables/pikku-variables.gen.js'
|
|
335
346
|
|
|
336
347
|
const BASE_URL = 'https://api.example.com/v1'
|
|
337
348
|
|
|
338
|
-
export const ${screamingName}_OAUTH2_CONFIG = {
|
|
339
|
-
tokenSecretId: '${screamingName}_TOKENS',
|
|
340
|
-
authorizationUrl: 'https://example.com/oauth2/authorize',
|
|
341
|
-
tokenUrl: 'https://example.com/oauth2/token',
|
|
342
|
-
scopes: ['read', 'write'],
|
|
343
|
-
}
|
|
344
|
-
|
|
345
349
|
export interface RequestOptions {
|
|
346
350
|
body?: unknown
|
|
347
351
|
qs?: Record<string, string | number | boolean | undefined>
|
|
348
352
|
}
|
|
349
353
|
|
|
350
354
|
export class ${pascalName}Service {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
${screamingName}_OAUTH2_CONFIG,
|
|
356
|
-
'${screamingName}_APP_CREDENTIALS',
|
|
357
|
-
secrets
|
|
358
|
-
)
|
|
359
|
-
}
|
|
355
|
+
constructor(
|
|
356
|
+
private creds: { accessToken: string },
|
|
357
|
+
_variables?: TypedVariablesService
|
|
358
|
+
) {}
|
|
360
359
|
|
|
361
360
|
async request<T>(
|
|
362
361
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
|
|
363
362
|
endpoint: string,
|
|
364
363
|
options?: RequestOptions
|
|
365
364
|
): Promise<T> {
|
|
366
|
-
const url = new URL(
|
|
365
|
+
const url = new URL(endpoint, BASE_URL)
|
|
367
366
|
|
|
368
367
|
if (options?.qs) {
|
|
369
368
|
for (const [key, value] of Object.entries(options.qs)) {
|
|
@@ -373,10 +372,11 @@ export class ${pascalName}Service {
|
|
|
373
372
|
}
|
|
374
373
|
}
|
|
375
374
|
|
|
376
|
-
const response = await
|
|
375
|
+
const response = await fetch(url.toString(), {
|
|
377
376
|
method,
|
|
378
377
|
headers: {
|
|
379
378
|
'Content-Type': 'application/json',
|
|
379
|
+
'Authorization': \`Bearer \${this.creds.accessToken}\`,
|
|
380
380
|
},
|
|
381
381
|
body: options?.body ? JSON.stringify(options.body) : undefined,
|
|
382
382
|
})
|
|
@@ -386,11 +386,7 @@ export class ${pascalName}Service {
|
|
|
386
386
|
throw new Error(\`${displayName} API error (\${response.status}): \${errorText}\`)
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
|
|
390
|
-
if (!text) {
|
|
391
|
-
return {} as T
|
|
392
|
-
}
|
|
393
|
-
return JSON.parse(text) as T
|
|
389
|
+
return response.json() as Promise<T>
|
|
394
390
|
}
|
|
395
391
|
}
|
|
396
392
|
`;
|
|
@@ -811,7 +807,9 @@ export const pikkuNewAddon = pikkuSessionlessFunc({
|
|
|
811
807
|
const resolvedDescription = description || `${resolvedDisplayName} integration for Pikku`;
|
|
812
808
|
// Resolve target directory
|
|
813
809
|
const baseDir = dir || config.scaffold?.addonDir || process.cwd();
|
|
814
|
-
|
|
810
|
+
// Folder mirrors the package name (@pikku/addon-<name>) so a packages/
|
|
811
|
+
// listing reads as packages/addon-<name>, distinct from app workspaces.
|
|
812
|
+
const addonDir = join(baseDir, `addon-${name}`);
|
|
815
813
|
if (existsSync(addonDir)) {
|
|
816
814
|
logger.error(`Directory already exists: ${addonDir}`);
|
|
817
815
|
process.exit(1);
|
|
@@ -9,6 +9,12 @@ export const pikkuBootstrap = pikkuSessionlessFunc({
|
|
|
9
9
|
const addonBootstraps = [];
|
|
10
10
|
for (const [, decl] of stateBeforeBootstrap.rpc?.wireAddonDeclarations ??
|
|
11
11
|
[]) {
|
|
12
|
+
// Remote addons (wireRemoteAddon) run on the host — never import their
|
|
13
|
+
// runtime bootstrap here; that would register their functions locally
|
|
14
|
+
// and drag in the runtime deps remote consumption exists to avoid. The
|
|
15
|
+
// consumer's own wireRemoteAddon() call registers the remote binding.
|
|
16
|
+
if (decl.remote)
|
|
17
|
+
continue;
|
|
12
18
|
addonBootstraps.push(`${decl.package}/.pikku/pikku-bootstrap.gen.js`);
|
|
13
19
|
logger.debug(`• Addon bootstrap: ${decl.package}`);
|
|
14
20
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const scopesAudit: import("#pikku").PikkuFunctionConfig<{}, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<{}, void, "rpc" | "session", import("#pikku").Services> | import("#pikku").PikkuFunction<{}, void, "rpc" | "session", import("#pikku").Services>, undefined, undefined>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { pikkuSessionlessFunc } from '#pikku';
|
|
2
|
+
import { loadDeclaredScopes, openScopeService, reportStaleScopes, } from './scopes-shared.js';
|
|
3
|
+
export const scopesAudit = pikkuSessionlessFunc({
|
|
4
|
+
remote: true,
|
|
5
|
+
func: async ({ logger, config }) => {
|
|
6
|
+
const declared = await loadDeclaredScopes(config.scopesMetaJsonFile, logger);
|
|
7
|
+
if (!declared) {
|
|
8
|
+
throw new Error('scope metadata not found');
|
|
9
|
+
}
|
|
10
|
+
const opened = await openScopeService({ config, logger }, declared, 'pikku scopes audit');
|
|
11
|
+
if (!opened) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const stale = await opened.service.findStaleScopes();
|
|
16
|
+
logger.info(`Scope audit: ${declared.length} scope(s) declared in code`);
|
|
17
|
+
if (stale.length === 0) {
|
|
18
|
+
logger.info(' every scope in the database is still declared');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
logger.info('');
|
|
22
|
+
logger.info(`${stale.length} scope(s) no longer declared in code:`);
|
|
23
|
+
reportStaleScopes(stale, logger);
|
|
24
|
+
const granted = stale.filter((s) => s.roles.length > 0);
|
|
25
|
+
logger.info('');
|
|
26
|
+
if (granted.length > 0) {
|
|
27
|
+
logger.warn(`${granted.length} undeclared scope(s) are still granted by a role. ` +
|
|
28
|
+
`They authorize nothing — no function can require a scope that is not declared — ` +
|
|
29
|
+
`but the grants persist until removed.`);
|
|
30
|
+
}
|
|
31
|
+
logger.info('Run `pikku scopes prune --yes` to remove them.');
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await opened.destroy();
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes scopes that are no longer declared in code, cascading them out of
|
|
3
|
+
* every role that holds them.
|
|
4
|
+
*
|
|
5
|
+
* This revokes access, so it never runs implicitly — not at boot, not as part
|
|
6
|
+
* of `pikku all`. Without `--yes` it only reports the blast radius.
|
|
7
|
+
*/
|
|
8
|
+
export declare const scopesPrune: import("#pikku").PikkuFunctionConfig<{
|
|
9
|
+
yes?: boolean;
|
|
10
|
+
}, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<{
|
|
11
|
+
yes?: boolean;
|
|
12
|
+
}, void, "rpc" | "session", import("#pikku").Services> | import("#pikku").PikkuFunction<{
|
|
13
|
+
yes?: boolean;
|
|
14
|
+
}, void, "rpc" | "session", import("#pikku").Services>, undefined, undefined>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { pikkuSessionlessFunc } from '#pikku';
|
|
2
|
+
import { loadDeclaredScopes, openScopeService, reportStaleScopes, } from './scopes-shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* Removes scopes that are no longer declared in code, cascading them out of
|
|
5
|
+
* every role that holds them.
|
|
6
|
+
*
|
|
7
|
+
* This revokes access, so it never runs implicitly — not at boot, not as part
|
|
8
|
+
* of `pikku all`. Without `--yes` it only reports the blast radius.
|
|
9
|
+
*/
|
|
10
|
+
export const scopesPrune = pikkuSessionlessFunc({
|
|
11
|
+
remote: true,
|
|
12
|
+
func: async ({ logger, config }, { yes }) => {
|
|
13
|
+
const declared = await loadDeclaredScopes(config.scopesMetaJsonFile, logger);
|
|
14
|
+
if (!declared) {
|
|
15
|
+
throw new Error('scope metadata not found');
|
|
16
|
+
}
|
|
17
|
+
const opened = await openScopeService({ config, logger }, declared, 'pikku scopes prune');
|
|
18
|
+
if (!opened) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const stale = await opened.service.findStaleScopes();
|
|
23
|
+
if (stale.length === 0) {
|
|
24
|
+
logger.info('scopes prune: nothing to prune');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
logger.info(`${stale.length} scope(s) no longer declared in code:`);
|
|
28
|
+
reportStaleScopes(stale, logger);
|
|
29
|
+
const granted = stale.filter((s) => s.roles.length > 0);
|
|
30
|
+
const affectedRoles = new Set(stale.flatMap(({ roles }) => roles));
|
|
31
|
+
if (!yes) {
|
|
32
|
+
logger.info('');
|
|
33
|
+
if (granted.length > 0) {
|
|
34
|
+
logger.warn(`Pruning would revoke ${granted.length} scope(s) from the roles above.`);
|
|
35
|
+
}
|
|
36
|
+
logger.info('Re-run with --yes to remove them.');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const pruned = await opened.service.pruneScopes();
|
|
40
|
+
logger.info('');
|
|
41
|
+
logger.info(`scopes prune: removed ${pruned.length} scope(s)`);
|
|
42
|
+
if (granted.length > 0) {
|
|
43
|
+
logger.warn(`Revoked from ${affectedRoles.size} role(s). Users holding those roles lose these scopes on their next request.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await opened.destroy();
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FlatScope } from '@pikku/core/scope';
|
|
2
|
+
import { KyselyScopeService } from '@pikku/kysely';
|
|
3
|
+
type Logger = {
|
|
4
|
+
info: (msg: string) => void;
|
|
5
|
+
warn: (msg: string) => void;
|
|
6
|
+
error: (msg: string) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare const loadDeclaredScopes: (scopesMetaJsonFile: string, logger: Logger) => Promise<FlatScope[] | null>;
|
|
9
|
+
export type OpenedScopeService = {
|
|
10
|
+
service: KyselyScopeService;
|
|
11
|
+
destroy: () => Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Opens a ScopeService against the project's configured database and brings the
|
|
15
|
+
* `declared` marks up to date with the code.
|
|
16
|
+
*
|
|
17
|
+
* The sync is deliberate: the marks are otherwise only as fresh as the last app
|
|
18
|
+
* boot, so an audit run straight after a code change would report stale
|
|
19
|
+
* answers. It is safe to do here because syncing is purely additive — it
|
|
20
|
+
* upserts and marks, and never deletes a scope or revokes a grant.
|
|
21
|
+
*/
|
|
22
|
+
export declare const openScopeService: ({ config, logger, }: {
|
|
23
|
+
config: {
|
|
24
|
+
rootDir: string;
|
|
25
|
+
outDir: string;
|
|
26
|
+
runtimeDir?: string;
|
|
27
|
+
srcDirectories: string[];
|
|
28
|
+
};
|
|
29
|
+
logger: Logger;
|
|
30
|
+
}, declared: FlatScope[], command: string) => Promise<OpenedScopeService | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Renders undeclared scopes and the roles that would lose them — the blast
|
|
33
|
+
* radius, shown before anything is deleted.
|
|
34
|
+
*/
|
|
35
|
+
export declare const reportStaleScopes: (stale: Array<{
|
|
36
|
+
scope: string;
|
|
37
|
+
roles: string[];
|
|
38
|
+
}>, logger: Logger) => void;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { flattenScopeDefinitions } from '@pikku/core/scope';
|
|
3
|
+
import { KyselyScopeService } from '@pikku/kysely';
|
|
4
|
+
import { createKysely, resolveDb } from '../db/local-db.js';
|
|
5
|
+
import { loadUserConfigForDb } from './db-shared.js';
|
|
6
|
+
/**
|
|
7
|
+
* Reads the generated scope metadata and flattens it to the declared scope set.
|
|
8
|
+
*
|
|
9
|
+
* Returns `null` — never an empty array — when the file cannot be read, so a
|
|
10
|
+
* caller can tell "nothing is declared" apart from "we failed to find out".
|
|
11
|
+
* `prune` deletes everything not in this set, so conflating the two would wipe
|
|
12
|
+
* every scope in the database.
|
|
13
|
+
*/
|
|
14
|
+
const isScopeDefinitionsMeta = (value) => typeof value === 'object' &&
|
|
15
|
+
value !== null &&
|
|
16
|
+
!Array.isArray(value) &&
|
|
17
|
+
Object.values(value).every((def) => typeof def === 'object' &&
|
|
18
|
+
def !== null &&
|
|
19
|
+
!Array.isArray(def) &&
|
|
20
|
+
typeof def.name === 'string');
|
|
21
|
+
export const loadDeclaredScopes = async (scopesMetaJsonFile, logger) => {
|
|
22
|
+
let parsed;
|
|
23
|
+
try {
|
|
24
|
+
parsed = JSON.parse(await readFile(scopesMetaJsonFile, 'utf8'));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
logger.error(`pikku scopes: no scope metadata at ${scopesMetaJsonFile}.\n` +
|
|
28
|
+
` Run \`pikku all\` to generate it.`);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
if (!isScopeDefinitionsMeta(parsed)) {
|
|
32
|
+
logger.error(`pikku scopes: the scope metadata at ${scopesMetaJsonFile} is malformed.\n` +
|
|
33
|
+
` Run \`pikku all\` to regenerate it.`);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return flattenScopeDefinitions(Object.values(parsed));
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Opens a ScopeService against the project's configured database and brings the
|
|
40
|
+
* `declared` marks up to date with the code.
|
|
41
|
+
*
|
|
42
|
+
* The sync is deliberate: the marks are otherwise only as fresh as the last app
|
|
43
|
+
* boot, so an audit run straight after a code change would report stale
|
|
44
|
+
* answers. It is safe to do here because syncing is purely additive — it
|
|
45
|
+
* upserts and marks, and never deletes a scope or revokes a grant.
|
|
46
|
+
*/
|
|
47
|
+
export const openScopeService = async ({ config, logger, }, declared, command) => {
|
|
48
|
+
const userConfig = await loadUserConfigForDb({
|
|
49
|
+
config,
|
|
50
|
+
logger,
|
|
51
|
+
});
|
|
52
|
+
if (!userConfig) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const resolved = resolveDb(userConfig, config.rootDir, config.outDir, config.runtimeDir);
|
|
56
|
+
if (!resolved) {
|
|
57
|
+
logger.error(`${command}: no database configured — set sqliteDb or postgresUrl in your createConfig.`);
|
|
58
|
+
throw new Error('no database configured');
|
|
59
|
+
}
|
|
60
|
+
const db = await createKysely(resolved);
|
|
61
|
+
try {
|
|
62
|
+
const service = new KyselyScopeService(db);
|
|
63
|
+
await service.init();
|
|
64
|
+
await service.syncScopes(declared);
|
|
65
|
+
return { service, destroy: () => db.destroy() };
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
await db.destroy();
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Renders undeclared scopes and the roles that would lose them — the blast
|
|
74
|
+
* radius, shown before anything is deleted.
|
|
75
|
+
*/
|
|
76
|
+
export const reportStaleScopes = (stale, logger) => {
|
|
77
|
+
for (const { scope, roles } of stale) {
|
|
78
|
+
const held = roles.length > 0
|
|
79
|
+
? `held by ${roles.length} role(s): ${roles.join(', ')}`
|
|
80
|
+
: 'held by no role';
|
|
81
|
+
logger.info(` ${scope.padEnd(40)} ${held}`);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join, resolve } from 'path';
|
|
2
2
|
import { pikkuSessionlessFunc } from '#pikku';
|
|
3
|
-
import { ConsoleLogger, LocalEmailService, InMemoryQueueService, InMemoryWorkflowService, InMemoryTriggerService, InMemoryAIRunStateService, } from '@pikku/core/services';
|
|
3
|
+
import { ConsoleLogger, LocalEmailService, InMemoryQueueService, InMemoryWorkflowService, InMemoryTriggerService, InMemoryAIRunStateService, QueueWebhookService, } from '@pikku/core/services';
|
|
4
4
|
import { KyselyAIStorageService, KyselyAIRunStateService, KyselyAgentRunService, } from '@pikku/kysely';
|
|
5
5
|
import { stopSingletonServices } from '@pikku/core';
|
|
6
6
|
import { pikkuState } from '@pikku/core/internal';
|
|
@@ -81,13 +81,15 @@ export const serve = pikkuSessionlessFunc({
|
|
|
81
81
|
})
|
|
82
82
|
: undefined;
|
|
83
83
|
const eventHub = await devServerRunner.createEventHub();
|
|
84
|
+
const serveQueueService = new InMemoryQueueService();
|
|
84
85
|
const inMemoryServices = {
|
|
85
86
|
logger: devLogger,
|
|
86
87
|
...(aiAgentRunner ? { aiAgentRunner } : {}),
|
|
87
88
|
emailService: new LocalEmailService(),
|
|
88
89
|
metaService: new LocalMetaService(pikkuDir),
|
|
89
90
|
schedulerService,
|
|
90
|
-
queueService:
|
|
91
|
+
queueService: serveQueueService,
|
|
92
|
+
webhookService: new QueueWebhookService(serveQueueService),
|
|
91
93
|
workflowService,
|
|
92
94
|
workflowRunService: workflowService,
|
|
93
95
|
triggerService: new InMemoryTriggerService(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readdir, readFile, mkdir, writeFile } from 'fs/promises';
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
|
-
import { join, dirname } from 'path';
|
|
3
|
+
import { join, dirname, sep } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { pikkuSessionlessFunc } from '#pikku';
|
|
6
6
|
/**
|
|
@@ -46,6 +46,17 @@ async function copyDir(src, dest) {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Where each supported agent reads project-local skills from, relative to the
|
|
51
|
+
* project root. `pi` mirrors pi.dev's own resolution: it scans
|
|
52
|
+
* `<cwd>/<CONFIG_DIR_NAME>/skills` for project skills, where CONFIG_DIR_NAME
|
|
53
|
+
* defaults to `.pi`.
|
|
54
|
+
*/
|
|
55
|
+
const AGENT_SKILL_DIRS = {
|
|
56
|
+
claude: join('.claude', 'skills'),
|
|
57
|
+
opencode: join('.opencode', 'skills'),
|
|
58
|
+
pi: join('.pi', 'skills'),
|
|
59
|
+
};
|
|
49
60
|
function parseInstallGroups(frontmatter) {
|
|
50
61
|
const inline = frontmatter.match(/^\s*installGroups\s*:\s*\[([^\]]*)\]/m);
|
|
51
62
|
if (inline) {
|
|
@@ -113,10 +124,8 @@ export const pikkuSkillsList = pikkuSessionlessFunc({
|
|
|
113
124
|
.map((e) => e.name)
|
|
114
125
|
.sort();
|
|
115
126
|
const installed = new Set();
|
|
116
|
-
for (const
|
|
117
|
-
join(process.cwd(),
|
|
118
|
-
join(process.cwd(), '.opencode', 'skills'),
|
|
119
|
-
]) {
|
|
127
|
+
for (const relative of Object.values(AGENT_SKILL_DIRS)) {
|
|
128
|
+
const dir = join(process.cwd(), relative);
|
|
120
129
|
if (existsSync(dir)) {
|
|
121
130
|
for (const e of await readdir(dir, { withFileTypes: true })) {
|
|
122
131
|
if (e.isDirectory() || e.isSymbolicLink())
|
|
@@ -133,11 +142,12 @@ export const pikkuSkillsList = pikkuSessionlessFunc({
|
|
|
133
142
|
console.log('Run `pikku skills install` to copy them into .claude/skills/');
|
|
134
143
|
console.log('Run `pikku skills install --core --fabric` to install the Fabric sandbox skill set.');
|
|
135
144
|
console.log('Run `pikku skills install --agent opencode` to copy them into .opencode/skills/');
|
|
145
|
+
console.log('Run `pikku skills install --agent pi` to copy them into .pi/skills/');
|
|
136
146
|
},
|
|
137
147
|
});
|
|
138
148
|
export const pikkuSkillsInstall = pikkuSessionlessFunc({
|
|
139
149
|
func: async ({ logger }, { agent = 'claude', only, core = false, fabric = false, update = false }) => {
|
|
140
|
-
const supportedAgents =
|
|
150
|
+
const supportedAgents = Object.keys(AGENT_SKILL_DIRS);
|
|
141
151
|
if (!supportedAgents.includes(agent)) {
|
|
142
152
|
logger.error(`Agent "${agent}" is not yet supported. Supported: ${supportedAgents.join(', ')}. ` +
|
|
143
153
|
`(codex/gemini will emit AGENTS.md/GEMINI.md from the same source — coming soon.)`);
|
|
@@ -160,9 +170,7 @@ export const pikkuSkillsInstall = pikkuSessionlessFunc({
|
|
|
160
170
|
process.exitCode = 1;
|
|
161
171
|
return;
|
|
162
172
|
}
|
|
163
|
-
const installRoot = agent
|
|
164
|
-
? join(process.cwd(), '.opencode', 'skills')
|
|
165
|
-
: join(process.cwd(), '.claude', 'skills');
|
|
173
|
+
const installRoot = join(process.cwd(), AGENT_SKILL_DIRS[agent]);
|
|
166
174
|
await mkdir(installRoot, { recursive: true });
|
|
167
175
|
let installed = 0;
|
|
168
176
|
let skipped = 0;
|
|
@@ -176,7 +184,7 @@ export const pikkuSkillsInstall = pikkuSessionlessFunc({
|
|
|
176
184
|
await copyDir(src, dest);
|
|
177
185
|
installed++;
|
|
178
186
|
}
|
|
179
|
-
const destLabel = agent
|
|
187
|
+
const destLabel = `${AGENT_SKILL_DIRS[agent].split(sep).join('/')}/`;
|
|
180
188
|
logger.info(`Installed ${installed} skill(s) into ${destLabel}${skipped > 0
|
|
181
189
|
? ` (skipped ${skipped} already present — pass --update to overwrite)`
|
|
182
190
|
: ''}`);
|
|
@@ -17,12 +17,13 @@ import type { AgentMap } from '${agentMapImportPath}'
|
|
|
17
17
|
type AIAgentConfig<
|
|
18
18
|
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
19
19
|
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
20
|
-
> = Omit<CoreAIAgent<PikkuPermission, PikkuMiddleware>, 'tools' | 'agents' | 'memory' | 'input' | 'output'> & {
|
|
20
|
+
> = Omit<CoreAIAgent<PikkuPermission, PikkuMiddleware>, 'tools' | 'agents' | 'workflows' | 'memory' | 'input' | 'output'> & {
|
|
21
21
|
input?: InputSchema
|
|
22
22
|
output?: OutputSchema
|
|
23
23
|
memory?: Omit<AIAgentMemoryConfig, 'workingMemory'> & { workingMemory?: StandardSchemaV1 }
|
|
24
24
|
tools?: object[]
|
|
25
25
|
agents?: AIAgentConfig<StandardSchemaV1 | undefined, StandardSchemaV1 | undefined>[]
|
|
26
|
+
workflows?: object[]
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export const pikkuAIAgent = <
|
|
@@ -98,6 +98,12 @@ export const consoleRoutes = defineHTTPRoutes({
|
|
|
98
98
|
},
|
|
99
99
|
})
|
|
100
100
|
|
|
101
|
+
// The console addon's functions have no authorization of their own. An app
|
|
102
|
+
// gates the whole privileged surface (credential read/write, source editing,
|
|
103
|
+
// package install) with a single package-scoped global permission —
|
|
104
|
+
// addGlobalPermission([isAdmin], '@pikku/addon-console') — which is resolved in
|
|
105
|
+
// the addon's package namespace, so it applies to every one of its functions at
|
|
106
|
+
// once. Apps that don't register one are unaffected (no globals => allow).
|
|
101
107
|
wireAddon({ name: 'console', package: '@pikku/addon-console' })
|
|
102
108
|
wireHTTPRoutes({ basePath: '${globalHTTPPrefix}', routes: { console: consoleRoutes } })
|
|
103
109
|
`;
|
|
@@ -7,6 +7,7 @@ export const serializeCredentialsTypes = ({ definitions, schemaLookup, credentia
|
|
|
7
7
|
let needsZod = false;
|
|
8
8
|
const mapEntries = [];
|
|
9
9
|
const metaEntries = [];
|
|
10
|
+
const oauth2Entries = [];
|
|
10
11
|
for (const [name, meta] of credentialEntries) {
|
|
11
12
|
if (meta.schema && typeof meta.schema === 'string') {
|
|
12
13
|
const schemaRef = schemaLookup.get(meta.schema);
|
|
@@ -26,12 +27,19 @@ export const serializeCredentialsTypes = ({ definitions, schemaLookup, credentia
|
|
|
26
27
|
];
|
|
27
28
|
if (meta.oauth2) {
|
|
28
29
|
metaParts.push(`oauth2: true`);
|
|
30
|
+
// `type` rides along so consumers can tell a platform-wide credential from
|
|
31
|
+
// a per-user one without a second lookup — they own different accounts.
|
|
32
|
+
const config = JSON.stringify({ ...meta.oauth2, type: meta.type }, null, 2).replace(/\n/g, '\n ');
|
|
33
|
+
oauth2Entries.push(` '${name}': ${config}`);
|
|
29
34
|
}
|
|
30
35
|
metaEntries.push(` '${name}': { ${metaParts.join(', ')} }`);
|
|
31
36
|
}
|
|
32
37
|
const imports = [];
|
|
33
38
|
imports.push(`import { TypedCredentialService as CoreTypedCredentialService, type CredentialMetaInfo } from '@pikku/core/services'`);
|
|
34
39
|
imports.push(`import type { CredentialService } from '@pikku/core/services'`);
|
|
40
|
+
if (oauth2Entries.length > 0) {
|
|
41
|
+
imports.push(`import type { OAuth2CredentialConfig } from '@pikku/core/secret'`);
|
|
42
|
+
}
|
|
35
43
|
if (needsZod) {
|
|
36
44
|
imports.push(`import type { z } from 'zod'`);
|
|
37
45
|
}
|
|
@@ -40,6 +48,19 @@ export const serializeCredentialsTypes = ({ definitions, schemaLookup, credentia
|
|
|
40
48
|
const vars = Array.from(variableNames).join(', ');
|
|
41
49
|
imports.push(`import { ${vars} } from '${importPath}'`);
|
|
42
50
|
}
|
|
51
|
+
const oauth2Configs = oauth2Entries.length > 0
|
|
52
|
+
? `
|
|
53
|
+
export const CREDENTIAL_OAUTH2_CONFIGS = {
|
|
54
|
+
${oauth2Entries.join(',\n')}
|
|
55
|
+
} satisfies Record<
|
|
56
|
+
string,
|
|
57
|
+
OAuth2CredentialConfig & {
|
|
58
|
+
appCredentialSecretId: string
|
|
59
|
+
type: 'singleton' | 'wire'
|
|
60
|
+
}
|
|
61
|
+
>
|
|
62
|
+
`
|
|
63
|
+
: '';
|
|
43
64
|
return `${imports.join('\n')}
|
|
44
65
|
|
|
45
66
|
export interface CredentialsMap {
|
|
@@ -51,6 +72,7 @@ export type CredentialName = keyof CredentialsMap
|
|
|
51
72
|
const CREDENTIALS_META: Record<string, CredentialMetaInfo> = {
|
|
52
73
|
${metaEntries.join(',\n')}
|
|
53
74
|
}
|
|
75
|
+
${oauth2Configs}
|
|
54
76
|
|
|
55
77
|
export class TypedCredentialService extends CoreTypedCredentialService<CredentialsMap> {
|
|
56
78
|
constructor(credentials: CredentialService) {
|
|
@@ -22,7 +22,7 @@ export const pikkuFunctionTypesSplit = pikkuSessionlessFunc({
|
|
|
22
22
|
const configTypeImport = pikkuConfigType
|
|
23
23
|
? `import type { ${pikkuConfigType.type} } from '${getFileImportRelativePath(functionTypesFile, pikkuConfigType.typePath, packageMappings)}'`
|
|
24
24
|
: '// Config type not found, will use fallback';
|
|
25
|
-
const content = serializeFunctionTypes(`import type { ${userSessionType.type} } from '${getFileImportRelativePath(functionTypesFile, userSessionType.typePath, packageMappings)}'`, userSessionType.type, `import type { ${singletonServicesType.type} } from '${getFileImportRelativePath(functionTypesFile, singletonServicesType.typePath, packageMappings)}'`, singletonServicesType.type, `import type { ${wireServicesType.type} } from '${getFileImportRelativePath(functionTypesFile, wireServicesType.typePath, packageMappings)}'`, wireServicesType.type, `import type { TypedPikkuRPC, FlattenedRPCMap } from '${getFileImportRelativePath(functionTypesFile, rpcInternalMapDeclarationFile, packageMappings)}'`, `import type { RequiredSingletonServices, RequiredWireServices } from '${getFileImportRelativePath(functionTypesFile, servicesFile, packageMappings)}'`, configTypeImport, config.addonName, undefined, typeof config.addon === 'object' ? config.addon?.categories : undefined);
|
|
25
|
+
const content = serializeFunctionTypes(`import type { ${userSessionType.type} } from '${getFileImportRelativePath(functionTypesFile, userSessionType.typePath, packageMappings)}'`, userSessionType.type, `import type { ${singletonServicesType.type} } from '${getFileImportRelativePath(functionTypesFile, singletonServicesType.typePath, packageMappings)}'`, singletonServicesType.type, `import type { ${wireServicesType.type} } from '${getFileImportRelativePath(functionTypesFile, wireServicesType.typePath, packageMappings)}'`, wireServicesType.type, `import type { TypedPikkuRPC, FlattenedRPCMap } from '${getFileImportRelativePath(functionTypesFile, rpcInternalMapDeclarationFile, packageMappings)}'`, `import type { RequiredSingletonServices, RequiredWireServices } from '${getFileImportRelativePath(functionTypesFile, servicesFile, packageMappings)}'`, configTypeImport, config.addonName, undefined, typeof config.addon === 'object' ? config.addon?.categories : undefined, `import type { ScopeId } from '${getFileImportRelativePath(functionTypesFile, config.scopesFile, packageMappings)}'`);
|
|
26
26
|
const addonRefs = serializeAddonRefs({
|
|
27
27
|
addonHttp: visitState.exportedContracts.addonHttp,
|
|
28
28
|
addonChannel: visitState.exportedContracts.addonChannel,
|
|
@@ -6,7 +6,7 @@ import { serializePikkuTypesHub } from './serialize-pikku-types-hub.js';
|
|
|
6
6
|
import { projectDeclaresBetterAuth } from '../../../utils/detect-better-auth.js';
|
|
7
7
|
export const pikkuFunctionTypes = pikkuSessionlessFunc({
|
|
8
8
|
func: async ({ logger, config, getInspectorState }, data) => {
|
|
9
|
-
const { typesDeclarationFile: typesFile, packageMappings, functionTypesFile, httpTypesFile, channelsTypesFile, triggersTypesFile, schedulersTypesFile, queueTypesFile, mcpTypesFile, cliTypesFile, nodeTypesFile, secretTypesFile, addonTypesFile, authTypesFile, } = config;
|
|
9
|
+
const { typesDeclarationFile: typesFile, packageMappings, functionTypesFile, httpTypesFile, channelsTypesFile, triggersTypesFile, schedulersTypesFile, queueTypesFile, mcpTypesFile, cliTypesFile, nodeTypesFile, secretTypesFile, scopeTypesFile, addonTypesFile, authTypesFile, } = config;
|
|
10
10
|
const getImportPath = (file) => config.addon
|
|
11
11
|
? null
|
|
12
12
|
: getFileImportRelativePath(typesFile, file, packageMappings);
|
|
@@ -31,7 +31,7 @@ export const pikkuFunctionTypes = pikkuSessionlessFunc({
|
|
|
31
31
|
const authTypesImportPath = authTypesFile && hasAuth
|
|
32
32
|
? getFileImportRelativePath(typesFile, authTypesFile, packageMappings)
|
|
33
33
|
: null;
|
|
34
|
-
const content = serializePikkuTypesHub(getFileImportRelativePath(typesFile, functionTypesFile, packageMappings), getImportPath(httpTypesFile), getImportPath(channelsTypesFile), getAlwaysImportPath(triggersTypesFile), getImportPath(schedulersTypesFile), getImportPath(queueTypesFile), getImportPath(mcpTypesFile), getImportPath(cliTypesFile), getAlwaysImportPath(nodeTypesFile), getAlwaysImportPath(secretTypesFile), config.addon ? getAlwaysImportPath(addonTypesFile) : null, authTypesImportPath);
|
|
34
|
+
const content = serializePikkuTypesHub(getFileImportRelativePath(typesFile, functionTypesFile, packageMappings), getImportPath(httpTypesFile), getImportPath(channelsTypesFile), getAlwaysImportPath(triggersTypesFile), getImportPath(schedulersTypesFile), getImportPath(queueTypesFile), getImportPath(mcpTypesFile), getImportPath(cliTypesFile), getAlwaysImportPath(nodeTypesFile), getAlwaysImportPath(secretTypesFile), config.addon ? getAlwaysImportPath(addonTypesFile) : null, authTypesImportPath, getAlwaysImportPath(scopeTypesFile));
|
|
35
35
|
await writeFileInDir(logger, typesFile, content);
|
|
36
36
|
},
|
|
37
37
|
middleware: [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generates core function, middleware, and permission type definitions
|
|
3
3
|
*/
|
|
4
|
-
export declare const serializeFunctionTypes: (userSessionTypeImport: string, userSessionTypeName: string, singletonServicesTypeImport: string, singletonServicesTypeName: string, wireServicesTypeImport: string, wireServicesTypeName: string, rpcMapTypeImport: string, requiredServicesTypeImport: string, configTypeImport: string, packageName?: string, workflowTypesImport?: string, nodeCategories?: string[]) => string;
|
|
4
|
+
export declare const serializeFunctionTypes: (userSessionTypeImport: string, userSessionTypeName: string, singletonServicesTypeImport: string, singletonServicesTypeName: string, wireServicesTypeImport: string, wireServicesTypeName: string, rpcMapTypeImport: string, requiredServicesTypeImport: string, configTypeImport: string, packageName?: string, workflowTypesImport?: string, nodeCategories?: string[], scopesTypeImport?: string) => string;
|