chore: starter template

This commit is contained in:
e2e
2026-07-10 22:04:38 +02:00
commit 0e884ba4f8
157 changed files with 6462 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
/**
* This file was generated by @pikku/cli@0.12.76
*/
export type AgentMap = {}

View File

@@ -0,0 +1,26 @@
/**
* This file was generated by @pikku/cli@0.12.76
*/
// AUTO-GENERATED by pikku CLI — do not edit
import { pikkuBetterAuth as _pikkuBetterAuth } from '@pikku/better-auth'
import type { BetterAuthInstance, PikkuBetterAuthFactory } from '@pikku/better-auth'
import type { SingletonServices } from '../function/pikku-function-types.gen.js'
import { TypedSecretService } from '../secrets/pikku-secrets.gen.js'
import { TypedVariablesService } from '../variables/pikku-variables.gen.js'
type AuthSingletonServices = Omit<SingletonServices, 'secrets' | 'variables'> & {
secrets: TypedSecretService
variables: TypedVariablesService
}
export const pikkuBetterAuth = <I extends BetterAuthInstance>(
factory: (services: AuthSingletonServices) => I | Promise<I>
): PikkuBetterAuthFactory<I> =>
_pikkuBetterAuth((services) =>
factory({
...services,
secrets: new TypedSecretService(services.secrets),
variables: new TypedVariablesService(services.variables),
} as AuthSingletonServices)
)

View File

@@ -0,0 +1,89 @@
/**
* This file was generated by @pikku/cli@0.12.76
*/
/**
* This provides the structure needed for TypeScript to be aware of channels
*/
import type { StubCall } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/stub-tracker'
import type { StubCall } from '/Users/yasser/git/pikku/fabric/templates/starter-template/node_modules/.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/stub-tracker.d.ts'
export type AgentApproveCallerInput = { agentName: string; runId: string; approvals: { toolCallId: string; approved: boolean; }[]; }
export type AgentCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; }
export type AgentResumeCallerInput = { agentName: string; runId: string; toolCallId: string; approved: boolean; }
export type AgentStreamCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; context?: string | undefined; }
export type AuthHandlerOutput = Promise<void> | Promise<any>
export type DeleteAgentThreadInput = { threadId: string; resourceId?: string | undefined; }
export type DeleteAgentThreadOutput = { deleted: boolean; }
export type GetAgentThreadMessagesInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadMessagesOutput = any[]
export type GetAgentThreadRunsInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadRunsOutput = any[]
export type GetAgentThreadsInput = { agentName?: string | undefined; resourceId?: string | undefined; limit?: number | undefined; offset?: number | undefined; }
export type GetAgentThreadsOutput = any[]
export type GetSessionInput = {}
export type GetSessionOutput = {
userId: string;
email: string;
name: string | null;
}
export type GraphStarterInput = { workflowName: string; nodeId: string; data?: unknown; }
export type GraphStarterOutput = { runId: string; }
export type PikkuConsoleGetSecretInput = { secretId: string; }
export type PikkuConsoleGetSecretOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleGetVariableInput = { variableId: string; }
export type PikkuConsoleGetVariableOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleHasSecretInput = { secretId: string; }
export type PikkuConsoleHasSecretOutput = { exists: boolean; }
export type PikkuConsoleSetSecretInput = { secretId: string; value: unknown; }
export type PikkuConsoleSetSecretOutput = { success: boolean; }
export type PikkuConsoleSetVariableInput = { variableId: string; value: unknown; }
export type PikkuConsoleSetVariableOutput = { success: boolean; }
export type PikkuScenarioGetStubCallsInput = { service?: string | undefined; }
export type PikkuScenarioGetStubCallsOutput = StubCall[]
export type PikkuScenarioResetLiveCoverageOutput = { enabled: boolean; }
export type PikkuScenarioResetStubsOutput = { enabled: boolean; }
export type RealtimeEventStreamInput = { topic: string; }
export type RealtimeSubscribeInput = { topic: string; }
export type RealtimeUnsubscribeInput = { topic: string; }
export type RpcCallerInput = { rpcName: string; data?: unknown; }
export type SecretSchema_betterAuthSecret = string
export type SessionHealthScenarioOutput = { email: string; userId: string; }
export type WorkflowRunnerInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterOutput = { runId: string; }
export type WorkflowStatusCheckerInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamFullInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamInput = { workflowName: string; runId: string; }
interface ChannelHandler<I, O> {
input: I;
output: O;
}
export type ChannelsMap = {
readonly 'events': {
readonly routes: {
readonly action: {
readonly subscribe: ChannelHandler<RealtimeSubscribeInput, never>,
readonly unsubscribe: ChannelHandler<RealtimeUnsubscribeInput, never>,
},
},
readonly defaultMessage: never,
},
};
export type ChannelDefaultHandlerOf<Channel extends keyof ChannelsMap> =
ChannelsMap[Channel]['defaultMessage'] extends { input: infer I; output: infer O }
? ChannelHandler<I, O>
: never;
export type ChannelWiringHandlerOf<
Channel extends keyof ChannelsMap,
Route extends keyof ChannelsMap[Channel]['routes'],
Method extends keyof ChannelsMap[Channel]['routes'][Route],
> =
ChannelsMap[Channel]['routes'][Route][Method] extends { input: infer I; output: infer O }
? ChannelHandler<I, O>
: never;

View File

@@ -0,0 +1,141 @@
// Generated by @pikku/cli — do not edit by hand.
// Run `pikku db migrate` to refresh.
// Use this type in db/classifications.ts:
// import type { DbClassificationMap } from './.pikku/db/classification-map.gen.d.ts'
// export const classifications = { ... } satisfies DbClassificationMap
export type ColumnEntry = {
/** Privacy level. Defaults to 'private' when omitted. */
security?: 'public' | 'private' | 'pii' | 'secret' | 'encrypted'
/** Anonymize strategy used by `pikku db anonymize`. */
classification?: 'fake:email' | 'fake:name' | 'hash' | 'keep'
/** Column kind override for codegen coercion + typing. */
kind?: 'date' | 'bool' | 'json' | 'uuid'
/** TypeScript type override, e.g. `string[]` or `MyJson`. Wins over `kind`. */
tsType?: string
/** Zod string-format validator (keeps the TS type as `string`). */
format?: 'email' | 'url' | 'emoji' | 'e164' | 'jwt' | 'cuid' | 'cuid2' | 'ulid' | 'nanoid' | 'base64' | 'base64url' | 'ipv4' | 'ipv6' | 'cidrv4' | 'cidrv6' | 'isoDate' | 'isoTime' | 'isoDatetime' | 'isoDuration'
description?: string
}
export type DbClassificationMap = {
"account": {
"id": ColumnEntry
"account_id": ColumnEntry
"provider_id": ColumnEntry
"user_id": ColumnEntry
"access_token": ColumnEntry
"refresh_token": ColumnEntry
"id_token": ColumnEntry
"access_token_expires_at": ColumnEntry
"refresh_token_expires_at": ColumnEntry
"scope": ColumnEntry
"password": ColumnEntry
"created_at": ColumnEntry
"updated_at": ColumnEntry
}
"ai_message": {
"id": ColumnEntry
"thread_id": ColumnEntry
"role": ColumnEntry
"content": ColumnEntry
"created_at": ColumnEntry
}
"ai_run": {
"run_id": ColumnEntry
"agent_name": ColumnEntry
"thread_id": ColumnEntry
"resource_id": ColumnEntry
"status": ColumnEntry
"error_message": ColumnEntry
"suspend_reason": ColumnEntry
"missing_rpcs": ColumnEntry
"usage_input_tokens": ColumnEntry
"usage_output_tokens": ColumnEntry
"usage_model": ColumnEntry
"created_at": ColumnEntry
"updated_at": ColumnEntry
}
"ai_threads": {
"id": ColumnEntry
"resource_id": ColumnEntry
"title": ColumnEntry
"metadata": ColumnEntry
"created_at": ColumnEntry
"updated_at": ColumnEntry
}
"ai_tool_call": {
"id": ColumnEntry
"thread_id": ColumnEntry
"message_id": ColumnEntry
"run_id": ColumnEntry
"tool_name": ColumnEntry
"args": ColumnEntry
"result": ColumnEntry
"approval_status": ColumnEntry
"approval_type": ColumnEntry
"agent_run_id": ColumnEntry
"display_tool_name": ColumnEntry
"display_args": ColumnEntry
"created_at": ColumnEntry
}
"ai_working_memory": {
"id": ColumnEntry
"scope": ColumnEntry
"data": ColumnEntry
"updated_at": ColumnEntry
}
"audit": {
"audit_id": ColumnEntry
"occurred_at": ColumnEntry
"type": ColumnEntry
"source": ColumnEntry
"outcome": ColumnEntry
"function_id": ColumnEntry
"wire_type": ColumnEntry
"trace_id": ColumnEntry
"transaction_id": ColumnEntry
"query_id": ColumnEntry
"actor_user_id": ColumnEntry
"actor_org_id": ColumnEntry
"tables": ColumnEntry
"changed_cols": ColumnEntry
"event": ColumnEntry
"old": ColumnEntry
"data": ColumnEntry
}
"session": {
"id": ColumnEntry
"expires_at": ColumnEntry
"token": ColumnEntry
"created_at": ColumnEntry
"updated_at": ColumnEntry
"ip_address": ColumnEntry
"user_agent": ColumnEntry
"user_id": ColumnEntry
"impersonated_by": ColumnEntry
}
"user": {
"id": ColumnEntry
"name": ColumnEntry
"email": ColumnEntry
"email_verified": ColumnEntry
"image": ColumnEntry
"created_at": ColumnEntry
"updated_at": ColumnEntry
"actor": ColumnEntry
"role": ColumnEntry
"banned": ColumnEntry
"ban_reason": ColumnEntry
"ban_expires": ColumnEntry
"fabric": ColumnEntry
}
"verification": {
"id": ColumnEntry
"identifier": ColumnEntry
"value": ColumnEntry
"expires_at": ColumnEntry
"created_at": ColumnEntry
"updated_at": ColumnEntry
}
}

