11// ---------------------------------------------------------------------------
2- // Resolving a toolkit URL's slug to the toolkit's row id, for forwarding.
2+ // Resolving a toolkit URL's slug to the toolkit's storage row id, for forwarding.
33//
44// Toolkits live in plugin storage (`@executor-js/plugin-toolkits`), owned by the
5- // org or by a single user. This reads them the way the v1 session does: through
6- // an executor scoped to the caller and org, so the caller sees the org's
7- // toolkits plus their own personal ones and nobody else's. The executor is
8- // built with the toolkits plugin alone, because a forwarded request has no use
9- // for the rest of the catalog. Among the rows with the slug the org's toolkit
10- // wins over the caller 's own, as in the plugin 's own slug resolution
11- // (`getBySlugEntry`).
5+ // org or by a single user. v2 imported each toolkit under its `plugin_storage`
6+ // row id (not the toolkit's own `id`, which is the row's `key`), and derives the
7+ // toolkit's v2 connection from that row id, so this reads the row id itself.
8+ // The plugin's API hides it, hence the direct read. Visibility matches the v1
9+ // session: the org's toolkits plus the caller's own personal ones, nobody
10+ // else's. Among rows with the slug the org 's toolkit wins over the caller 's own,
11+ // as in the plugin's slug resolution (`getBySlugEntry`).
1212// ---------------------------------------------------------------------------
1313
14- import { Effect , Layer } from "effect" ;
14+ import { sql } from "drizzle-orm" ;
15+ import { Effect } from "effect" ;
1516
16- import { PluginsProvider , makeScopedExecutor } from "@executor-js/api/server" ;
17- import { toolkitsPlugin } from "@executor-js/plugin-toolkits/server" ;
18-
19- import { CloudDbProvider , CloudHostConfig } from "../engine/execution-stack" ;
20- import { makeDbLayer } from "../db/db" ;
21-
22- const toolkitsOnly = Layer . succeed ( PluginsProvider ) ( { plugins : ( ) => [ toolkitsPlugin ( ) ] } ) ;
17+ import { DbService , makeDbLayer } from "../db/db" ;
2318
2419export const resolveToolkitRowId = (
2520 organizationId : string ,
@@ -28,17 +23,17 @@ export const resolveToolkitRowId = (
2823) : Promise < string | null > =>
2924 Effect . runPromise (
3025 Effect . gen ( function * ( ) {
31- const executor = yield * makeScopedExecutor < readonly [ ReturnType < typeof toolkitsPlugin > ] > (
32- accountId ,
33- organizationId ,
34- "" ,
26+ const { db } = yield * DbService ;
27+ const result = yield * Effect . promise ( ( ) =>
28+ db . execute < { row_id : string } > ( sql `
29+ select row_id from plugin_storage
30+ where tenant = ${ organizationId } and plugin_id = 'toolkits' and collection = 'toolkits'
31+ and (owner = 'org' or (owner = 'user' and subject = ${ accountId } ))
32+ and (data::jsonb)->>'slug' = ${ slug }
33+ order by case when owner = 'org' then 0 else 1 end, key
34+ limit 1
35+ ` ) ,
3536 ) ;
36- const toolkits = yield * executor . toolkits . list ( ) ;
37- const matches = toolkits . filter ( ( toolkit ) => toolkit . slug === slug ) ;
38- return ( matches . find ( ( toolkit ) => toolkit . owner === "org" ) ?? matches [ 0 ] ) ?. id ?? null ;
39- } ) . pipe (
40- Effect . provide ( Layer . mergeAll ( CloudDbProvider , toolkitsOnly , CloudHostConfig ) ) ,
41- Effect . provide ( makeDbLayer ( ) ) ,
42- Effect . scoped ,
43- ) ,
37+ return [ ...result ] [ 0 ] ?. row_id ?? null ;
38+ } ) . pipe ( Effect . provide ( makeDbLayer ( ) ) , Effect . scoped ) ,
4439 ) ;
0 commit comments