diff --git a/packages/worker/src/mcp/capabilities/error-message.ts b/packages/worker/src/mcp/capabilities/error-message.ts index 881c4455c5..5ba64a7510 100644 --- a/packages/worker/src/mcp/capabilities/error-message.ts +++ b/packages/worker/src/mcp/capabilities/error-message.ts @@ -1,3 +1,35 @@ export function getErrorMessage(error: unknown) { return error instanceof Error ? error.message : String(error) } + +export function getErrorCause(error: unknown) { + if (error && typeof error === 'object' && 'cause' in error) { + return (error as { cause?: unknown }).cause + } + return undefined +} + +export function getErrorCauseChain(error: unknown) { + const chain: Array = [] + const seen = new Set() + let current: unknown = error + while (current !== undefined && !seen.has(current)) { + seen.add(current) + chain.push(current) + current = getErrorCause(current) + } + return chain +} + +export function errorCauseChainIncludes( + error: unknown, + matches: (message: string) => boolean, +) { + return getErrorCauseChain(error).some((entry) => + matches(getErrorMessage(entry)), + ) +} + +export function formatErrorCauseChain(error: unknown) { + return getErrorCauseChain(error).map(getErrorMessage).join(' Caused by: ') +} diff --git a/packages/worker/src/mcp/capabilities/packages/publish-external-push.node.test.ts b/packages/worker/src/mcp/capabilities/packages/publish-external-push.node.test.ts index e01857f30b..55537515fe 100644 --- a/packages/worker/src/mcp/capabilities/packages/publish-external-push.node.test.ts +++ b/packages/worker/src/mcp/capabilities/packages/publish-external-push.node.test.ts @@ -367,6 +367,40 @@ test('rebuilds published package bundle artifacts one target at a time after pub ) }) +test('artifact rebuild failures include the failing target and cause', async () => { + setupDefaultMocks() + const target = { + kind: 'module', + artifactName: '.', + entryPoint: 'src/index.ts', + bundleKind: 'module', + } + mockModule.resolveArtifactSourceHead.mockResolvedValue({ + branch: 'main', + commit: 'commit-new', + }) + mockModule.publishFromExternalRef.mockResolvedValue({ + status: 'published', + previous_commit: 'commit-old', + published_commit: 'commit-new', + manifest: {}, + checks: [{ kind: 'manifest', ok: true, message: 'ok' }], + }) + mockModule.listPublishedPackageArtifactTargets.mockResolvedValue([target]) + mockModule.rebuildPublishedPackageArtifact.mockRejectedValueOnce( + new Error('No matching default export for import "default"'), + ) + + await expect( + publishExternalPushCapability.handler( + { package_id: 'package-1' }, + createContext(), + ), + ).rejects.toThrow( + 'Package source publish succeeded, but bundle artifact rebuild failed for source "source-1" at commit "commit-new" target { kind "module", artifact ".", entry "src/index.ts", bundle "module" }. Cause: No matching default export for import "default". Re-run the publish capability to repair artifacts.', + ) +}) + test('force publish passes destructive confirmation through and refuses without allow_force', async () => { setupDefaultMocks() mockModule.resolveArtifactSourceHead.mockResolvedValue({ @@ -544,6 +578,59 @@ test('publishExternalPush recovers from transient Durable Object resets', async } }) +test('publishExternalPush retries when artifact rebuild wraps a transient Durable Object reset cause', async () => { + setupDefaultMocks() + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined) + const target = { + kind: 'module', + artifactName: '.', + entryPoint: 'src/index.ts', + bundleKind: 'module', + } + mockModule.resolveArtifactSourceHead.mockResolvedValue({ + branch: 'main', + commit: 'commit-new', + }) + mockModule.listPublishedPackageArtifactTargets.mockResolvedValue([target]) + mockModule.publishFromExternalRef + .mockResolvedValueOnce({ + status: 'published', + previous_commit: 'commit-old', + published_commit: 'commit-new', + manifest: {}, + checks: [{ kind: 'manifest', ok: true, message: 'ok' }], + }) + .mockResolvedValueOnce({ + status: 'already_published', + published_commit: 'commit-new', + }) + mockModule.rebuildPublishedPackageArtifact + .mockRejectedValueOnce( + new Error('rebuild target failed', { + cause: new Error('Durable Object exceeded its CPU time limit'), + }), + ) + .mockResolvedValueOnce({ ok: true, target, kvKey: 'bundle-key' }) + + try { + const recovered = await publishExternalPushCapability.handler( + { package_id: 'package-1' }, + createContext(), + ) + + expect(recovered.status).toBe('already_published') + expect(mockModule.publishFromExternalRef).toHaveBeenCalledTimes(2) + expect(mockModule.rebuildPublishedPackageArtifact).toHaveBeenCalledTimes(2) + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining( + 'package_publish_external_push transient Durable Object reset', + ), + ) + } finally { + warnSpy.mockRestore() + } +}) + test('check failure leaves mutation to the shared publish pipeline', async () => { setupDefaultMocks() mockModule.resolveArtifactSourceHead.mockResolvedValue({ diff --git a/packages/worker/src/mcp/capabilities/packages/publish-external-push.ts b/packages/worker/src/mcp/capabilities/packages/publish-external-push.ts index 1b6f381837..bfb736abf4 100644 --- a/packages/worker/src/mcp/capabilities/packages/publish-external-push.ts +++ b/packages/worker/src/mcp/capabilities/packages/publish-external-push.ts @@ -2,7 +2,10 @@ import * as Sentry from '@sentry/cloudflare' import { z } from 'zod' import { defineDomainCapability } from '#mcp/capabilities/define-domain-capability.ts' import { capabilityDomainNames } from '#mcp/capabilities/domain-metadata.ts' -import { getErrorMessage } from '#mcp/capabilities/error-message.ts' +import { + errorCauseChainIncludes, + getErrorMessage, +} from '#mcp/capabilities/error-message.ts' import { requireMcpUser } from '#mcp/capabilities/meta/require-user.ts' import { getStaticPackageDependentsSummary, @@ -29,11 +32,12 @@ const inputSchema = z.object({ const externalPublishRetryDelaysMs = [100, 500] as const function isTransientDurableObjectResetError(error: unknown) { - const message = getErrorMessage(error) - return ( - message.includes('Durable Object exceeded its CPU time limit') || - message.includes("Durable Object's isolate exceeded its memory limit") || - message.includes('Durable Object was reset') + return errorCauseChainIncludes( + error, + (message) => + message.includes('Durable Object exceeded its CPU time limit') || + message.includes("Durable Object's isolate exceeded its memory limit") || + message.includes('Durable Object was reset'), ) } diff --git a/packages/worker/src/mcp/capabilities/repo/package-artifact-rebuild.ts b/packages/worker/src/mcp/capabilities/repo/package-artifact-rebuild.ts index cb2a106522..fdb2aa41fa 100644 --- a/packages/worker/src/mcp/capabilities/repo/package-artifact-rebuild.ts +++ b/packages/worker/src/mcp/capabilities/repo/package-artifact-rebuild.ts @@ -1,4 +1,29 @@ import { repoSessionRpc } from '#worker/repo/repo-session-do.ts' +import { type PublishedPackageArtifactBuildTarget } from '#worker/package-runtime/package-artifact-targets.ts' +import { formatErrorCauseChain } from '#mcp/capabilities/error-message.ts' + +function describePackageArtifactTarget( + target: PublishedPackageArtifactBuildTarget, +) { + return [ + `kind "${target.kind}"`, + `artifact "${target.artifactName ?? ''}"`, + `entry "${target.entryPoint}"`, + `bundle "${target.bundleKind}"`, + ].join(', ') +} + +function buildRebuildFailureMessage(input: { + sourceId: string + publishedCommit: string + target?: PublishedPackageArtifactBuildTarget + error: unknown +}) { + const target = input.target + ? ` target { ${describePackageArtifactTarget(input.target)} }` + : '' + return `Package source publish succeeded, but bundle artifact rebuild failed for source "${input.sourceId}" at commit "${input.publishedCommit}"${target}. Cause: ${formatErrorCauseChain(input.error)}. Re-run the publish capability to repair artifacts.` +} export async function rebuildPublishedPackageArtifactsViaRepoSession(input: { env: Env @@ -9,14 +34,26 @@ export async function rebuildPublishedPackageArtifactsViaRepoSession(input: { publishedCommit: string baseUrl: string }) { + const session = repoSessionRpc(input.env, input.rpcSessionId) + let targets: Array try { - const session = repoSessionRpc(input.env, input.rpcSessionId) - const targets = await session.listPublishedPackageArtifactTargets({ + targets = await session.listPublishedPackageArtifactTargets({ sessionId: input.repoSessionId, sourceId: input.sourceId, userId: input.userId, }) - for (const target of targets) { + } catch (error) { + throw new Error( + buildRebuildFailureMessage({ + sourceId: input.sourceId, + publishedCommit: input.publishedCommit, + error, + }), + { cause: error }, + ) + } + for (const target of targets) { + try { await session.rebuildPublishedPackageArtifact({ sessionId: input.repoSessionId, sourceId: input.sourceId, @@ -25,11 +62,16 @@ export async function rebuildPublishedPackageArtifactsViaRepoSession(input: { target, baseUrl: input.baseUrl, }) + } catch (error) { + throw new Error( + buildRebuildFailureMessage({ + sourceId: input.sourceId, + publishedCommit: input.publishedCommit, + target, + error, + }), + { cause: error }, + ) } - } catch (error) { - throw new Error( - `Package source publish succeeded, but bundle artifact rebuild failed for source "${input.sourceId}" at commit "${input.publishedCommit}". Re-run the publish capability to repair artifacts.`, - { cause: error }, - ) } } diff --git a/packages/worker/src/package-runtime/package-artifact-targets.ts b/packages/worker/src/package-runtime/package-artifact-targets.ts new file mode 100644 index 0000000000..bd2c72c7d2 --- /dev/null +++ b/packages/worker/src/package-runtime/package-artifact-targets.ts @@ -0,0 +1,85 @@ +import { + getPackageAppEntryPath, + listPackageServices, + listPackageSubscriptions, + normalizePackageWorkspacePath, +} from '#worker/package-registry/manifest.ts' +import { + type AuthoredPackageJson, + type PackageExportTarget, +} from '#worker/package-registry/types.ts' +import { type BundleArtifactKind } from './published-runtime-artifacts.ts' +import { buildPackageSubscriptionArtifactName } from './subscription-artifacts.ts' + +export type PublishedPackageArtifactBuildTarget = { + kind: BundleArtifactKind + artifactName?: string | null + entryPoint: string + bundleKind: 'app' | 'module' | 'importable-module' +} + +function resolvePackageExportRuntimeEntryPoint(target: PackageExportTarget) { + return typeof target === 'string' + ? target + : (target.import ?? target.default ?? null) +} + +export function collectPublishedPackageArtifactTargets( + manifest: AuthoredPackageJson, +) { + const targets: Array = [] + if (manifest.kody.app) { + const entryPoint = getPackageAppEntryPath(manifest) + if (entryPoint) { + targets.push({ + kind: 'app', + entryPoint, + bundleKind: 'app', + }) + } + } + for (const service of listPackageServices(manifest)) { + targets.push({ + kind: 'service', + artifactName: service.name, + entryPoint: service.entry, + bundleKind: 'module', + }) + } + for (const [exportName, exportTarget] of Object.entries(manifest.exports)) { + const entryPoint = resolvePackageExportRuntimeEntryPoint(exportTarget) + if (!entryPoint) continue + const normalizedEntryPoint = normalizePackageWorkspacePath(entryPoint) + targets.push({ + kind: 'module', + artifactName: exportName, + entryPoint: normalizedEntryPoint, + bundleKind: 'module', + }) + targets.push({ + kind: 'importable-module', + artifactName: exportName, + entryPoint: normalizedEntryPoint, + bundleKind: 'importable-module', + }) + } + for (const subscription of listPackageSubscriptions(manifest)) { + targets.push({ + kind: 'module', + artifactName: buildPackageSubscriptionArtifactName(subscription.topic), + entryPoint: subscription.handler, + bundleKind: 'module', + }) + } + for (const [jobName, jobDefinition] of Object.entries( + manifest.kody.jobs ?? {}, + )) { + targets.push({ + kind: 'job', + artifactName: jobName, + entryPoint: normalizePackageWorkspacePath(jobDefinition.entry), + bundleKind: 'module', + }) + } + return targets +} diff --git a/packages/worker/src/package-runtime/published-bundle-artifacts.node.test.ts b/packages/worker/src/package-runtime/published-bundle-artifacts.node.test.ts index c78c62dc13..8dc032780c 100644 --- a/packages/worker/src/package-runtime/published-bundle-artifacts.node.test.ts +++ b/packages/worker/src/package-runtime/published-bundle-artifacts.node.test.ts @@ -264,10 +264,10 @@ test('rebuildPublishedPackageArtifacts bundles declared subscription handlers', expect(buildAppBundle).not.toHaveBeenCalled() expect(buildModuleBundle).toHaveBeenCalledWith({ - entryPoint: './src/index.ts', + entryPoint: 'src/index.ts', }) expect(buildImportableModuleBundle).toHaveBeenCalledWith({ - entryPoint: './src/index.ts', + entryPoint: 'src/index.ts', }) expect(buildModuleBundle).toHaveBeenCalledWith({ entryPoint: 'src/on-email-received.ts', diff --git a/packages/worker/src/package-runtime/published-bundle-artifacts.ts b/packages/worker/src/package-runtime/published-bundle-artifacts.ts index 9938e2d4f7..a70308ba2d 100644 --- a/packages/worker/src/package-runtime/published-bundle-artifacts.ts +++ b/packages/worker/src/package-runtime/published-bundle-artifacts.ts @@ -1,8 +1,3 @@ -import { - getPackageAppEntryPath, - listPackageServices, - listPackageSubscriptions, -} from '#worker/package-registry/manifest.ts' import { type AuthoredPackageJson, type SavedPackageRecord, @@ -29,7 +24,10 @@ import { } from '#worker/repo/published-bundle-artifacts-repo.ts' import { type EntitySourceRow } from '#worker/repo/types.ts' import { type WorkerLoaderModules } from '#worker/worker-loader-types.ts' -import { buildPackageSubscriptionArtifactName } from './subscription-artifacts.ts' +import { + collectPublishedPackageArtifactTargets, + type PublishedPackageArtifactBuildTarget, +} from './package-artifact-targets.ts' type PersistPublishedBundleArtifactInput = { env: Env @@ -45,13 +43,6 @@ type PersistPublishedBundleArtifactInput = { packageContext?: PublishedBundleArtifact['packageContext'] } -export type PublishedPackageArtifactBuildTarget = { - kind: BundleArtifactKind - artifactName?: string | null - entryPoint: string - bundleKind: 'app' | 'module' | 'importable-module' -} - type PublishedPackageArtifactBuilders = { buildAppBundle: (args: { entryPoint: string }) => Promise<{ mainModule: string @@ -260,72 +251,6 @@ export async function loadPublishedBundleArtifactByIdentity(input: { } } -export function collectPublishedPackageArtifactTargets( - manifest: AuthoredPackageJson, -) { - const targets: Array = [] - if (manifest.kody.app) { - const entryPoint = getPackageAppEntryPath(manifest) - if (entryPoint) { - targets.push({ - kind: 'app', - entryPoint, - bundleKind: 'app', - }) - } - } - for (const service of listPackageServices(manifest)) { - targets.push({ - kind: 'service', - artifactName: service.name, - entryPoint: service.entry, - bundleKind: 'module', - }) - } - for (const [exportName, exportTarget] of Object.entries( - manifest.exports, - ) as Array<[string, AuthoredPackageJson['exports'][string]]>) { - const entryPoint = - typeof exportTarget === 'string' - ? exportTarget - : (exportTarget.import ?? exportTarget.default ?? null) - if (!entryPoint) continue - targets.push({ - kind: 'module', - artifactName: exportName, - entryPoint, - bundleKind: 'module', - }) - targets.push({ - kind: 'importable-module', - artifactName: exportName, - entryPoint, - bundleKind: 'importable-module', - }) - } - for (const subscription of listPackageSubscriptions(manifest)) { - targets.push({ - kind: 'module', - artifactName: buildPackageSubscriptionArtifactName(subscription.topic), - entryPoint: subscription.handler, - bundleKind: 'module', - }) - } - for (const [jobName, jobDefinition] of Object.entries( - manifest.kody.jobs ?? {}, - ) as Array< - [string, NonNullable[string]] - >) { - targets.push({ - kind: 'job', - artifactName: jobName, - entryPoint: jobDefinition.entry, - bundleKind: 'module', - }) - } - return targets -} - export async function persistPublishedPackageArtifactTarget( input: { env: Env @@ -415,3 +340,5 @@ export async function deletePublishedArtifactsForSource(input: { } export type { PublishedBundleArtifactRecord } +export { collectPublishedPackageArtifactTargets } +export type { PublishedPackageArtifactBuildTarget } diff --git a/packages/worker/src/repo/checks.node.test.ts b/packages/worker/src/repo/checks.node.test.ts index 7ed5dceb14..838a83c7b9 100644 --- a/packages/worker/src/repo/checks.node.test.ts +++ b/packages/worker/src/repo/checks.node.test.ts @@ -435,17 +435,16 @@ export default async () => { ) }) -test('runRepoChecks allows named-only helper exports and typechecks callable manifest exports', async () => { +test('runRepoChecks validates every persisted package artifact target before publish', async () => { const files = new Map([ [ 'package.json', createPackageManifest({ - packageName: '@kody/helper-and-callable-export', - kodyId: 'helper-and-callable-export', - description: 'Exports helpers and callable runtime targets', + packageName: '@kody/persisted-artifacts', + kodyId: 'persisted-artifacts', + description: 'Exports package runtime targets', exports: { '.': './src/index.ts', - './helper': './src/helper.ts', './job': './src/job.ts', './search': './src/search.ts', './subscription': './src/subscription.ts', @@ -474,10 +473,9 @@ test('runRepoChecks allows named-only helper exports and typechecks callable man }, }), ], - ['src/index.ts', 'export const ready = true\n'], [ - 'src/helper.ts', - 'export const format = (value: string) => value.trim()\n', + 'src/index.ts', + 'export default async () => ({ ready: true })\nexport const ready = true\n', ], [ 'src/job.ts', @@ -516,11 +514,19 @@ test('runRepoChecks allows named-only helper exports and typechecks callable man }, manifestPath: 'package.json', sourceRoot: '/', + env: {} as Env, + baseUrl: 'https://kody.dev', + userId: 'user-123', }) expect(result.ok).toBe(true) expect(result.results).toEqual( expect.arrayContaining([ + expect.objectContaining({ + kind: 'bundle', + ok: true, + message: 'Bundled 8 package target(s) successfully.', + }), expect.objectContaining({ kind: 'typecheck', ok: true, @@ -529,6 +535,16 @@ test('runRepoChecks allows named-only helper exports and typechecks callable man }), ]), ) + expect(mockModule.buildKodyModuleBundle).toHaveBeenCalledWith( + expect.objectContaining({ + entryPoint: 'src/index.ts', + }), + ) + expect(mockModule.buildKodyImportableModuleBundle).toHaveBeenCalledWith( + expect.objectContaining({ + entryPoint: 'src/index.ts', + }), + ) expect(typeScriptFileSystem.write).toHaveBeenCalledWith( '.__kody_repo_runtime__.d.ts', expect.stringContaining('declare const codemode'), @@ -545,10 +561,6 @@ test('runRepoChecks allows named-only helper exports and typechecks callable man '.__kody_repo_module_check__.ts', expect.stringContaining('import userEntrypoint from "./src/subscription"'), ) - expect(typeScriptFileSystem.write).not.toHaveBeenCalledWith( - '.__kody_repo_module_check__.ts', - expect.stringContaining('import userEntrypoint from "./src/helper"'), - ) }) test('runRepoChecks still reports unknown globals for package-owned jobs', async () => { @@ -1182,7 +1194,87 @@ test('runRepoChecks fails bundle validation when runtime bundling cannot resolve userId: 'user-123', }), ) - expect(mockModule.buildKodyModuleBundle).not.toHaveBeenCalled() + expect(mockModule.buildKodyModuleBundle).toHaveBeenCalledWith( + expect.objectContaining({ + entryPoint: 'src/index.ts', + userId: 'user-123', + }), + ) +}) + +test('runRepoChecks fails before publish when an exported module artifact cannot be built', async () => { + const files = new Map([ + [ + 'package.json', + JSON.stringify({ + name: '@kody/named-only-export', + exports: { + '.': './src/index.ts', + }, + kody: { + id: 'named-only-export', + description: 'Exports a helper that is not callable.', + }, + }), + ], + ['src/index.ts', 'export const ready = true\n'], + ]) + const snapshot = createSnapshotFromFiles(files) + const typeScriptFileSystem: MockTypeScriptFileSystem = { + ...snapshot, + write: vi.fn(), + } + mockModule.createFileSystemSnapshot.mockResolvedValue(snapshot) + mockModule.createTypescriptLanguageService.mockResolvedValue({ + fileSystem: typeScriptFileSystem, + languageService: { + getSemanticDiagnostics: vi.fn(() => []), + }, + }) + mockModule.buildKodyModuleBundle.mockRejectedValueOnce( + new Error('No matching default export for import "default"'), + ) + + const result = await runRepoChecks({ + workspace: { + async readFile(path: string) { + return files.get(path) ?? null + }, + async glob() { + return Array.from(files.keys()).map((path) => ({ path, type: 'file' })) + }, + }, + manifestPath: 'package.json', + sourceRoot: '/', + env: {} as Env, + baseUrl: 'https://kody.dev', + userId: 'user-123', + }) + + expect(result.ok).toBe(false) + expect(result.results).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + kind: 'bundle', + ok: false, + message: expect.stringContaining( + 'src/index.ts: No matching default export for import "default"', + ), + }), + ]), + ) + expect(mockModule.buildKodyModuleBundle).toHaveBeenCalledWith( + expect.objectContaining({ + entryPoint: 'src/index.ts', + userId: 'user-123', + }), + ) + expect(mockModule.buildKodyImportableModuleBundle).toHaveBeenCalledWith( + expect.objectContaining({ + entryPoint: 'src/index.ts', + userId: 'user-123', + }), + ) }) test('runRepoChecks validates package runtime bundles with npm dependencies', async () => { @@ -1256,7 +1348,7 @@ test('runRepoChecks validates package runtime bundles with npm dependencies', as expect.objectContaining({ kind: 'bundle', ok: true, - message: 'Bundled 2 package target(s) successfully.', + message: 'Bundled 3 package target(s) successfully.', }), ]), ) diff --git a/packages/worker/src/repo/checks.ts b/packages/worker/src/repo/checks.ts index 5e084526cb..bbef02449a 100644 --- a/packages/worker/src/repo/checks.ts +++ b/packages/worker/src/repo/checks.ts @@ -1,8 +1,7 @@ import { - getPackageAppEntryPath, listPackageServices, - listPackageSubscriptions, listPackageRetrievers, + listPackageSubscriptions, normalizePackageWorkspacePath, parseAuthoredPackageJson, resolvePackageExportPath, @@ -13,6 +12,10 @@ import { buildKodyImportableModuleBundle, buildKodyModuleBundle, } from '#worker/package-runtime/module-graph.ts' +import { + collectPublishedPackageArtifactTargets, + type PublishedPackageArtifactBuildTarget, +} from '#worker/package-runtime/package-artifact-targets.ts' import { collectStaticKodyPackageImportsFromFiles } from '#worker/package-runtime/static-kody-imports.ts' import { hasTopLevelDefaultExport } from '#worker/module-source.ts' import { @@ -435,9 +438,23 @@ function compareBundleTargets( return buildBundleTargetKey(left).localeCompare(buildBundleTargetKey(right)) } -function collectPackageBundleTargets( - manifest: AuthoredPackageJson, -): Array { +function toPackageBundleKind(target: PublishedPackageArtifactBuildTarget) { + switch (target.bundleKind) { + case 'app': + return 'app' + case 'module': + return 'callable' + case 'importable-module': + return 'importable' + default: { + const bundleKind: never = target.bundleKind + void bundleKind + throw new Error('Unhandled package artifact bundle kind.') + } + } +} + +function collectPackageBundleTargets(manifest: AuthoredPackageJson) { const targets = new Map() const remember = ( path: string, @@ -449,27 +466,8 @@ function collectPackageBundleTargets( bundleKind, }) } - const appEntryPath = getPackageAppEntryPath(manifest) - if (appEntryPath) { - remember(appEntryPath, 'app') - } - for (const exportName of Object.keys(manifest.exports)) { - remember( - resolvePackageExportPath({ - manifest, - exportName, - }), - 'importable', - ) - } - for (const job of Object.values(manifest.kody.jobs ?? {})) { - remember(job.entry, 'callable') - } - for (const service of listPackageServices(manifest)) { - remember(service.entry, 'callable') - } - for (const subscription of listPackageSubscriptions(manifest)) { - remember(subscription.handler, 'callable') + for (const target of collectPublishedPackageArtifactTargets(manifest)) { + remember(target.entryPoint, toPackageBundleKind(target)) } for (const retriever of listPackageRetrievers(manifest)) { remember( @@ -483,9 +481,7 @@ function collectPackageBundleTargets( return Array.from(targets.values()).sort(compareBundleTargets) } -function collectPackageCallableTypecheckTargets( - manifest: AuthoredPackageJson, -): Array { +function collectPackageCallableTypecheckTargets(manifest: AuthoredPackageJson) { const targets = new Map() const emittedEventTopics = Object.keys(manifest.kody.emits ?? {}) const remember = (path: string, includeStorage: boolean) => {