View File

@@ -0,0 +1,148 @@
/**
* This file was generated by @pikku/cli@0.12.76
*/
/**
* This provides the structure needed for typescript to be aware of routes and their return types
*/
import type { StubCall } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/stub-tracker'
import type { StreamWorkflowRunInput } from '.bun/@pikku+addon-console@0.12.26+8a6fcc78e6b267a5/node_modules/@pikku/addon-console/dist/.pikku/rpc/pikku-rpc-wirings-map.internal.gen'
import type { WorkflowRunStatus } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/wirings/workflow/workflow.types'
export type AgentApproveCallerInput = { agentName: string; runId: string; approvals: { toolCallId: string; approved: boolean; }[]; }
export type AgentCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; }
export type AgentResumeCallerInput = { agentName: string; runId: string; toolCallId: string; approved: boolean; }
export type AgentStreamCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; context?: string | undefined; }
export type AuthHandlerOutput = Promise<void> | Promise<any>
export type DeleteAgentThreadInput = { threadId: string; resourceId?: string | undefined; }
export type DeleteAgentThreadOutput = { deleted: boolean; }
export type GetAgentThreadMessagesInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadMessagesOutput = any[]
export type GetAgentThreadRunsInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadRunsOutput = any[]
export type GetAgentThreadsInput = { agentName?: string | undefined; resourceId?: string | undefined; limit?: number | undefined; offset?: number | undefined; }
export type GetAgentThreadsOutput = any[]
export type GetSessionInput = {}
export type GetSessionOutput = {
userId: string;
email: string;
name: string | null;
}
export type GraphStarterInput = { workflowName: string; nodeId: string; data?: unknown; }
export type GraphStarterOutput = { runId: string; }
export type PikkuConsoleGetSecretInput = { secretId: string; }
export type PikkuConsoleGetSecretOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleGetVariableInput = { variableId: string; }
export type PikkuConsoleGetVariableOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleHasSecretInput = { secretId: string; }
export type PikkuConsoleHasSecretOutput = { exists: boolean; }
export type PikkuConsoleSetSecretInput = { secretId: string; value: unknown; }
export type PikkuConsoleSetSecretOutput = { success: boolean; }
export type PikkuConsoleSetVariableInput = { variableId: string; value: unknown; }
export type PikkuConsoleSetVariableOutput = { success: boolean; }
export type PikkuScenarioGetStubCallsInput = { service?: string | undefined; }
export type PikkuScenarioGetStubCallsOutput = StubCall[]
export type PikkuScenarioResetLiveCoverageOutput = { enabled: boolean; }
export type PikkuScenarioResetStubsOutput = { enabled: boolean; }
export type RealtimeEventStreamInput = { topic: string; }
export type RealtimeSubscribeInput = { topic: string; }
export type RealtimeUnsubscribeInput = { topic: string; }
export type RpcCallerInput = { rpcName: string; data?: unknown; }
export type SecretSchema_betterAuthSecret = string
export type SessionHealthScenarioOutput = { email: string; userId: string; }
export type WorkflowRunnerInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterOutput = { runId: string; }
export type WorkflowStatusCheckerInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamFullInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamInput = { workflowName: string; runId: string; }
// The '& {}' is a workaround for not directly refering to a type since it confuses typescript
export type AgentCallerInputParams = Pick<AgentCallerInput, 'agentName'> & {}
export type AgentCallerInputBody = Omit<AgentCallerInput, 'agentName'> & {}
export type AgentStreamCallerInputParams = Pick<AgentStreamCallerInput, 'agentName'> & {}
export type AgentStreamCallerInputBody = Omit<AgentStreamCallerInput, 'agentName'> & {}
export type AgentApproveCallerInputParams = Pick<AgentApproveCallerInput, 'agentName'> & {}
export type AgentApproveCallerInputBody = Omit<AgentApproveCallerInput, 'agentName'> & {}
export type AgentResumeCallerInputParams = Pick<AgentResumeCallerInput, 'agentName'> & {}
export type AgentResumeCallerInputBody = Omit<AgentResumeCallerInput, 'agentName'> & {}
export type StreamWorkflowRunInputParams = Pick<StreamWorkflowRunInput, 'runId'> & {}
export type StreamWorkflowRunInputBody = Omit<StreamWorkflowRunInput, 'runId'> & {}
export type RealtimeEventStreamInputParams = Pick<RealtimeEventStreamInput, 'topic'> & {}
export type RealtimeEventStreamInputBody = Omit<RealtimeEventStreamInput, 'topic'> & {}
export type RpcCallerInputParams = Pick<RpcCallerInput, 'rpcName'> & {}
export type RpcCallerInputBody = Omit<RpcCallerInput, 'rpcName'> & {}
export type WorkflowStarterInputParams = Pick<WorkflowStarterInput, 'workflowName'> & {}
export type WorkflowStarterInputBody = Omit<WorkflowStarterInput, 'workflowName'> & {}
export type WorkflowRunnerInputParams = Pick<WorkflowRunnerInput, 'workflowName'> & {}
export type WorkflowRunnerInputBody = Omit<WorkflowRunnerInput, 'workflowName'> & {}
export type WorkflowStatusCheckerInputParams = Pick<WorkflowStatusCheckerInput, 'workflowName' | 'runId'> & {}
export type WorkflowStatusCheckerInputBody = Omit<WorkflowStatusCheckerInput, 'workflowName' | 'runId'> & {}
export type WorkflowStatusStreamInputParams = Pick<WorkflowStatusStreamInput, 'workflowName' | 'runId'> & {}
export type WorkflowStatusStreamInputBody = Omit<WorkflowStatusStreamInput, 'workflowName' | 'runId'> & {}
export type WorkflowStatusStreamFullInputParams = Pick<WorkflowStatusStreamFullInput, 'workflowName' | 'runId'> & {}
export type WorkflowStatusStreamFullInputBody = Omit<WorkflowStatusStreamFullInput, 'workflowName' | 'runId'> & {}
export type GraphStarterInputParams = Pick<GraphStarterInput, 'workflowName' | 'nodeId'> & {}
export type GraphStarterInputBody = Omit<GraphStarterInput, 'workflowName' | 'nodeId'> & {}
interface HTTPWiringHandler<I, O> {
input: I;
output: O;
}
export type HTTPWiringsMap = {
readonly '/api/auth{/*splat}': {
readonly GET: HTTPWiringHandler<null, AuthHandlerOutput>,
readonly POST: HTTPWiringHandler<null, AuthHandlerOutput>,
},
readonly '/workflow-run/:runId/stream': {
readonly GET: HTTPWiringHandler<StreamWorkflowRunInput, null>,
},
readonly '/events/:topic': {
readonly GET: HTTPWiringHandler<RealtimeEventStreamInput, null>,
},
readonly '/workflow/:workflowName/status/:runId': {
readonly GET: HTTPWiringHandler<WorkflowStatusCheckerInput, WorkflowRunStatus>,
},
readonly '/workflow/:workflowName/status/:runId/stream': {
readonly GET: HTTPWiringHandler<WorkflowStatusStreamInput, null>,
},
readonly '/workflow/:workflowName/status/:runId/stream/full': {
readonly GET: HTTPWiringHandler<WorkflowStatusStreamFullInput, null>,
},
readonly '/rpc/agent/:agentName': {
readonly POST: HTTPWiringHandler<AgentCallerInput, null>,
},
readonly '/rpc/agent/:agentName/stream': {
readonly POST: HTTPWiringHandler<AgentStreamCallerInput, null>,
},
readonly '/rpc/agent/:agentName/approve': {
readonly POST: HTTPWiringHandler<AgentApproveCallerInput, null>,
},
readonly '/rpc/agent/:agentName/resume': {
readonly POST: HTTPWiringHandler<AgentResumeCallerInput, null>,
},
readonly '/rpc/:rpcName': {
readonly POST: HTTPWiringHandler<RpcCallerInput, null>,
},
readonly '/workflow/:workflowName/start': {
readonly POST: HTTPWiringHandler<WorkflowStarterInput, WorkflowStarterOutput>,
},
readonly '/workflow/:workflowName/run': {
readonly POST: HTTPWiringHandler<WorkflowRunnerInput, null>,
},
readonly '/workflow/:workflowName/graph/:nodeId': {
readonly POST: HTTPWiringHandler<GraphStarterInput, GraphStarterOutput>,
},
};
export type HTTPWiringHandlerOf<HTTPWiring extends keyof HTTPWiringsMap, Method extends keyof HTTPWiringsMap[HTTPWiring]> =
HTTPWiringsMap[HTTPWiring][Method] extends { input: infer I; output: infer O }
? HTTPWiringHandler<I, O>
: never;
export type HTTPWiringsWithMethod<Method extends string> = {
[HTTPWiring in keyof HTTPWiringsMap]: Method extends keyof HTTPWiringsMap[HTTPWiring] ? HTTPWiring : never;
}[keyof HTTPWiringsMap];

