Appearance
Private vs workspace apps
Most reads in the App SDK are filtered by what kind of app you are. There are two kinds:
- Workspace app — installed into, and locked to, a single workspace. The host knows its workspace id. Reads are scoped to that one workspace; cross-workspace requests are rejected.
- Private (personal) app — not bound to any workspace (e.g. the marketplace, personal tools). Reads span all workspaces the user belongs to, and a few workspace-management methods are only available here.
You can tell which one you're in from hailer.info(): a workspace app has a workspaceId; a private app does not.
What changes, method by method
The host applies the scope on its side, so it's the same call returning different data:
| Method | Workspace app | Private app |
|---|---|---|
workspace.list() | Just the app's workspace | All the user's workspaces (sorted by name) |
workspace.current() | The app's workspace | The user's currently-active workspace |
workspace.create(name) | Rejected (403) | Allowed |
workflow.list() | Workflows in the app's workspace | Workflows across all workspaces |
workflow.get(id) | Scoped to the app's workspace | Any workspace the user can see |
team.list() | Teams in the app's workspace | Teams across all workspaces |
user.get(id) | null if the user isn't in the app's workspace | Any user the app can see |
user.list() | Members of the current workspace | Members of the current workspace |
permission.map({workspaceId}) | Always the app's workspace; a different workspaceId is rejected (403) | All workspaces, or a specific one on request |
insight.list() | Insights in the app's workspace | Insights in the user's current workspace |
team.list() and permission.map() return data keyed by workspace id, so a private app's result can contain several workspaces at once — iterate the keys rather than assuming one.
Practical implications
Don't hard-code a single workspace. In a private app, results are multi-workspace. Read the workspace id off each item (workflows carry a workspaceId; teams/permissions are keyed by it) instead of assuming there's only one.
Guard workspace-management calls. workspace.create() throws in a workspace app. Only offer it when you're a private app:
ts
const { workspaceId } = hailer.info();
const isPrivateApp = !workspaceId;
if (isPrivateApp) {
const ws = await hailer.workspace.create('New workspace');
}Don't ask a workspace app about another workspace. permission.map({ workspaceId }) with a different id — and any cross-workspace read — is rejected with a 403 in a workspace app. Pass no workspaceId (or the app's own) and let the host scope it.
Empty results reflect scope. A workspace app returning [] from workflow.list() means there are no workflows in that workspace. Check the app's scope with info().
Next steps
- App lifecycle — where
workspaceIdcomes from. - Reference: workspace · permission · user