diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..f3d2d36b --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +public-hoist-pattern[]=*commandkit* \ No newline at end of file diff --git a/apps/test-bot/src/workflows/greet/steps/greet.step.ts b/apps/test-bot/src/workflows/greet/steps/greet.step.ts index 4b9f9db1..466b60ef 100644 --- a/apps/test-bot/src/workflows/greet/steps/greet.step.ts +++ b/apps/test-bot/src/workflows/greet/steps/greet.step.ts @@ -1,4 +1,3 @@ -import { Logger } from 'commandkit'; import { useClient } from 'commandkit/hooks'; export async function greetUser(userId: string, again = false) { diff --git a/examples/with-workflow/package.json b/examples/with-workflow/package.json index 61814c8d..573fd666 100644 --- a/examples/with-workflow/package.json +++ b/examples/with-workflow/package.json @@ -15,7 +15,7 @@ "typescript": "^5.8.3" }, "dependencies": { - "@commandkit/workflow": "^0", + "@commandkit/workflow": "latest", "commandkit": "^1.2.0-rc.12", "discord.js": "^14.24.0", "workflow": "^4.0.1-beta.12" diff --git a/examples/with-workflow/src/workflows/greet/steps/greet.step.ts b/examples/with-workflow/src/workflows/greet/steps/greet.step.ts index 22280a19..466b60ef 100644 --- a/examples/with-workflow/src/workflows/greet/steps/greet.step.ts +++ b/examples/with-workflow/src/workflows/greet/steps/greet.step.ts @@ -1,9 +1,11 @@ -import { commandkit } from 'commandkit'; +import { useClient } from 'commandkit/hooks'; export async function greetUser(userId: string, again = false) { 'use step'; - const user = await commandkit.client.users.fetch(userId); + const client = useClient(); + + const user = await client.users.fetch(userId); const message = again ? 'Hello again!' : 'Hello!'; diff --git a/packages/commandkit/hooks.cjs b/packages/commandkit/hooks.cjs index 00e9e3c6..d3e750b8 100644 --- a/packages/commandkit/hooks.cjs +++ b/packages/commandkit/hooks.cjs @@ -9,11 +9,18 @@ const { } = require('./dist/app/events/EventWorkerContext.js'); function useAnyEnvironment() { - const commandCtx = getContext(); - if (commandCtx) return commandCtx; + try { + const commandCtx = getContext(); + if (commandCtx) return commandCtx; + } catch {} + + try { + const eventWorkerCtx = getEventWorkerContext(); + if (eventWorkerCtx) return eventWorkerCtx; + } catch {} - const eventWorkerCtx = getEventWorkerContext(); - if (eventWorkerCtx) return eventWorkerCtx; + const maybeCommandKit = getCommandKit(); + if (maybeCommandKit) return { commandkit: maybeCommandKit }; throw new Error( 'No environment found. This hook must be used within a CommandKit environment.', diff --git a/packages/commandkit/src/plugins/plugin-runtime/CommandKitPluginRuntime.ts b/packages/commandkit/src/plugins/plugin-runtime/CommandKitPluginRuntime.ts index 4dd0807d..cb6bf1b2 100644 --- a/packages/commandkit/src/plugins/plugin-runtime/CommandKitPluginRuntime.ts +++ b/packages/commandkit/src/plugins/plugin-runtime/CommandKitPluginRuntime.ts @@ -55,7 +55,10 @@ export class CommandKitPluginRuntime { */ public async preload(plugin: RuntimePlugin) { for (const entrypoint of plugin.preload) { - await import(toFileURL(`${getCurrentDirectory()}/${entrypoint}`)); + const path = entrypoint.startsWith('module:') + ? entrypoint.slice(7) + : toFileURL(`${getCurrentDirectory()}/${entrypoint}`); + await import(path); } } diff --git a/packages/workflow/package.json b/packages/workflow/package.json index 9bcfe729..188fe230 100644 --- a/packages/workflow/package.json +++ b/packages/workflow/package.json @@ -8,6 +8,16 @@ "files": [ "dist" ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./handler": { + "types": "./dist/public-handler.d.ts", + "import": "./dist/public-handler.js" + } + }, "scripts": { "check-types": "tsc --noEmit", "build": "tsc" diff --git a/packages/workflow/src/builder.ts b/packages/workflow/src/builder.ts index 1c30677f..aef4c38d 100644 --- a/packages/workflow/src/builder.ts +++ b/packages/workflow/src/builder.ts @@ -1,6 +1,8 @@ import { BaseBuilder, createBaseBuilderConfig } from '@workflow/builders'; +import { Logger } from 'commandkit'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; export interface LocalBuilderOptions { /** @@ -16,13 +18,13 @@ export interface LocalBuilderOptions { export class LocalBuilder extends BaseBuilder { #outDir: string; public constructor(private options: LocalBuilderOptions) { - const outDir = join(options.outDir, '.compiled-workflows'); + const outDir = join(process.cwd(), options.outDir, '.compiled-workflows'); super({ ...createBaseBuilderConfig({ workingDir: process.cwd(), watch: false, dirs: options.inputPaths.map((path) => - join(process.cwd(), options.outDir, path), + join(process.cwd(), 'src', path), ), }), buildTarget: 'next', // Placeholder, not actually used @@ -34,35 +36,58 @@ export class LocalBuilder extends BaseBuilder { const inputFiles = await this.getInputFiles(); await mkdir(this.#outDir, { recursive: true }); + const workflowPath = join(this.#outDir, 'workflows.js'); + const stepsPath = join(this.#outDir, 'steps.js'); + const webhookPath = join(this.#outDir, 'webhook.js'); + await this.createWorkflowsBundle({ - outfile: join(this.#outDir, 'workflows.js'), + outfile: workflowPath, bundleFinalOutput: false, format: 'esm', inputFiles, }); await this.createStepsBundle({ - outfile: join(this.#outDir, 'steps.js'), + outfile: stepsPath, externalizeNonSteps: true, format: 'esm', inputFiles, }); await this.createWebhookBundle({ - outfile: join(this.#outDir, 'webhook.js'), + outfile: webhookPath, bundle: false, }); - await this.generateHandler(); + await this.generateHandler({ + workflow: workflowPath, + steps: stepsPath, + webhook: webhookPath, + }); } public getHandlerPath(): string { - return join(this.#outDir, 'handler.js'); + return join(import.meta.dirname, 'public-handler.js'); } - private async generateHandler(): Promise { - const handlerPath = this.getHandlerPath(); + private async generateHandler({ + workflow, + steps, + webhook, + }: { + workflow: string; + steps: string; + webhook: string; + }): Promise { + const handlerPath = join(import.meta.dirname, 'handler.js'); const source = await readFile(handlerPath, 'utf-8'); - await writeFile(handlerPath, source); + await writeFile( + this.getHandlerPath(), + source + .replace('{{workflowPath}}', pathToFileURL(workflow).toString()) + .replace('{{stepsPath}}', pathToFileURL(steps).toString()) + .replace('{{webhookPath}}', pathToFileURL(webhook).toString()), + ); + Logger.debug`Generated workflow handler at ${handlerPath}`; } } diff --git a/packages/workflow/src/handler.ts b/packages/workflow/src/handler.ts index b9cec838..e1845540 100644 --- a/packages/workflow/src/handler.ts +++ b/packages/workflow/src/handler.ts @@ -2,9 +2,9 @@ // @ts-nocheck import { Hono } from 'hono'; import { serve } from '@hono/node-server'; -import { POST as WebhookPOST } from './webhook.mjs'; -import { POST as StepPOST } from './steps.mjs'; -import { POST as FlowPOST } from './workflows.mjs'; +import { POST as WebhookPOST } from '{{webhookPath}}'; +import { POST as StepPOST } from '{{stepsPath}}'; +import { POST as FlowPOST } from '{{workflowPath}}'; const app = new Hono(); diff --git a/packages/workflow/src/plugin.ts b/packages/workflow/src/plugin.ts index 55b8f0d8..0147e347 100644 --- a/packages/workflow/src/plugin.ts +++ b/packages/workflow/src/plugin.ts @@ -7,6 +7,6 @@ export class WorkflowPlugin extends RuntimePlugin { public constructor(options: WorkflowPluginOptions) { super(options); - this.preload.add('.compiled-workflows/handler.js'); + this.preload.add('module:@commandkit/workflow/handler'); } } diff --git a/packages/workflow/src/public-handler.ts b/packages/workflow/src/public-handler.ts new file mode 100644 index 00000000..e69de29b