View File

@@ -0,0 +1,168 @@
/**
* This file was generated by @pikku/cli@0.12.76
*/
/**
* This provides the structure needed for typescript to be aware of RPCs and their return types
*/
import type { StubCall } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/stub-tracker'
import type { FunctionCoverageReport } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/v8-coverage-service'
export type AgentApproveCallerInput = { agentName: string; runId: string; approvals: { toolCallId: string; approved: boolean; }[]; }
export type AgentCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; }
export type AgentResumeCallerInput = { agentName: string; runId: string; toolCallId: string; approved: boolean; }
export type AgentStreamCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; context?: string | undefined; }
export type AuthHandlerOutput = Promise<void> | Promise<any>
export type DeleteAgentThreadInput = { threadId: string; resourceId?: string | undefined; }
export type DeleteAgentThreadOutput = { deleted: boolean; }
export type GetAgentThreadMessagesInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadMessagesOutput = any[]
export type GetAgentThreadRunsInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadRunsOutput = any[]
export type GetAgentThreadsInput = { agentName?: string | undefined; resourceId?: string | undefined; limit?: number | undefined; offset?: number | undefined; }
export type GetAgentThreadsOutput = any[]
export type GetSessionInput = {}
export type GetSessionOutput = {
userId: string;
email: string;
name: string | null;
}
export type GraphStarterInput = { workflowName: string; nodeId: string; data?: unknown; }
export type GraphStarterOutput = { runId: string; }
export type PikkuConsoleGetSecretInput = { secretId: string; }
export type PikkuConsoleGetSecretOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleGetVariableInput = { variableId: string; }
export type PikkuConsoleGetVariableOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleHasSecretInput = { secretId: string; }
export type PikkuConsoleHasSecretOutput = { exists: boolean; }
export type PikkuConsoleSetSecretInput = { secretId: string; value: unknown; }
export type PikkuConsoleSetSecretOutput = { success: boolean; }
export type PikkuConsoleSetVariableInput = { variableId: string; value: unknown; }
export type PikkuConsoleSetVariableOutput = { success: boolean; }
export type PikkuScenarioGetStubCallsInput = { service?: string | undefined; }
export type PikkuScenarioGetStubCallsOutput = StubCall[]
export type PikkuScenarioResetLiveCoverageOutput = { enabled: boolean; }
export type PikkuScenarioResetStubsOutput = { enabled: boolean; }
export type RealtimeEventStreamInput = { topic: string; }
export type RealtimeSubscribeInput = { topic: string; }
export type RealtimeUnsubscribeInput = { topic: string; }
export type RpcCallerInput = { rpcName: string; data?: unknown; }
export type SecretSchema_betterAuthSecret = string
export type SessionHealthScenarioOutput = { email: string; userId: string; }
export type WorkflowRunnerInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterOutput = { runId: string; }
export type WorkflowStatusCheckerInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamFullInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamInput = { workflowName: string; runId: string; }
interface RPCHandler<I, O> {
input: I;
output: O;
}
export type RPCMap = {
readonly 'getSession': RPCHandler<GetSessionInput, GetSessionOutput>,
readonly 'getAgentThreads': RPCHandler<GetAgentThreadsInput, GetAgentThreadsOutput>,
readonly 'getAgentThreadMessages': RPCHandler<GetAgentThreadMessagesInput, GetAgentThreadMessagesOutput>,
readonly 'getAgentThreadRuns': RPCHandler<GetAgentThreadRunsInput, GetAgentThreadRunsOutput>,
readonly 'deleteAgentThread': RPCHandler<DeleteAgentThreadInput, DeleteAgentThreadOutput>,
readonly 'pikkuConsoleSetSecret': RPCHandler<PikkuConsoleSetSecretInput, PikkuConsoleSetSecretOutput>,
readonly 'pikkuConsoleGetVariable': RPCHandler<PikkuConsoleGetVariableInput, PikkuConsoleGetVariableOutput>,
readonly 'pikkuConsoleSetVariable': RPCHandler<PikkuConsoleSetVariableInput, PikkuConsoleSetVariableOutput>,
readonly 'pikkuConsoleHasSecret': RPCHandler<PikkuConsoleHasSecretInput, PikkuConsoleHasSecretOutput>,
readonly 'pikkuConsoleGetSecret': RPCHandler<PikkuConsoleGetSecretInput, PikkuConsoleGetSecretOutput>,
readonly 'pikkuScenarioTakeLiveCoverage': RPCHandler<null, FunctionCoverageReport>,
readonly 'pikkuScenarioResetLiveCoverage': RPCHandler<null, PikkuScenarioResetLiveCoverageOutput>,
readonly 'pikkuScenarioResetStubs': RPCHandler<null, PikkuScenarioResetStubsOutput>,
readonly 'pikkuScenarioGetStubCalls': RPCHandler<PikkuScenarioGetStubCallsInput, PikkuScenarioGetStubCallsOutput>,
};
// Addon package RPC maps
import type { RPCMap as ConsoleRPCMap } from '@pikku/addon-console/.pikku/rpc/pikku-rpc-wirings-map.internal.gen.js'
// Utility type to prefix keys with namespace (skips 'any' to prevent type poisoning)
type PrefixKeys<T, Prefix extends string> = unknown extends T ? {} : {
[K in keyof T as `${Prefix}:${string & K}`]: T[K]
}
// Merge all RPC maps with namespace prefixes
export type FlattenedRPCMap =
RPCMap & PrefixKeys<ConsoleRPCMap, 'console'>
type IsAny<T> = 0 extends (1 & T) ? true : false
type IsVoidishInput<T> = IsAny<T> extends true
? false
: [T] extends [void | null | undefined]
? true
: false
export type RPCInvoke = <Name extends keyof FlattenedRPCMap>(
...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
? [name: Name]
: [name: Name, data: FlattenedRPCMap[Name]['input']]
) => Promise<FlattenedRPCMap[Name]['output']>
export type RPCRemote = <Name extends keyof FlattenedRPCMap>(
...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
? [name: Name]
: [name: Name, data: FlattenedRPCMap[Name]['input']]
) => Promise<FlattenedRPCMap[Name]['output']>
import type { FlattenedWorkflowMap } from '../workflow/pikku-workflow-map.gen.d.js'
import type { AgentMap } from '../agent/pikku-agent-map.gen.d.js'
// Addon package Agent maps
import type { AgentMap as ConsoleAgentMap } from '@pikku/addon-console/.pikku/agent/pikku-agent-map.gen.d.js'
type FlattenedAgentMap =
AgentMap & PrefixKeys<ConsoleAgentMap, 'console'>
import type { PikkuRPC } from '@pikku/core/rpc'
interface AIAgentInput {
message: string
threadId: string
resourceId: string
}
export type TypedStartWorkflow = <Name extends keyof FlattenedWorkflowMap>(
name: Name,
input: FlattenedWorkflowMap[Name]['input'],
options?: { startNode?: string }
) => Promise<{ runId: string }>
export type TypedRunWorkflow = <Name extends keyof FlattenedWorkflowMap>(
name: Name,
input: FlattenedWorkflowMap[Name]['input']
) => Promise<FlattenedWorkflowMap[Name]['output']>
export type TypedWorkflowStatus = (
workflowName: string,
runId: string
) => Promise<{ id: string; status: 'running' | 'suspended' | 'completed' | 'failed' | 'cancelled'; output?: unknown; error?: { message?: string } }>
type TypedAgentRun = [keyof FlattenedAgentMap] extends [never]
? (name: string, input: AIAgentInput) => Promise<any>
: <Name extends keyof FlattenedAgentMap>(
name: Name,
input: AIAgentInput
) => Promise<{ runId: string; result: FlattenedAgentMap[Name]['output']; usage: { inputTokens: number; outputTokens: number } }>
type TypedAgentStream = [keyof FlattenedAgentMap] extends [never]
? (name: string, input: AIAgentInput, options?: { requiresToolApproval?: 'all' | 'explicit' | false }) => Promise<void>
: <Name extends keyof FlattenedAgentMap>(
name: Name,
input: AIAgentInput,
options?: { requiresToolApproval?: 'all' | 'explicit' | false }
) => Promise<void>
export type TypedPikkuRPC = PikkuRPC<RPCInvoke, RPCRemote, TypedStartWorkflow, TypedAgentRun, TypedAgentStream>

