fix(hub-projects): retarget plain trigger resource paths on import

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
tristantr
2026-07-13 12:17:59 +02:00
co-authored by Claude Fable 5
parent b399cd8e2e
commit d31d298130
3 changed files with 56 additions and 3 deletions
@@ -6,6 +6,7 @@ import {
extractAppRefs,
buildPathMap,
rewriteContent,
rewriteTriggerConfig,
rewriteFlowValue,
rewriteAppValue,
extractRawAppRefs,
@@ -142,6 +143,38 @@ describe('rewriteContent', () => {
})
})
describe('rewriteTriggerConfig', () => {
const map = new Map([
['f/proj/kafka', 'f/target/kafka'],
['f/proj/script', 'f/target/script']
])
it('remaps plain resource path fields', () => {
expect(
rewriteTriggerConfig({ kafka_resource_path: 'f/proj/kafka', group_id: 'g1' }, map)
).toEqual({ kafka_resource_path: 'f/target/kafka', group_id: 'g1' })
})
it('remaps nested objects, arrays, and $res: tokens', () => {
expect(
rewriteTriggerConfig(
{
nested: { path: 'f/proj/script' },
list: ['f/proj/kafka', 'unrelated'],
code: 'x = "$res:f/proj/kafka"'
},
map
)
).toEqual({
nested: { path: 'f/target/script' },
list: ['f/target/kafka', 'unrelated'],
code: 'x = "$res:f/target/kafka"'
})
})
it('leaves non-matching strings and non-string values untouched', () => {
const config = { url: 'wss://example.com', port: 9092, enabled: true, extra: null }
expect(rewriteTriggerConfig(config, map)).toEqual(config)
})
})
describe('rewriteFlowValue', () => {
it('rewrites inline code, static inputs, and script paths; clones input', () => {
const map = new Map([
@@ -155,6 +155,24 @@ export function rewriteContent(content: string, map: Map<string, string>): strin
})
}
/**
* Trigger configs reference resources as plain path strings (e.g.
* `kafka_resource_path: "f/slug/db"`), not `$res:` tokens, so token rewriting
* misses them. Deep-walk the config and remap any string that exact-matches a
* map key (map keys are full bundle paths, so an exact match is a reference),
* falling back to `$res:` token rewriting for embedded refs.
*/
export function rewriteTriggerConfig(config: any, map: Map<string, string>): any {
if (typeof config === 'string') return map.get(config) ?? rewriteContent(config, map)
if (Array.isArray(config)) return config.map((v) => rewriteTriggerConfig(v, map))
if (config && typeof config === 'object') {
return Object.fromEntries(
Object.entries(config).map(([k, v]) => [k, rewriteTriggerConfig(v, map)])
)
}
return config
}
export function rewriteFlowValue(value: any, map: Map<string, string>): any {
const cloned = JSON.parse(JSON.stringify(value ?? {}))
for (const mod of getAllModules(cloned?.modules ?? [], cloned?.failure_module)) {
@@ -29,7 +29,8 @@
rewriteAppValue,
rewriteContent,
rewriteFlowValue,
rewriteRawAppContent
rewriteRawAppContent,
rewriteTriggerConfig
} from '$lib/components/workspaceSettings/projectBundle'
import { updatePolicy } from '$lib/components/apps/editor/appPolicy'
import { updateRawAppPolicy } from '$lib/sharedUtils'
@@ -275,8 +276,9 @@
...t,
path: remap(t.path),
runnable_path: remap(t.runnable_path),
// `$res:` refs can live in trigger args/config.
config: t.config ? JSON.parse(rewriteContent(JSON.stringify(t.config), map)) : t.config
// Configs hold both `$res:` tokens and plain resource paths
// (kafka_resource_path etc.) — rewrite both.
config: t.config ? rewriteTriggerConfig(t.config, map) : t.config
}))
}
}