mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-24 10:12:44 +00:00
feat(client): expose paseo.projects.subscribe() through the public SDK (#3983)
* feat(client): expose project update subscriptions * docs(sdk): clarify project subscription initialization * docs(sdk): document race-free project initialization --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
paseo-bot[bot]
parent
dd7671be20
commit
b403dea32b
@@ -335,6 +335,63 @@ test("project actions list registered projects through the existing RPC", async
|
||||
await client.close();
|
||||
});
|
||||
|
||||
test("project actions subscribe to existing project updates", async () => {
|
||||
const { client, ws } = await connectClient();
|
||||
const updates: string[] = [];
|
||||
const unsubscribe = client.projects.subscribe((update) => {
|
||||
updates.push(update.kind === "upsert" ? update.project.projectDisplayName : update.projectId);
|
||||
});
|
||||
|
||||
ws.message(
|
||||
sessionMessage({
|
||||
type: "project.update",
|
||||
payload: {
|
||||
kind: "upsert",
|
||||
project: {
|
||||
projectId: "project_sdk",
|
||||
projectKey: "sdk",
|
||||
projectDisplayName: "Renamed SDK",
|
||||
projectCustomName: "Renamed SDK",
|
||||
projectCustomIconRevision: null,
|
||||
projectIconRevision: "icon-revision",
|
||||
projectRootPath: "/repo/sdk",
|
||||
projectKind: "git",
|
||||
syncSeq: 9,
|
||||
},
|
||||
generation: "daemon-generation",
|
||||
seq: 9,
|
||||
},
|
||||
}),
|
||||
);
|
||||
ws.message(
|
||||
sessionMessage({
|
||||
type: "project.update",
|
||||
payload: {
|
||||
kind: "remove",
|
||||
projectId: "project_removed",
|
||||
generation: "daemon-generation",
|
||||
seq: 10,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(updates).toEqual(["Renamed SDK", "project_removed"]);
|
||||
|
||||
unsubscribe();
|
||||
ws.message(
|
||||
sessionMessage({
|
||||
type: "project.update",
|
||||
payload: {
|
||||
kind: "remove",
|
||||
projectId: "project_after_unsubscribe",
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(updates).toEqual(["Renamed SDK", "project_removed"]);
|
||||
|
||||
await client.close();
|
||||
});
|
||||
|
||||
test("agent actions list the daemon directory without exposing the low-level client", async () => {
|
||||
const { client, ws } = await connectClient();
|
||||
const listedAgent = createAgent({ title: "Planner" });
|
||||
|
||||
@@ -104,6 +104,11 @@ export type PaseoProjectListOptions = Omit<ProjectListRequestMessage, "type" | "
|
||||
requestId?: string;
|
||||
};
|
||||
export type PaseoProjectListResult = ProjectListResponseMessage["payload"];
|
||||
export type PaseoProjectUpdate = Extract<
|
||||
SessionOutboundMessage,
|
||||
{ type: "project.update" }
|
||||
>["payload"];
|
||||
export type PaseoProjectUpdateHandler = (update: PaseoProjectUpdate) => void;
|
||||
|
||||
export interface PaseoAgentListResult {
|
||||
requestId: string;
|
||||
@@ -173,6 +178,7 @@ export interface PaseoWorkspaceHandle {
|
||||
|
||||
export interface PaseoProjectActions {
|
||||
list(options?: PaseoProjectListOptions): Promise<PaseoProjectListResult>;
|
||||
subscribe(handler: PaseoProjectUpdateHandler): () => void;
|
||||
}
|
||||
|
||||
export interface PaseoWorkspaceActions {
|
||||
@@ -494,6 +500,10 @@ export function createPaseoApi(daemonClient: DaemonClient): PaseoApi {
|
||||
terminals,
|
||||
projects: {
|
||||
list: (options) => daemonClient.listProjects(options),
|
||||
subscribe: (handler) =>
|
||||
daemonClient.on("project.update", (message) => {
|
||||
handler(message.payload);
|
||||
}),
|
||||
},
|
||||
workspaces: {
|
||||
list: (options) => daemonClient.fetchWorkspaces(options),
|
||||
|
||||
@@ -112,9 +112,12 @@ Creation options include `config`, `cwd`, `parent`, `title`, `prompt`, `env`, `o
|
||||
|
||||
## `client.projects`
|
||||
|
||||
| Method | Result | Behavior |
|
||||
| ---------------- | ------------------------ | ----------------------------------------------------------------------------- |
|
||||
| `list(options?)` | `PaseoProjectListResult` | Lists every registered project, including projects with no active workspaces. |
|
||||
| Method | Result | Behavior |
|
||||
| -------------------- | ------------------------ | --------------------------------------------------------------------------------------- |
|
||||
| `list(options?)` | `PaseoProjectListResult` | Lists every registered project, including projects with no active workspaces. |
|
||||
| `subscribe(handler)` | Unsubscribe function | Listens only for future project upserts/removals. Pair with `list()` for initial state. |
|
||||
|
||||
To build a complete project cache without an initialization gap, subscribe and buffer updates before awaiting `list()`. Initialize the cache from the list result, then apply buffered updates in arrival order.
|
||||
|
||||
## `client.workspaces`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user