View File

@@ -0,0 +1,185 @@
/**
* This file was generated by @pikku/cli@0.12.76
*/
/**
* This provides the structure needed for typescript to be aware of RPCs and their return types
*/
import type { StubCall } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/stub-tracker'
import type { FunctionCoverageReport } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/v8-coverage-service'
import type { WorkflowRunStatus } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/wirings/workflow/workflow.types'
export type AgentApproveCallerInput = { agentName: string; runId: string; approvals: { toolCallId: string; approved: boolean; }[]; }
export type AgentCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; }
export type AgentResumeCallerInput = { agentName: string; runId: string; toolCallId: string; approved: boolean; }
export type AgentStreamCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; context?: string | undefined; }
export type AuthHandlerOutput = Promise<void> | Promise<any>
export type DeleteAgentThreadInput = { threadId: string; resourceId?: string | undefined; }
export type DeleteAgentThreadOutput = { deleted: boolean; }
export type GetAgentThreadMessagesInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadMessagesOutput = any[]
export type GetAgentThreadRunsInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadRunsOutput = any[]
export type GetAgentThreadsInput = { agentName?: string | undefined; resourceId?: string | undefined; limit?: number | undefined; offset?: number | undefined; }
export type GetAgentThreadsOutput = any[]
export type GetSessionInput = {}
export type GetSessionOutput = {
userId: string;
email: string;
name: string | null;
}
export type GraphStarterInput = { workflowName: string; nodeId: string; data?: unknown; }
export type GraphStarterOutput = { runId: string; }
export type PikkuConsoleGetSecretInput = { secretId: string; }
export type PikkuConsoleGetSecretOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleGetVariableInput = { variableId: string; }
export type PikkuConsoleGetVariableOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleHasSecretInput = { secretId: string; }
export type PikkuConsoleHasSecretOutput = { exists: boolean; }
export type PikkuConsoleSetSecretInput = { secretId: string; value: unknown; }
export type PikkuConsoleSetSecretOutput = { success: boolean; }
export type PikkuConsoleSetVariableInput = { variableId: string; value: unknown; }
export type PikkuConsoleSetVariableOutput = { success: boolean; }
export type PikkuScenarioGetStubCallsInput = { service?: string | undefined; }
export type PikkuScenarioGetStubCallsOutput = StubCall[]
export type PikkuScenarioResetLiveCoverageOutput = { enabled: boolean; }
export type PikkuScenarioResetStubsOutput = { enabled: boolean; }
export type RealtimeEventStreamInput = { topic: string; }
export type RealtimeSubscribeInput = { topic: string; }
export type RealtimeUnsubscribeInput = { topic: string; }
export type RpcCallerInput = { rpcName: string; data?: unknown; }
export type SecretSchema_betterAuthSecret = string
export type SessionHealthScenarioOutput = { email: string; userId: string; }
export type WorkflowRunnerInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterOutput = { runId: string; }
export type WorkflowStatusCheckerInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamFullInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamInput = { workflowName: string; runId: string; }
interface RPCHandler<I, O> {
input: I;
output: O;
}
export type RPCMap = {
readonly 'getSession': RPCHandler<GetSessionInput, GetSessionOutput>,
readonly 'sessionHealthScenario': RPCHandler<null, SessionHealthScenarioOutput>,
readonly 'agentCaller': RPCHandler<AgentCallerInput, null>,
readonly 'agentStreamCaller': RPCHandler<AgentStreamCallerInput, null>,
readonly 'agentApproveCaller': RPCHandler<AgentApproveCallerInput, null>,
readonly 'agentResumeCaller': RPCHandler<AgentResumeCallerInput, null>,
readonly 'getAgentThreads': RPCHandler<GetAgentThreadsInput, GetAgentThreadsOutput>,
readonly 'getAgentThreadMessages': RPCHandler<GetAgentThreadMessagesInput, GetAgentThreadMessagesOutput>,
readonly 'getAgentThreadRuns': RPCHandler<GetAgentThreadRunsInput, GetAgentThreadRunsOutput>,
readonly 'deleteAgentThread': RPCHandler<DeleteAgentThreadInput, DeleteAgentThreadOutput>,
readonly 'authHandler': RPCHandler<null, AuthHandlerOutput>,
readonly 'pikkuConsoleSetSecret': RPCHandler<PikkuConsoleSetSecretInput, PikkuConsoleSetSecretOutput>,
readonly 'pikkuConsoleGetVariable': RPCHandler<PikkuConsoleGetVariableInput, PikkuConsoleGetVariableOutput>,
readonly 'pikkuConsoleSetVariable': RPCHandler<PikkuConsoleSetVariableInput, PikkuConsoleSetVariableOutput>,
readonly 'pikkuConsoleHasSecret': RPCHandler<PikkuConsoleHasSecretInput, PikkuConsoleHasSecretOutput>,
readonly 'pikkuConsoleGetSecret': RPCHandler<PikkuConsoleGetSecretInput, PikkuConsoleGetSecretOutput>,
readonly 'realtimeSubscribe': RPCHandler<RealtimeSubscribeInput, null>,
readonly 'realtimeUnsubscribe': RPCHandler<RealtimeUnsubscribeInput, null>,
readonly 'realtimeEventStream': RPCHandler<RealtimeEventStreamInput, null>,
readonly 'rpcCaller': RPCHandler<RpcCallerInput, null>,
readonly 'pikkuScenarioTakeLiveCoverage': RPCHandler<null, FunctionCoverageReport>,
readonly 'pikkuScenarioResetLiveCoverage': RPCHandler<null, PikkuScenarioResetLiveCoverageOutput>,
readonly 'pikkuScenarioResetStubs': RPCHandler<null, PikkuScenarioResetStubsOutput>,
readonly 'pikkuScenarioGetStubCalls': RPCHandler<PikkuScenarioGetStubCallsInput, PikkuScenarioGetStubCallsOutput>,
readonly 'workflowStarter': RPCHandler<WorkflowStarterInput, WorkflowStarterOutput>,
readonly 'workflowRunner': RPCHandler<WorkflowRunnerInput, null>,
readonly 'workflowStatusChecker': RPCHandler<WorkflowStatusCheckerInput, WorkflowRunStatus>,
readonly 'workflowStatusStream': RPCHandler<WorkflowStatusStreamInput, null>,
readonly 'workflowStatusStreamFull': RPCHandler<WorkflowStatusStreamFullInput, null>,
readonly 'graphStarter': RPCHandler<GraphStarterInput, GraphStarterOutput>,
};
// Addon package RPC maps
import type { RPCMap as ConsoleRPCMap } from '@pikku/addon-console/.pikku/rpc/pikku-rpc-wirings-map.internal.gen.js'
// Utility type to prefix keys with namespace (skips 'any' to prevent type poisoning)
type PrefixKeys<T, Prefix extends string> = unknown extends T ? {} : {
[K in keyof T as `${Prefix}:${string & K}`]: T[K]
}
// Merge all RPC maps with namespace prefixes
export type FlattenedRPCMap =
RPCMap & PrefixKeys<ConsoleRPCMap, 'console'>
type IsAny<T> = 0 extends (1 & T) ? true : false
type IsVoidishInput<T> = IsAny<T> extends true
? false
: [T] extends [void | null | undefined]
? true
: false
export type RPCInvoke = <Name extends keyof FlattenedRPCMap>(
...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
? [name: Name]
: [name: Name, data: FlattenedRPCMap[Name]['input']]
) => Promise<FlattenedRPCMap[Name]['output']>
export type RPCRemote = <Name extends keyof FlattenedRPCMap>(
...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
? [name: Name]
: [name: Name, data: FlattenedRPCMap[Name]['input']]
) => Promise<FlattenedRPCMap[Name]['output']>
import type { FlattenedWorkflowMap } from '../workflow/pikku-workflow-map.gen.d.js'
import type { AgentMap } from '../agent/pikku-agent-map.gen.d.js'
// Addon package Agent maps
import type { AgentMap as ConsoleAgentMap } from '@pikku/addon-console/.pikku/agent/pikku-agent-map.gen.d.js'
type FlattenedAgentMap =
AgentMap & PrefixKeys<ConsoleAgentMap, 'console'>
import type { PikkuRPC } from '@pikku/core/rpc'
interface AIAgentInput {
message: string
threadId: string
resourceId: string
}
export type TypedStartWorkflow = <Name extends keyof FlattenedWorkflowMap>(
name: Name,
input: FlattenedWorkflowMap[Name]['input'],
options?: { startNode?: string }
) => Promise<{ runId: string }>
export type TypedRunWorkflow = <Name extends keyof FlattenedWorkflowMap>(
name: Name,
input: FlattenedWorkflowMap[Name]['input']
) => Promise<FlattenedWorkflowMap[Name]['output']>
export type TypedWorkflowStatus = (
workflowName: string,
runId: string
) => Promise<{ id: string; status: 'running' | 'suspended' | 'completed' | 'failed' | 'cancelled'; output?: unknown; error?: { message?: string } }>
type TypedAgentRun = [keyof FlattenedAgentMap] extends [never]
? (name: string, input: AIAgentInput) => Promise<any>
: <Name extends keyof FlattenedAgentMap>(
name: Name,
input: AIAgentInput
) => Promise<{ runId: string; result: FlattenedAgentMap[Name]['output']; usage: { inputTokens: number; outputTokens: number } }>
type TypedAgentStream = [keyof FlattenedAgentMap] extends [never]
? (name: string, input: AIAgentInput, options?: { requiresToolApproval?: 'all' | 'explicit' | false }) => Promise<void>
: <Name extends keyof FlattenedAgentMap>(
name: Name,
input: AIAgentInput,
options?: { requiresToolApproval?: 'all' | 'explicit' | false }
) => Promise<void>
export type TypedPikkuRPC = PikkuRPC<RPCInvoke, RPCRemote, TypedStartWorkflow, TypedAgentRun, TypedAgentStream>

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"agentName":{"type":"string"},"runId":{"type":"string"},"approvals":{"type":"array","items":{"type":"object","properties":{"toolCallId":{"type":"string"},"approved":{"type":"boolean"}},"required":["toolCallId","approved"],"additionalProperties":false}}},"required":["agentName","runId","approvals"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"agentName":{"type":"string"},"message":{"type":"string"},"threadId":{"type":"string"},"resourceId":{"type":"string"}},"required":["agentName","message","threadId","resourceId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"agentName":{"type":"string"},"runId":{"type":"string"},"toolCallId":{"type":"string"},"approved":{"type":"boolean"}},"required":["agentName","runId","toolCallId","approved"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"agentName":{"type":"string"},"message":{"type":"string"},"threadId":{"type":"string"},"resourceId":{"type":"string"},"context":{"type":"string"}},"required":["agentName","message","threadId","resourceId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"type":"null"},{}],"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"threadId":{"type":"string"},"resourceId":{"type":"string"}},"required":["threadId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"generatedAt":{"type":"string"},"summary":{"type":"object","properties":{"total":{"type":"number"},"covered":{"type":"number"},"partial":{"type":"number"},"uncovered":{"type":"number"},"unknown":{"type":"number"},"overallRatio":{"type":"number"}},"required":["total","covered","partial","uncovered","unknown","overallRatio"],"additionalProperties":false},"functions":{"type":"array","items":{"$ref":"#/definitions/FunctionCoverageEntry"}}},"required":["generatedAt","summary","functions"],"additionalProperties":false,"definitions":{"FunctionCoverageEntry":{"type":"object","properties":{"name":{"type":"string"},"sourceFile":{"type":"string"},"exposed":{"type":"boolean"},"description":{"type":["string","null"]},"coveredLines":{"type":"number"},"totalLines":{"type":"number"},"missedLines":{"type":"array","items":{"type":"number"}},"ratio":{"type":"number"},"status":{"$ref":"#/definitions/CoverageStatus"}},"required":["name","sourceFile","exposed","description","coveredLines","totalLines","missedLines","ratio","status"],"additionalProperties":false},"CoverageStatus":{"type":"string","enum":["covered","partial","uncovered","unknown"]}}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"threadId":{"type":"string"},"resourceId":{"type":"string"}},"required":["threadId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"array","items":{},"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"threadId":{"type":"string"},"resourceId":{"type":"string"}},"required":["threadId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"array","items":{},"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"agentName":{"type":"string"},"resourceId":{"type":"string"},"limit":{"type":"number"},"offset":{"type":"number"}},"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"array","items":{},"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}

