SDK Workbench
The local UI that calls your handlers the same way the CI HUB client does.
The SDK Workbench is the local stand-in for the CI HUB client. npm run dev serves it at http://localhost:8080 (see CLI).
The workbench talks to your integration over the same HTTP surface the client uses. Every control in it runs one of your handlers, with the same inputs the client would send.
What the workbench tests
- Your handlers, not mocks. Nothing between the workbench and your code is faked. If a flow works here, it works in the client.
- Your response shape. Every response is validated against the schema for that handler. Failures appear in the diagnostics panel, pointing at the field.
- What the client does with your response. A valid response that hides a button or fetches an unexpected URL shows up as an insight, not just a pass.
How a click reaches your code
Take the Navigation module. Type a folder id, press Load, and your getFolder handler runs. Everything on screen arrives in that handler's request data: the folder id, the selected filters, the data locale. The second argument carries the session, which is the access token and the adapterData your login handler returned. Both are sent on every call after login.
Two consequences:
- Auth must succeed before anything else works.
- A mistake in what
loginreturns often surfaces later, when a handler reads anadapterDatafield that was never set. See adapterData.
If a control runs a handler you did not export, the server replies that the method is not implemented and the workbench shows that message.
Where to start
Work down the sidebar in order. Each module depends on the ones above it.
Details. Reads your metadata and registers your handler list.
Auth. Everything else needs the session it produces.
Info, if you implement it. Search and Navigation build their filter bars from what it returns.
Search or Navigation, whichever your platform leads with.
Everything else, in any order.
Details
Runs: no handler. The server reads every non-function property of your defineIntegration call and returns it, plus the list of handler names you exported.
Tests: that your metadata is well formed and that the handlers you think you exported are exported.
The Registered Handlers badges are the literal list of functions the server found on your integration object. A handler missing here is missing everywhere, and every feature depending on it is disabled in every other module.
The capability badges are what you declared in capabilities. The handler list and the capabilities together decide what the rest of the workbench lets you do, so read this view before concluding that something else is broken.
Press Refresh Details in the sidebar after changing your integration. Adding a handler or a capability does not change the gating until this runs again.
See Integration Info and Capabilities Reference.
Auth
Runs: login, then checkToken, refreshToken and logout.
Tests: the whole OAuth round trip, as the client performs it.
Login calls your login handler and expects a redirect to your provider in return. The workbench opens that URL in a popup. When your provider redirects back, login runs a second time with the authorization code and is expected to return the token payload. The workbench stores it and immediately calls checkToken with it.
One Login press therefore exercises both halves of your login handler plus the token check. If the popup closes on an error page, your second call returned no access token.
The remaining buttons appear once you are logged in:
| Control | Effect |
|---|---|
| Check Token | Calls checkToken with the current access token |
| Refresh Token | Calls refreshToken and replaces the stored session with what you return |
| Logout | Calls logout |
| View Token JSON | Shows what the workbench is holding. Use it to confirm adapterData contains what your later handlers read |
capabilities.supportsNewLoginUrl changes which login address the workbench uses, but both forms reach the same login handler. See Login Flow and Auth Handlers.
Info
Runs: info.
Tests: the per-user configuration your integration returns after authentication. The handler is optional, but much of the workbench is built from it: pre-search filters, data locales, search configs, the option inputs on the upload and update forms, and the request headers used to fetch thumbnails.
Search and Navigation call info themselves when they need filters, so what is listed here is exactly what those modules offer. If a filter bar is missing from Search, this view tells you whether info returned it.
See Info Handler and Filters.
Search
Runs: search.
Tests: everything the client's search bar does.
- Typing a query and pressing Search calls
searchwith that text. - Selecting a filter re-runs
searchwith the selected filter ids, so you can check that your handler applies them and that the filters you return mark the right options as active. - Load more re-runs
searchwith themorecursor you returned, which verifies your pagination. - Parent ID appears when you declare
capabilities.assetSearch.supportsParentId, and scopes the search to a folder. - Similarity Search appears when you declare
capabilities.assetSearch.similarSearch. It handssearcha base64 image alongside the query, the only case where that handler receives a file.
The two accordions at the bottom call createAsset and updateAsset. Search results are not a folder, so the upload accordion asks for a target parent id. The client offers upload from search results only when you declare capabilities.supportsAddAssetInSearch, the same flag that gates the entry in the grid's background menu.
Results render as a grid. Right-clicking an asset gives the actions the client offers, covered in The grid and its context menus.
See Search and canAddAsset in Search.
Navigation
Runs: getFolder, plus most of your mutating handlers.
Tests: folder browsing and the permission model around it. This is the widest module in the workbench.
Load calls getFolder with the folder id, starting at root. Double-clicking a folder in the grid calls it again for that folder, which is how you walk your tree.
This module is where capabilities get tested, in two layers. What you return in a folder's capabilities decides what the client offers inside it, and the workbench enforces the same rules: return canAddAsset: false and the upload form is refused, with the reason shown. Mismatches between what you intended and what you returned surface here.
The accordions below the folder input call one handler each, so you can exercise a handler without hunting for the right tile:
| Accordion | Your handler |
|---|---|
| Create Folder | createFolder |
| Create Asset (Upload) | createAsset |
| Update Asset | updateAsset |
| Rename Folder | renameFolder |
| Delete Folder | deleteFolder |
| Delete Asset | deleteAsset |
| Rename Asset | renameAsset |
| Lock / Unlock Asset | lockAsset |
| Download | download |
Download resolves the URL through your download handler and shows it without fetching the file, so you can check the URL before trusting it.
See Folder Navigation, Per-Folder Capabilities, Folder Operations, Upload, Download and Asset Operations.
Versions
Runs: getAssetVersions.
Tests: the version history of one asset. Enter an asset id and press Load. The With master checkbox is passed to your handler, so you can exercise both paths through it.
The grid renders each version with the size, modified date and version label you returned, laid out the way the client lays them out. Use it to check that your version ordering and labelling read correctly to a user.
See getAssetVersions.
Brand
Runs: getBrandConfig, then getBrandAssets.
Tests: the Brand Hub surface, which needs capabilities.supportsBrandHub declared plus both handlers exported.
Load Brand Config calls getBrandConfig. Double-clicking a category in the grid calls getBrandAssets with that category's folderId and categoryType, the values you returned in the config. That makes it a real test of the two handlers agreeing with each other. Load more pages through a category using the more cursor you returned.
See Brand Hub.
Tasks
Runs: searchTasks, getTask, getTaskAssets, addTaskComment, addAssetToTask, addTaskAsset, updateTaskState, updateCustomTaskState, deleteTaskAsset.
Tests: task workflows, which need capabilities.tasking declared.
Searching calls searchTasks. Clicking a result calls getTask. Everything in the task detail panel maps to one handler:
| Control | Your handler |
|---|---|
| Get Assets | getTaskAssets |
| Add Comment | addTaskComment |
| Add Asset (id only) | addAssetToTask |
| Add Task Asset (full form) | addTaskAsset |
| A badge under "Transition to state" | updateTaskState |
| Update Custom Task State | updateCustomTaskState |
| Remove (Delete Task Asset) | deleteTaskAsset |
The state badges come from the availableStates you returned on the task, so clicking one tests that your task response and your state handler agree. After a transition or an asset change the workbench re-reads the task, which shows whether the change took effect on your side.
See Tasks.
Reparent
Runs: moveAsset or moveFolder, depending on the type toggle.
Tests: moving something to a new parent, including moving to root. The same form opens from the grid's Move entry with the source already filled in.
The grid and its context menus
Search, Navigation, Versions and Brand render their results as a grid of tiles. Right-clicking a tile gives the actions the client would offer for it, and each one opens the same form the accordions use, pre-filled and locked to that item. The menu runs the same handlers listed above. What it adds is the gating.
Every entry is checked twice: once against your handler list and capabilities, and once against the capability flags on the item you clicked. An entry you cannot use stays visible and explains itself on hover. That message is the useful part, because it tells you why the client would not offer the action to a user.
Folders are the exception worth understanding. A folder listed inside another folder usually arrives with nothing but an id and a name, so the workbench does not know what it permits and will not guess. Load actions in its menu calls your getFolder for that one folder to find out. If the actions stay disabled afterwards, your getFolder did not return capabilities for it.
Preview Details runs no handler. It shows one asset or folder the way the client displays it after transforming your response: dates rewritten, capabilities resolved through their fallback chain, and the classification that decides which host actions appear. Use it to check whether a field you returned survives the client's transforms.
See Asset Object and Asset Types.
When something is disabled
There are three reasons, and the diagnostics panel names which one applies.
The handler is not exported. Diagnostics says Missing handler(s): <name>. Add the function to your defineIntegration call and press Refresh Details.
The capability is not declared. Diagnostics says Capability not met: <expression>, showing the exact flag it tested. Several features need both a handler and a flag: Brand needs supportsBrandHub, Tasks needs tasking, similarity search needs assetSearch.similarSearch, upload from search results needs supportsAddAssetInSearch. Add the flag to capabilities and press Refresh Details. See Capabilities Reference.
The item said no. The handler exists and the capability is declared, but the folder or asset you are acting on returned a flag that forbids it, such as canAddAsset: false or canDeleteAsset: false. Nothing is wrong with your configuration. This is your own response talking, and the fix is in whatever your handler computed for that item.
On any module other than Details and Auth, the panel may simply be telling you to run Details or log in first.
What the workbench cannot tell you
Worth knowing before you treat a green result as final:
- Direct Access Helper behavior is close, but not identical. Your helper runs in a real browser here, but not the browser environment it gets in production. MD5 is the clearest example: the workbench cannot produce one and passes your helper an empty string, so a helper that depends on it passes here and fails for users. See Limitations and Download Hashes.
- The CORS check is unauthenticated. A provider that allows the preflight but blocks credentialed requests still passes here and fails in production.
- Batch operations are not exercised.
batchOperations.canDeleteandcanLockchange how the client callsdeleteAssetandlockAsset. The workbench acts on one item at a time. - Host-specific behavior is out of scope. How your assets place into InDesign, Photoshop or Office is not something a browser can test.
For the hosted end of the process, see Partner Journey.
Handler lookup
Every handler the workbench can call, and where to trigger it. A handler you export that is not listed here is never reached by any control.
| Handler | Where in the workbench |
|---|---|
addAssetToTask | Tasks, Add Asset |
addTaskAsset | Tasks, Add Task Asset |
addTaskComment | Tasks, Add Comment |
checkToken | Auth, Check Token, and automatically after login |
createAsset | Navigation and Search accordions, folder and listing context menus |
createFolder | Navigation accordion, folder and listing context menus |
deleteAsset | Navigation accordion, asset context menu |
deleteFolder | Navigation accordion, folder context menu |
deleteTaskAsset | Tasks, Delete Task Asset |
download | Navigation accordion, asset context menu |
getAssetVersions | Versions, Load; asset context menu, View Versions |
getBrandAssets | Brand, opening a category and Load more |
getBrandConfig | Brand, Load Brand Config |
getFolder | Navigation Load and folder drill-down; folder menu, Load actions |
getTask | Tasks, clicking a result |
getTaskAssets | Tasks, Get Assets |
info | Info, Load Provider Info; and on demand from Search and Navigation |
lockAsset | Navigation accordion, asset context menu |
login | Auth, Login. Runs twice: the redirect, then the callback |
logout | Auth, Logout |
moveAsset | Reparent with type Asset; asset context menu, Move |
moveFolder | Reparent with type Folder; folder context menu, Move |
refreshToken | Auth, Refresh Token |
renameAsset | Navigation accordion, asset context menu |
renameFolder | Navigation accordion, folder context menu |
search | Search, and every filter change and Load more |
searchTasks | Tasks, Search and Load more |
updateAsset | Navigation and Search accordions, asset context menu |
updateCustomTaskState | Tasks, Update Custom Task State |
updateTaskState | Tasks, clicking a state badge |