View File

@@ -0,0 +1 @@
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"userId":{"type":"string"},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["userId","email","name"],"additionalProperties":false}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"workflowName":{"type":"string"},"nodeId":{"type":"string"},"data":{}},"required":["workflowName","nodeId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"runId":{"type":"string"}},"required":["runId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"secretId":{"type":"string"}},"required":["secretId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"exists":{"type":"boolean"},"value":{}},"required":["exists","value"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"variableId":{"type":"string"}},"required":["variableId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"exists":{"type":"boolean"},"value":{}},"required":["exists","value"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"secretId":{"type":"string"}},"required":["secretId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"exists":{"type":"boolean"}},"required":["exists"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"secretId":{"type":"string"},"value":{}},"required":["secretId","value"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"success":{"type":"boolean"}},"required":["success"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"variableId":{"type":"string"},"value":{}},"required":["variableId","value"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"success":{"type":"boolean"}},"required":["success"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"service":{"type":"string"}},"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"array","items":{"$ref":"#/definitions/StubCall"},"definitions":{"StubCall":{"type":"object","properties":{"service":{"type":"string"},"method":{"type":"string"},"args":{"type":"array","items":{}}},"required":["service","method","args"],"additionalProperties":false}}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"topic":{"type":"string"}},"required":["topic"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"topic":{"type":"string"}},"required":["topic"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"topic":{"type":"string"}},"required":["topic"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"rpcName":{"type":"string"},"data":{}},"required":["rpcName"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"email":{"type":"string"},"userId":{"type":"string"}},"required":["email","userId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"runId":{"type":"string"}},"required":["runId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"id":{"type":"string"},"status":{"$ref":"#/definitions/WorkflowStatus"},"startedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time"},"deterministic":{"type":"boolean"},"plannedSteps":{"type":"array","items":{"$ref":"#/definitions/WorkflowPlannedStep"}},"steps":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"status":{"$ref":"#/definitions/StepStatus"},"duration":{"type":"number"},"attempts":{"type":"number","description":"Number of attempts for this step (1 = first try; > 1 means it retried)."}},"required":["name","status"],"additionalProperties":false}},"output":{},"error":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":false}},"required":["id","status","startedAt","steps"],"additionalProperties":false,"definitions":{"WorkflowStatus":{"type":"string","enum":["running","suspended","completed","failed","cancelled"],"description":"Workflow run status"},"WorkflowPlannedStep":{"type":"object","properties":{"stepName":{"type":"string","description":"Durable step key — matches the runtime step name stored in the DB"},"displayName":{"type":"string","description":"Optional human-readable label for the UI timeline (falls back to stepName)"}},"required":["stepName"],"additionalProperties":false},"StepStatus":{"type":"string","enum":["pending","running","scheduled","succeeded","failed","suspended"],"description":"Workflow step status"}}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"workflowName":{"type":"string"},"data":{}},"required":["workflowName"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"workflowName":{"type":"string"},"data":{}},"required":["workflowName"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"runId":{"type":"string"}},"required":["runId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"workflowName":{"type":"string"},"runId":{"type":"string"}},"required":["workflowName","runId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"workflowName":{"type":"string"},"runId":{"type":"string"}},"required":["workflowName","runId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"workflowName":{"type":"string"},"runId":{"type":"string"}},"required":["workflowName","runId"],"additionalProperties":false,"definitions":{}}

View File

@@ -0,0 +1,97 @@
/**
* This file was generated by @pikku/cli@0.12.76
*/
/**
* Workflow type map with input/output types for each workflow
*/
import type { StubCall } from '.bun/@pikku+core@0.12.57/node_modules/@pikku/core/dist/services/stub-tracker'
export type AgentApproveCallerInput = { agentName: string; runId: string; approvals: { toolCallId: string; approved: boolean; }[]; }
export type AgentCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; }
export type AgentResumeCallerInput = { agentName: string; runId: string; toolCallId: string; approved: boolean; }
export type AgentStreamCallerInput = { agentName: string; message: string; threadId: string; resourceId: string; context?: string | undefined; }
export type AuthHandlerOutput = Promise<void> | Promise<any>
export type DeleteAgentThreadInput = { threadId: string; resourceId?: string | undefined; }
export type DeleteAgentThreadOutput = { deleted: boolean; }
export type GetAgentThreadMessagesInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadMessagesOutput = any[]
export type GetAgentThreadRunsInput = { threadId: string; resourceId?: string | undefined; }
export type GetAgentThreadRunsOutput = any[]
export type GetAgentThreadsInput = { agentName?: string | undefined; resourceId?: string | undefined; limit?: number | undefined; offset?: number | undefined; }
export type GetAgentThreadsOutput = any[]
export type GetSessionInput = {}
export type GetSessionOutput = {
userId: string;
email: string;
name: string | null;
}
export type GraphStarterInput = { workflowName: string; nodeId: string; data?: unknown; }
export type GraphStarterOutput = { runId: string; }
export type PikkuConsoleGetSecretInput = { secretId: string; }
export type PikkuConsoleGetSecretOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleGetVariableInput = { variableId: string; }
export type PikkuConsoleGetVariableOutput = { exists: boolean; value: unknown; }
export type PikkuConsoleHasSecretInput = { secretId: string; }
export type PikkuConsoleHasSecretOutput = { exists: boolean; }
export type PikkuConsoleSetSecretInput = { secretId: string; value: unknown; }
export type PikkuConsoleSetSecretOutput = { success: boolean; }
export type PikkuConsoleSetVariableInput = { variableId: string; value: unknown; }
export type PikkuConsoleSetVariableOutput = { success: boolean; }
export type PikkuScenarioGetStubCallsInput = { service?: string | undefined; }
export type PikkuScenarioGetStubCallsOutput = StubCall[]
export type PikkuScenarioResetLiveCoverageOutput = { enabled: boolean; }
export type PikkuScenarioResetStubsOutput = { enabled: boolean; }
export type RealtimeEventStreamInput = { topic: string; }
export type RealtimeSubscribeInput = { topic: string; }
export type RealtimeUnsubscribeInput = { topic: string; }
export type RpcCallerInput = { rpcName: string; data?: unknown; }
export type SecretSchema_betterAuthSecret = string
export type SessionHealthScenarioOutput = { email: string; userId: string; }
export type WorkflowRunnerInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterInput = { workflowName: string; data?: unknown; }
export type WorkflowStarterOutput = { runId: string; }
export type WorkflowStatusCheckerInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamFullInput = { workflowName: string; runId: string; }
export type WorkflowStatusStreamInput = { workflowName: string; runId: string; }
// Addon package Workflow maps
import type { WorkflowMap as ConsoleWorkflowMap } from '@pikku/addon-console/.pikku/workflow/pikku-workflow-map.gen.d.js'
interface WorkflowHandler<I, O> {
input: I;
output: O;
}
interface GraphNodeHandler<I> {
input: I;
}
export type WorkflowMap = {
readonly 'sessionHealthScenario': WorkflowHandler<void, SessionHealthScenarioOutput>,
};
export type GraphsMap = {
readonly 'sessionHealthScenario': {
readonly 'visitor signs in and reads their session': GraphNodeHandler<GetSessionInput>,
},
};
type PrefixWorkflowKeys<T, Prefix extends string> = unknown extends T ? {} : {
[K in keyof T as `${Prefix}:${string & K}`]: T[K]
}
export type FlattenedWorkflowMap =
WorkflowMap & PrefixWorkflowKeys<ConsoleWorkflowMap, 'console'>
export type WorkflowClient<Name extends keyof FlattenedWorkflowMap> = {
start: (input: FlattenedWorkflowMap[Name]['input']) => Promise<{ runId: string }>;
getRun: <output extends keyof FlattenedWorkflowMap[Name]>(runId: string) => Promise<FlattenedWorkflowMap[Name][output]>;
cancelRun: (runId: string) => Promise<boolean>;
}
export type TypedWorkflowClients = {
[Name in keyof FlattenedWorkflowMap]: WorkflowClient<Name>;
}

View File

@@ -0,0 +1,34 @@
{
"name": "@project/functions",
"version": "0.0.1",
"private": true,
"type": "module",
"imports": {
"#pikku": "./.pikku/pikku-types.gen.ts",
"#pikku/*.gen.js": "./.pikku/*.gen.ts",
"#pikku/*": "./.pikku/*"
},
"scripts": {
"db:types": "pikku db types"
},
"dependencies": {
"@ai-sdk/openai-compatible": "^2.0.48",
"@pikku/addon-console": "^0.12.22",
"@pikku/ai-vercel": "^0.12.7",
"@pikku/better-auth": "^0.12.16",
"@pikku/core": "^0.12.57",
"@pikku/kysely": "^0.13.0",
"@pikku/schema-cfworker": "^0.12.4",
"@standard-schema/spec": "^1.1.0",
"ai": "^6.0.0",
"better-auth": "^1.6.18",
"kysely": "^0.29.0",
"tsx": "^4.21.0",
"zod": "^4.3.6"
},
"devDependencies": {
"@pikku/deploy-standalone": "^0.12.7",
"@types/node": "^22",
"typescript": "^5.9.3"
}
}

View File

@@ -0,0 +1,39 @@
import type { CoreServices, CoreSingletonServices, CoreConfig, CoreUserSession } from '@pikku/core'
import type { AuditLog, EmailService } from '@pikku/core/services'
import type { Kysely } from 'kysely'
import type { DB } from '#pikku/db/schema.gen.js'
import type { TypedSecretService } from '../.pikku/secrets/pikku-secrets.gen.js'
import type { TypedVariablesService } from '../.pikku/variables/pikku-variables.gen.js'
import type { auth } from './auth.js'
export interface UserSession extends CoreUserSession {
userId: string
}
export interface Config extends CoreConfig {
port: number
hostname: string
}
export interface SingletonServices extends CoreSingletonServices<Config> {
variables: TypedVariablesService
secrets: TypedSecretService
kysely: Kysely<DB>
// Resolved Better Auth instance, injected once by the generated pikkuServices
// wrapper from the `auth` factory. Typed as the factory's return so functions
// get better-auth's full server `api`/`handler` surface via DI.
auth: Awaited<ReturnType<typeof auth>>
// Always constructed in services.ts, so declare it REQUIRED here — it is
// optional in CoreSingletonServices, which otherwise makes every emailService
// use read as possibly-undefined and forces needless `!`/guards in functions.
emailService: EmailService
// Per-invocation audit log, ALWAYS returned from createWireServices (see
// services.ts) so general activity logging is available in every function —
// `await auditLog.write({ type, source: 'explicit', metadata })`. Declared
// REQUIRED (like emailService above) so a plain `auditLog.write(...)` doesn't
// read as possibly-undefined and force needless `?.`/guards. A function with
// `audit: true` ADDITIONALLY gets a kysely wrapped to capture every table write.
auditLog: AuditLog
}
export interface Services extends CoreServices<SingletonServices> {}

View File

@@ -0,0 +1,72 @@
import { betterAuth } from 'better-auth'
import { admin } from 'better-auth/plugins'
import { actor, fabric } from '@pikku/better-auth'
import { pikkuBetterAuth } from '#pikku'
/**
* Better Auth configuration — email + password sign-in.
*
* `pikkuBetterAuth` has no side effects: the pikku CLI statically inspects this single
* exported `auth` const and generates the catch-all `/api/auth/**` HTTP wiring,
* the session-bridge middleware, and a `wireSecret` for `BETTER_AUTH_SECRET` (and
* one per social provider, if you add any) — so the auth routes and secret
* requirements flow through normal inspection into the deploy manifest.
*
* The factory runs once when singleton services are built, pulling the secret
* (and the database) off the injected `services`; the resolved instance is then
* available to every function as `services.auth`. Better Auth is given the app's
* own kysely: the CamelCasePlugin maps Better Auth's camelCase field names onto
* the snake_case columns created in db/sqlite/0001-init.sql, keeping the whole DB
* on one naming convention. To offer Google / GitHub / ... add a `socialProviders`
* entry (and a button on the login page) — the CLI will wire its secret too.
*/
// The factory receives the FULL singleton services (emailService, logger, …) —
// destructure whatever you need, e.g. `{ kysely, secrets, emailService }` to wire
// sendResetPassword/verification emails. It runs lazily after all services exist,
// so never re-construct a service here or reach for a dynamic import.
export const auth = pikkuBetterAuth(async ({ kysely, secrets, variables }) => {
const BETTER_AUTH_SECRET = await secrets.getSecret('BETTER_AUTH_SECRET')
// Genuinely optional: unset simply disables /api/auth/sign-in/actor (scenarios
// off for this deployment) — the actor plugin refuses all sign-ins
// without it.
const SCENARIO_ACTOR_SECRET = await secrets
.getSecret('SCENARIO_ACTOR_SECRET')
.catch(() => undefined)
// Fabric operator admin: the RSA public key the control plane's token is
// verified against. The Fabric deployer pushes FABRIC_AUTH_PUBLIC_KEY onto
// every stage; locally it's simply absent, which disables /sign-in/fabric.
// Asymmetric — the app verifies, it can never forge an operator login.
const FABRIC_AUTH_PUBLIC_KEY = await variables.get('FABRIC_AUTH_PUBLIC_KEY')
return betterAuth({
secret: BETTER_AUTH_SECRET,
database: { db: kysely, type: 'sqlite' },
emailAndPassword: { enabled: true },
// Stateless session: CLI splits out betterAuthStatelessSession so non-auth
// units verify the signed cookie instead of bundling better-auth. pikku #737.
session: { cookieCache: { enabled: true } },
advanced: { database: { generateId: 'uuid' } },
// Scenario actors: synthetic users (user.actor = true, see
// db/sqlite/0003-user-actor.sql) signed in by pikkuScenario via
// POST /api/auth/sign-in/actor { email, secret }. Never signs in real users.
//
// admin(): exposes /api/auth/admin/* (listUsers, setRole, impersonateUser,
// …) so an app admin can list and "view as" their end-users — this is what
// the Fabric console's Users tab drives. Adds role/banned/impersonatedBy
// columns (see db/sqlite/0004-admin.sql). No user is an admin by default:
// grant it by setting a user's `role` to 'admin' (or pass
// `adminUserIds: [...]` here) — the admin API refuses non-admins.
//
// fabric(): exposes /api/auth/sign-in/fabric — the Fabric control plane
// mints a short-lived RS256 token and signs in as a synthetic `fabric: true`
// admin operator (db/sqlite/0005-fabric.sql), so the console Users tab can
// list/impersonate real users without the operator being one of them. It
// pairs with admin() and verifies against FABRIC_AUTH_PUBLIC_KEY; missing
// key disables the endpoint.
plugins: [
actor({ secret: SCENARIO_ACTOR_SECRET }),
admin(),
fabric({ publicKey: FABRIC_AUTH_PUBLIC_KEY }),
],
})
})

View File

@@ -0,0 +1,6 @@
import { pikkuConfig } from '../.pikku/pikku-types.gen.js'
export const createConfig = pikkuConfig(async () => ({
port: parseInt(process.env.API_PORT || '4003', 10),
hostname: process.env.HOST || '0.0.0.0',
}))

View File

@@ -0,0 +1,32 @@
import { z } from 'zod'
import { pikkuFunc } from '#pikku'
export const GetSessionInput = z.object({})
export const GetSessionOutput = z.object({
userId: z.string(),
email: z.string().email(),
name: z.string().nullable(),
})
export const getSession = pikkuFunc({
expose: true,
readonly: true,
auth: true,
description: 'Returns the current signed-in user.',
input: GetSessionInput,
output: GetSessionOutput,
func: async ({ kysely }, _input, { session }) => {
const user = await kysely
.selectFrom('user')
.select(['id', 'email', 'name'])
.where('id', '=', session!.userId)
.executeTakeFirstOrThrow()
return {
userId: user.id,
email: user.email,
name: user.name ?? null,
}
},
})

View File

@@ -0,0 +1,33 @@
import { pikkuScenario } from '#pikku/workflow/pikku-workflow-types.gen.js'
/**
* A scenario is a story of RPC calls told through a synthetic persona (an
* "actor" — see scenarios.actors in pikku.config.json). Every step runs over
* the REAL transport with the actor's session cookie, so a passing scenario
* proves the deployed API works exactly as a signed-in user would experience it.
*
* Run it with `pikku scenario run local` (needs SCENARIO_ACTOR_SECRET in the
* environment — the actor plugin in src/auth.ts refuses sign-ins without it).
* This one signs the visitor in and reads their own session: actor sign-in,
* session cookie, authed RPC, and session mapping in one pass — a ready-made
* health check for staging or production.
*/
export const sessionHealthScenario = pikkuScenario<void, { email: string; userId: string }>({
title: 'Session health (scenario)',
tags: ['scenario'],
func: async ({ logger }, _input, { workflow, actors }) => {
if (!actors?.visitor) {
throw new Error(
'sessionHealthScenario needs run actors (visitor) — run via `pikku scenario run <environment>`',
)
}
logger.debug('session-health scenario starting')
const session = await workflow.do(
'visitor signs in and reads their session',
'getSession',
{},
{ actor: actors.visitor },
)
return { email: session.email, userId: session.userId }
},
})

View File

@@ -0,0 +1,52 @@
import {
LocalEmailService,
type EmailService,
type SendEmailInput,
type SendEmailResult,
} from '@pikku/core/services'
import { renderEmailTemplate, type EmailTemplateName } from '../../.pikku/email/pikku-emails.gen.js'
type GeneratedTemplateEmailServiceOptions = {
delegate?: EmailService
defaultLocale?: string
}
export class GeneratedTemplateEmailService implements EmailService {
private readonly delegate: EmailService
private readonly defaultLocale: string
constructor(options: GeneratedTemplateEmailServiceOptions = {}) {
this.delegate = options.delegate ?? new LocalEmailService()
this.defaultLocale = options.defaultLocale ?? 'en'
}
async send(input: SendEmailInput): Promise<SendEmailResult> {
if (!('template' in input) || !input.template) {
return this.delegate.send(input)
}
const rendered = renderEmailTemplate({
name: input.template.name as EmailTemplateName,
locale: (input.template.locale ?? this.defaultLocale) as Parameters<
typeof renderEmailTemplate
>[0]['locale'],
data: input.template.data ?? {},
})
return this.delegate.send({
to: input.to,
from: input.from,
cc: input.cc,
bcc: input.bcc,
replyTo: input.replyTo,
headers: {
...(input.headers ?? {}),
'x-pikku-email-template': String(input.template.name),
'x-pikku-email-hash': rendered.hash,
},
subject: rendered.subject,
html: rendered.html,
...(rendered.text ? { text: rendered.text } : {}),
})
}
}

View File

@@ -0,0 +1,18 @@
import { addHTTPMiddleware } from '@pikku/core/http'
import { cors } from '@pikku/core/middleware'
const corsOrigins = process.env.CORS_ORIGINS
? process.env.CORS_ORIGINS.split(',')
.map((origin) => origin.trim())
.filter(Boolean)
: [process.env.FRONTEND_URL, 'http://localhost:7104', 'http://127.0.0.1:7104'].filter(
(origin): origin is string => Boolean(origin),
)
addHTTPMiddleware('*', [
cors({
origin: corsOrigins,
credentials: true,
headers: ['Content-Type', 'Authorization', 'X-Auth-Return-Redirect'],
}),
])

View File

@@ -0,0 +1,98 @@
import {
JsonConsoleLogger,
LocalEmailService,
LocalSecretService,
LocalVariablesService,
NoopAuditService,
createInvocationAudit,
} from '@pikku/core/services'
import { createAuditedKysely } from '@pikku/kysely'
import { pikkuServices, pikkuWireServices } from '../.pikku/pikku-types.gen.js'
import { TypedSecretService } from '../.pikku/secrets/pikku-secrets.gen.js'
import { TypedVariablesService } from '../.pikku/variables/pikku-variables.gen.js'
import { CFWorkerSchemaService } from '@pikku/schema-cfworker'
import type { Kysely } from 'kysely'
import type { VercelAIAgentRunner } from '@pikku/ai-vercel'
import { GeneratedTemplateEmailService } from './lib/email-service.js'
import type { DB } from '#pikku/db/schema.gen.js'
export const createSingletonServices = pikkuServices(async (config, existingServices) => {
const variables =
existingServices?.variables ?? new TypedVariablesService(new LocalVariablesService())
const secrets =
existingServices?.secrets ?? new TypedSecretService(new LocalSecretService(variables))
const logger = existingServices?.logger ?? new JsonConsoleLogger()
const schema = existingServices?.schema ?? new CFWorkerSchemaService(logger)
const emailService =
existingServices?.emailService ??
new GeneratedTemplateEmailService({
delegate: new LocalEmailService(),
})
// The durable audit sink. In a deployed stage fabric injects the platform's
// audit service; locally it falls back to a no-op so nothing is persisted.
const audit = existingServices?.audit ?? new NoopAuditService()
// kysely is injected by pikku dev (node:sqlite) or the CF Worker workflow (libsql).
// The template never constructs its own dialect — dialects are fabric/runtime
// concerns — so it must always be provided by the runtime.
if (!existingServices?.kysely) {
throw new Error('kysely service was not injected by the runtime (pikku dev / fabric)')
}
const kysely: Kysely<DB> = existingServices.kysely
const litellmProxyUrl = process.env.LITELLM_PROXY_URL ?? null
const litellmApiKey = process.env.LITELLM_API_KEY ?? null
let aiAgentRunner: VercelAIAgentRunner | undefined
if (litellmProxyUrl && litellmApiKey) {
// The AI SDKs (~3MB) are stubbed out of non-agent units at bundle time —
// only units with the `ai-model` capability keep them. So import them
// dynamically and guard on the module resolving to a real export; in a
// stubbed unit the import yields `{}` and the runner is simply not built.
const aiVercel = await import('@pikku/ai-vercel')
const aiSdk = await import('@ai-sdk/openai-compatible')
if (aiVercel.VercelAIAgentRunner && aiSdk.createOpenAICompatible) {
const litellmProvider = aiSdk.createOpenAICompatible({
name: 'litellm',
baseURL: litellmProxyUrl,
apiKey: litellmApiKey,
})
aiAgentRunner = new aiVercel.VercelAIAgentRunner({
openai: (modelId: string) => litellmProvider.chatModel(modelId),
anthropic: (modelId: string) => litellmProvider.chatModel(modelId),
google: (modelId: string) => litellmProvider.chatModel(modelId),
deepseek: (modelId: string) => litellmProvider.chatModel(modelId),
})
}
}
return {
...(existingServices ?? {}),
config,
variables,
secrets,
schema,
logger,
emailService,
audit,
kysely,
...(aiAgentRunner ? { aiAgentRunner } : {}),
}
})
export const createWireServices = pikkuWireServices(async (singletonServices, wire) => {
if (!singletonServices.audit) {
return {}
}
const auditLog = createInvocationAudit(singletonServices.audit, wire)
// auditLog is ALWAYS returned so `auditLog.write(...)` works in every function
// for general activity logging. `auditLog.config` is set ONLY when this
// invocation opts into row-level auditing (`audit: true`); when it is, ALSO wrap
// kysely so every query is captured and the runner flushes the buffer on close.
// Without audit: true, leave the plain kysely untouched — no per-query overhead.
if (!auditLog.config) {
return { auditLog }
}
return {
auditLog,
kysely: createAuditedKysely(singletonServices.kysely, { audit: auditLog }),
}
})