Skip to content

[SILO-1463] feat: api_v2 support via client.v2 (406 operations) - #56

Open
Prashant-Surya wants to merge 2 commits into
mainfrom
feat/silo-1463-node-sdk-v2
Open

[SILO-1463] feat: api_v2 support via client.v2 (406 operations)#56
Prashant-Surya wants to merge 2 commits into
mainfrom
feat/silo-1463-node-sdk-v2

Conversation

@Prashant-Surya

Copy link
Copy Markdown
Member

Description

Adds the complete Plane api_v2 surface to the Node SDK — 406 operations across 120 resource groups — as a single chained form rooted at the workspace, mirroring the API's own scope tree. v1 is untouched: every existing root export resolves to the same v1 declaration (verified with a type-level probe), and v2 types that share a v1 name are aliased V2* at the root and namespaced under v2models.

const ws = client.v2.workspace("acme");                 // zero-I/O locator
const proj = ws.project("ENG");                         // project key or UUID
await proj.workItems.create({ name: "Fix login bug", state: "Todo", labels: ["bug"] });
await proj.workItems.comments.list(workItemId);
await ws.workItems.retrieveByIdentifier("ENG-12");      // readable key, no project needed
await ws.wiki.pages.create({ name: "Runbook" });        // public page -> default collection
await client.v2.users.me();                             // the six non-workspace operations
  • Kernel (src/api/v2/kernel/): own axios instance with RFC 9457 PlaneApiError and PlaneNetworkError, offset/cursor pagination with a stall guard, ?fields / ?expand / ?order_by validated per operation against the OpenAPI golden, typed Pick<T, F> field projection, upsert, bulk create/update/delete, findByName, custom verb actions, scope-bound resources.
  • Generated constants (pnpm codegen:v2) for all 406 operations; every implemented operation is declared in exactly one resource's operations map and a two-way coverage test enforces 406/406.
  • Request models follow v1's convention: Create<Resource> / Update<Resource>.
  • Method set is identical to plane-sdk (Python) (camelCase vs snake_case).
  • scripts/check-types-bundle.mjs guards the public export surface on every build.
  • Version bumped to 0.3.0; README gains an "API v2" section.

Type of Change

  • Feature (non-breaking change which adds functionality)

Test Scenarios

  • Unit: jest tests/unit/v2 — 448 tests against nock asserting verb, exact URL, query, and body; error paths, stall guard, field/expand rejection, bulk cap, findByName ambiguity, typed field projection, two-way operation coverage.
  • Live: tests/e2e/v2 skips without PLANE_BASE_URL / PLANE_API_KEY / TEST_WORKSPACE_SLUG; against a plane-dev instance all 50 suites pass — includes an end-to-end scenario (full-scenario.e2e.test.ts) and the two work-item-type flows ported from plane-ee.
  • tsc 0 errors, oxlint unchanged from main (165 warnings / 0 errors), oxfmt clean, pnpm build passes with the export-surface snapshot.
  • CI: unit tests are now gated; a secret-gated v2-golden-drift job regenerates the constants against plane-ee's golden.

Follow-ups (not in this PR)

  • No ./v2 package subpath export yet (import { v2 } from "@makeplane/plane-node-sdk" is the entry point).
  • The e2e harness has no guard against a production PLANE_BASE_URL.
  • Spec items raised on plane-ee in SILO-1464: page delete requires archive first (undocumented), collection delete orphans pages, a 403 race right after project creation.

References

  • SILO-1463
  • Companion: plane-python-sdk [SILO-1466], plane-ee [SILO-1464] (the live suite depends on that permission fix for users/me, permissions/me, worklogs/summary).

🤖 Generated with Claude Code

https://claude.ai/code/session_015XXZ9CT96T1dZoiSYmtiNe

…operations

`client.v2` exposes every api_v2 operation through a single chained form rooted at
the workspace, mirroring the API's own scope tree:

    const ws = client.v2.workspace("acme");      // zero-I/O locator
    const proj = ws.project("ENG");              // key or UUID
    await proj.workItems.create({ name: "Fix login bug", state: "Todo" });
    await ws.workItems.retrieveByIdentifier("ENG-12");
    await ws.wiki.pages.create({ name: "Runbook" }); // public page -> default collection
    await client.v2.users.me();                  // the six non-workspace operations

- Kernel: own axios instance with RFC 9457 errors and PlaneNetworkError,
  offset/cursor envelopes with a stall guard, ?fields/?expand/?order_by validated
  per operation against the golden, typed `Pick<T, F>` field projection, upsert,
  bulk create/update/delete with per-row results, findByName, custom verb
  actions, scope-bound resources (`new Resource(transport, scope)`).
- Spec-generated constants (`pnpm codegen:v2`) for all 406 operations; every
  implemented operation is declared in exactly one resource's `operations` map
  and a two-way coverage test enforces 406/406.
- Method set is identical to plane-sdk (Python) (camelCase vs snake_case).
- Root exports keep every v1 name; v2 types that collide are aliased `V2*`, and
  `scripts/check-types-bundle.mjs` guards the public export surface on build.
- Unit tests under tests/unit/v2 (nock); e2e under tests/e2e/v2 skip without env.
- CI: unit tests gated; a secret-gated `v2-golden-drift` job regenerates the
  constants against plane-ee's golden.
- Version 0.3.0. v1 surface untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XXZ9CT96T1dZoiSYmtiNe
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 296 files, which is 196 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: fb0d6f4c-5a1c-4f58-983c-c2e8ccc8e63d

📥 Commits

Reviewing files that changed from the base of the PR and between d83a212 and 3a244c0.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/api/v2/generated/constants.ts is excluded by !**/generated/**
📒 Files selected for processing (296)
  • .github/workflows/build-test.yaml
  • .oxlintrc.json
  • CLAUDE.md
  • README.md
  • jest.config.js
  • package.json
  • scripts/__fixtures__/types-bundle-exports.snapshot.txt
  • scripts/check-types-bundle.mjs
  • scripts/generate-v2-constants.mjs
  • src/api/v2/Artifacts.ts
  • src/api/v2/Assets.ts
  • src/api/v2/AuditLogs.ts
  • src/api/v2/Automations/ProjectAutomationActivities.ts
  • src/api/v2/Automations/ProjectAutomationEdges.ts
  • src/api/v2/Automations/ProjectAutomationNodes.ts
  • src/api/v2/Automations/ProjectAutomations.ts
  • src/api/v2/Automations/WorkspaceAutomationActivities.ts
  • src/api/v2/Automations/WorkspaceAutomationEdges.ts
  • src/api/v2/Automations/WorkspaceAutomationNodes.ts
  • src/api/v2/Automations/WorkspaceAutomations.ts
  • src/api/v2/Automations/index.ts
  • src/api/v2/Collections/Members.ts
  • src/api/v2/Collections/Pages.ts
  • src/api/v2/Collections/index.ts
  • src/api/v2/CustomerProperties.ts
  • src/api/v2/Customers/PropertyValues.ts
  • src/api/v2/Customers/Requests.ts
  • src/api/v2/Customers/WorkItems.ts
  • src/api/v2/Customers/index.ts
  • src/api/v2/Cycles/WorkItems.ts
  • src/api/v2/Cycles/index.ts
  • src/api/v2/Estimates/Points.ts
  • src/api/v2/Estimates/index.ts
  • src/api/v2/Features.ts
  • src/api/v2/GroupSync/Config.ts
  • src/api/v2/GroupSync/ProjectMappings.ts
  • src/api/v2/GroupSync/WorkspaceMappings.ts
  • src/api/v2/GroupSync/index.ts
  • src/api/v2/Initiatives/Labels.ts
  • src/api/v2/Initiatives/Projects.ts
  • src/api/v2/Initiatives/WorkItems.ts
  • src/api/v2/Initiatives/index.ts
  • src/api/v2/Intakes.ts
  • src/api/v2/Invitations.ts
  • src/api/v2/Labels.ts
  • src/api/v2/Members.ts
  • src/api/v2/Milestones/WorkItems.ts
  • src/api/v2/Milestones/index.ts
  • src/api/v2/Modules/WorkItems.ts
  • src/api/v2/Modules/index.ts
  • src/api/v2/Pages.ts
  • src/api/v2/PermissionSchemes.ts
  • src/api/v2/Permissions.ts
  • src/api/v2/Project.ts
  • src/api/v2/ProjectWorklogs.ts
  • src/api/v2/Projects.ts
  • src/api/v2/Releases/Changelog.ts
  • src/api/v2/Releases/Comments.ts
  • src/api/v2/Releases/Labels.ts
  • src/api/v2/Releases/Links.ts
  • src/api/v2/Releases/Tags.ts
  • src/api/v2/Releases/WorkItems.ts
  • src/api/v2/Releases/index.ts
  • src/api/v2/Roles.ts
  • src/api/v2/States.ts
  • src/api/v2/Stickies.ts
  • src/api/v2/Teamspaces.ts
  • src/api/v2/UserAssets.ts
  • src/api/v2/UsersMe.ts
  • src/api/v2/Views.ts
  • src/api/v2/WebhookLogs.ts
  • src/api/v2/Webhooks.ts
  • src/api/v2/Wiki.ts
  • src/api/v2/WikiPages.ts
  • src/api/v2/WorkItemProperties/Options.ts
  • src/api/v2/WorkItemProperties/index.ts
  • src/api/v2/WorkItemRelationDefinitions.ts
  • src/api/v2/WorkItemTemplates/ProjectTemplates.ts
  • src/api/v2/WorkItemTemplates/WorkspaceTemplates.ts
  • src/api/v2/WorkItemTemplates/index.ts
  • src/api/v2/WorkItemTypes/Properties.ts
  • src/api/v2/WorkItemTypes/index.ts
  • src/api/v2/WorkItems/Activities.ts
  • src/api/v2/WorkItems/Attachments.ts
  • src/api/v2/WorkItems/Comments.ts
  • src/api/v2/WorkItems/Dependencies.ts
  • src/api/v2/WorkItems/Links.ts
  • src/api/v2/WorkItems/Relations.ts
  • src/api/v2/WorkItems/WorkLogs.ts
  • src/api/v2/WorkItems/index.ts
  • src/api/v2/Workflows/States.ts
  • src/api/v2/Workflows/Transitions.ts
  • src/api/v2/Workflows/index.ts
  • src/api/v2/Workspace.ts
  • src/api/v2/WorkspaceMembers.ts
  • src/api/v2/WorkspaceViews.ts
  • src/api/v2/WorkspaceWorkItemProperties/Contexts.ts
  • src/api/v2/WorkspaceWorkItemProperties/Options.ts
  • src/api/v2/WorkspaceWorkItemProperties/index.ts
  • src/api/v2/WorkspaceWorkItemTypes/Properties.ts
  • src/api/v2/WorkspaceWorkItemTypes/index.ts
  • src/api/v2/WorkspaceWorkItems.ts
  • src/api/v2/index.ts
  • src/api/v2/kernel/bulk.ts
  • src/api/v2/kernel/pagination.ts
  • src/api/v2/kernel/resource.ts
  • src/api/v2/kernel/transport.ts
  • src/client/plane-client.ts
  • src/errors/PlaneApiError.ts
  • src/errors/PlaneNetworkError.ts
  • src/errors/index.ts
  • src/index.ts
  • src/models/v2/Artifact.ts
  • src/models/v2/AuditLog.ts
  • src/models/v2/Automation.ts
  • src/models/v2/AutomationActivity.ts
  • src/models/v2/AutomationEdge.ts
  • src/models/v2/AutomationNode.ts
  • src/models/v2/Bridge.ts
  • src/models/v2/Collection.ts
  • src/models/v2/Customer.ts
  • src/models/v2/CustomerProperty.ts
  • src/models/v2/CustomerPropertyValue.ts
  • src/models/v2/CustomerRequest.ts
  • src/models/v2/Cycle.ts
  • src/models/v2/CycleTransfer.ts
  • src/models/v2/Estimate.ts
  • src/models/v2/EstimatePoint.ts
  • src/models/v2/Feature.ts
  • src/models/v2/GroupMapping.ts
  • src/models/v2/GroupSyncConfig.ts
  • src/models/v2/Initiative.ts
  • src/models/v2/InitiativeLabel.ts
  • src/models/v2/IntakeWorkItem.ts
  • src/models/v2/Label.ts
  • src/models/v2/Member.ts
  • src/models/v2/Milestone.ts
  • src/models/v2/Module.ts
  • src/models/v2/Page.ts
  • src/models/v2/Permission.ts
  • src/models/v2/PermissionScheme.ts
  • src/models/v2/Project.ts
  • src/models/v2/ProjectRoleDistribution.ts
  • src/models/v2/Release.ts
  • src/models/v2/ReleaseChangelog.ts
  • src/models/v2/ReleaseComment.ts
  • src/models/v2/ReleaseLabel.ts
  • src/models/v2/ReleaseLink.ts
  • src/models/v2/ReleaseTag.ts
  • src/models/v2/Role.ts
  • src/models/v2/State.ts
  • src/models/v2/Sticky.ts
  • src/models/v2/Teamspace.ts
  • src/models/v2/UserAsset.ts
  • src/models/v2/View.ts
  • src/models/v2/Webhook.ts
  • src/models/v2/WebhookLog.ts
  • src/models/v2/WhoAmI.ts
  • src/models/v2/WorkItem.ts
  • src/models/v2/WorkItemActivity.ts
  • src/models/v2/WorkItemAttachment.ts
  • src/models/v2/WorkItemComment.ts
  • src/models/v2/WorkItemDependency.ts
  • src/models/v2/WorkItemLink.ts
  • src/models/v2/WorkItemProperty.ts
  • src/models/v2/WorkItemPropertyContext.ts
  • src/models/v2/WorkItemPropertyOption.ts
  • src/models/v2/WorkItemRelation.ts
  • src/models/v2/WorkItemRelationDefinition.ts
  • src/models/v2/WorkItemTemplate.ts
  • src/models/v2/WorkItemType.ts
  • src/models/v2/WorkItemWorklog.ts
  • src/models/v2/Workflow.ts
  • src/models/v2/WorkflowState.ts
  • src/models/v2/WorkflowTransition.ts
  • src/models/v2/WorklogSummary.ts
  • src/models/v2/WorkspaceAsset.ts
  • src/models/v2/WorkspaceGroupMapping.ts
  • src/models/v2/WorkspaceInvite.ts
  • src/models/v2/common.ts
  • src/models/v2/index.ts
  • tests/e2e/v2/artifacts.e2e.test.ts
  • tests/e2e/v2/assets.e2e.test.ts
  • tests/e2e/v2/audit-logs.e2e.test.ts
  • tests/e2e/v2/automations.e2e.test.ts
  • tests/e2e/v2/bulk.e2e.test.ts
  • tests/e2e/v2/collections.e2e.test.ts
  • tests/e2e/v2/crud.e2e.test.ts
  • tests/e2e/v2/customer-properties.e2e.test.ts
  • tests/e2e/v2/customers.e2e.test.ts
  • tests/e2e/v2/cycle-actions.e2e.test.ts
  • tests/e2e/v2/cycles-modules-milestones.e2e.test.ts
  • tests/e2e/v2/errors.e2e.test.ts
  • tests/e2e/v2/estimates.e2e.test.ts
  • tests/e2e/v2/features.e2e.test.ts
  • tests/e2e/v2/find-by-name.e2e.test.ts
  • tests/e2e/v2/full-scenario.e2e.test.ts
  • tests/e2e/v2/group-sync.e2e.test.ts
  • tests/e2e/v2/initiatives.e2e.test.ts
  • tests/e2e/v2/intakes.e2e.test.ts
  • tests/e2e/v2/invitations.e2e.test.ts
  • tests/e2e/v2/members.e2e.test.ts
  • tests/e2e/v2/milestone-work-items.e2e.test.ts
  • tests/e2e/v2/module-work-items.e2e.test.ts
  • tests/e2e/v2/pages.e2e.test.ts
  • tests/e2e/v2/pagination.e2e.test.ts
  • tests/e2e/v2/permission-schemes.e2e.test.ts
  • tests/e2e/v2/permissions.e2e.test.ts
  • tests/e2e/v2/project-work-item-types-flow.e2e.test.ts
  • tests/e2e/v2/project-worklogs-summary.e2e.test.ts
  • tests/e2e/v2/projects.e2e.test.ts
  • tests/e2e/v2/releases.e2e.test.ts
  • tests/e2e/v2/roles.e2e.test.ts
  • tests/e2e/v2/stickies.e2e.test.ts
  • tests/e2e/v2/support/client.ts
  • tests/e2e/v2/support/env.ts
  • tests/e2e/v2/support/names.ts
  • tests/e2e/v2/support/project.ts
  • tests/e2e/v2/support/specs.ts
  • tests/e2e/v2/support/suite.ts
  • tests/e2e/v2/support/work-item-type-mode.ts
  • tests/e2e/v2/sweep-leftover-projects.e2e.test.ts
  • tests/e2e/v2/teamspaces.e2e.test.ts
  • tests/e2e/v2/upsert.e2e.test.ts
  • tests/e2e/v2/users-me.e2e.test.ts
  • tests/e2e/v2/views.e2e.test.ts
  • tests/e2e/v2/webhook-logs.e2e.test.ts
  • tests/e2e/v2/webhooks.e2e.test.ts
  • tests/e2e/v2/work-item-comments.e2e.test.ts
  • tests/e2e/v2/work-item-properties.e2e.test.ts
  • tests/e2e/v2/work-item-relation-definitions.e2e.test.ts
  • tests/e2e/v2/work-item-relations.e2e.test.ts
  • tests/e2e/v2/work-item-subresources.e2e.test.ts
  • tests/e2e/v2/work-item-templates.e2e.test.ts
  • tests/e2e/v2/work-item-types.e2e.test.ts
  • tests/e2e/v2/work-items.e2e.test.ts
  • tests/e2e/v2/workflows.e2e.test.ts
  • tests/e2e/v2/workspace-work-item-types-flow.e2e.test.ts
  • tests/unit/v2/artifacts.test.ts
  • tests/unit/v2/assets.test.ts
  • tests/unit/v2/audit-logs.test.ts
  • tests/unit/v2/automations.test.ts
  • tests/unit/v2/bridges.test.ts
  • tests/unit/v2/bulk.test.ts
  • tests/unit/v2/collections.test.ts
  • tests/unit/v2/constants.test.ts
  • tests/unit/v2/customer-properties.test.ts
  • tests/unit/v2/customers.test.ts
  • tests/unit/v2/cycle-actions.test.ts
  • tests/unit/v2/cycles-modules-milestones.test.ts
  • tests/unit/v2/e2e-project-identifier.test.ts
  • tests/unit/v2/estimates.test.ts
  • tests/unit/v2/features.test.ts
  • tests/unit/v2/field-projection.test.ts
  • tests/unit/v2/find-one.test.ts
  • tests/unit/v2/group-sync.test.ts
  • tests/unit/v2/initiatives.test.ts
  • tests/unit/v2/intakes.test.ts
  • tests/unit/v2/invitations.test.ts
  • tests/unit/v2/labels.test.ts
  • tests/unit/v2/locators.test.ts
  • tests/unit/v2/members.test.ts
  • tests/unit/v2/milestone-work-items.test.ts
  • tests/unit/v2/module-work-items.test.ts
  • tests/unit/v2/operations-coverage.test.ts
  • tests/unit/v2/pages.test.ts
  • tests/unit/v2/pagination.test.ts
  • tests/unit/v2/permission-schemes.test.ts
  • tests/unit/v2/permissions.test.ts
  • tests/unit/v2/project-worklogs-summary.test.ts
  • tests/unit/v2/projects.test.ts
  • tests/unit/v2/releases.test.ts
  • tests/unit/v2/resource.test.ts
  • tests/unit/v2/roles.test.ts
  • tests/unit/v2/states.test.ts
  • tests/unit/v2/stickies.test.ts
  • tests/unit/v2/teamspaces.test.ts
  • tests/unit/v2/transport.test.ts
  • tests/unit/v2/users-me.test.ts
  • tests/unit/v2/views.test.ts
  • tests/unit/v2/webhook-logs.test.ts
  • tests/unit/v2/webhooks.test.ts
  • tests/unit/v2/wiki-pages.test.ts
  • tests/unit/v2/work-item-comments.test.ts
  • tests/unit/v2/work-item-properties.test.ts
  • tests/unit/v2/work-item-relation-definitions.test.ts
  • tests/unit/v2/work-item-relations.test.ts
  • tests/unit/v2/work-item-subresources.test.ts
  • tests/unit/v2/work-item-templates.test.ts
  • tests/unit/v2/work-item-types.test.ts
  • tests/unit/v2/work-items.test.ts
  • tests/unit/v2/workflows.test.ts
  • tests/unit/v2/workspace-members.test.ts
  • tests/unit/v2/workspace-views.test.ts
  • tests/unit/v2/workspace-work-item-types.test.ts
  • tests/unit/v2/workspace-work-items.test.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@makeplane

makeplane Bot commented Aug 30, 2026

Copy link
Copy Markdown

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

Comment thread tests/e2e/v2/full-scenario.e2e.test.ts Outdated
const propertyId = severity.id;
cleanup.push(["property", () => ws.workItemProperties.delete(propertyId)]);
await ws.workItemTypes.properties.attach(typeId, [propertyId]);
cleanup.push(["detach", () => ws.workItemTypes.properties.detach(typeId, propertyId)]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link and unlink as a verb feels more aligned with our web app CTAs

Comment thread tests/e2e/v2/full-scenario.e2e.test.ts Outdated
cleanup.push(["sub-task", () => proj.workItems.delete(subtask.id)]);
expect(subtask.parent_id).toBe(item.id);

await proj.cycles.manageWorkItems(sprint.id, { add: [item.id, subtask.id] });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest splitting this into add_work_items / remove_work_items instead of a single method with an action param.

or we can also go with proj.cycles.workitems.add / remove

With one method, add=[], remove=[] and add=[x], remove=[x] are both expressible but meaningless, so we end up validating at runtime instead of letting the signature enforce it.

const handbook = await ws.wiki.collections.create({ name: `Handbook ${tag}` });
cleanup.push(["collection", () => ws.wiki.collections.delete(handbook.id)]);
const runbook = await ws.wiki.pages.create({ name: "Login runbook", collection_id: handbook.id });
cleanup.push(["wiki page", () => archiveThenDelete(ws.wiki.pages, runbook.id)]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should also give archiveThenDelete as a inbuilt method for all resources which follows this pattern

expect((await proj.workItemTypes.list()).data.some((row) => row.id === bugType.id)).toBe(true);

// ---- 3. States and labels --------------------------------------------------
const todo = await proj.states.findByName("Todo"); // seeded with every new project

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if we have two states with same name but in different state groups? we should accept a state group as well i think

…ookups (review feedback)

Reviewer feedback on the v2 surface (runs/sdk-v2-foundation/plans/2026-09-03-team-feedback.md, items 1, 2 and the SDK-now half of 5).

Renames (work item type properties, project + workspace scoped):
- WorkItemTypeProperties.attach -> link, .detach -> unlink
- WorkspaceWorkItemTypeProperties.attach -> link, .detach -> unlink
  (operations map keys stay attach/detach: golden operationIds)

Removed every manage* method in favour of add(parentId, ids) / remove(parentId, ids)
bridge verbs that send one verb per call and resolve to the plain id array:
- Cycles.manageWorkItems      -> cycles.workItems.add/remove      (new CycleWorkItems)
- Modules.manageWorkItems     -> modules.workItems.add/remove     (new ModuleWorkItems)
- Milestones.manageWorkItems  -> milestones.workItems.add/remove  (new MilestoneWorkItems)
- Customers.manageWorkItems   -> customers.workItems.add/remove   (new CustomerWorkItems)
- Releases.manageWorkItems    -> releases.workItems.add/remove    (new ReleaseWorkItems)
- Releases.manageLabels       -> releases.labels.add/remove       (on the ReleaseLabels catalog)
- Initiatives.manageWorkItems -> initiatives.workItems.add/remove (new InitiativeWorkItems)
- Initiatives.manageProjects  -> initiatives.projects.add/remove  (new InitiativeProjects)
- Initiatives.manageLabels    -> initiatives.labels.add/remove    (on the InitiativeLabels catalog)
- CollectionMembers.manage    -> collections.members.add(collectionId, CollectionMemberAddItem[]) / .remove(collectionId, userIds)
- CollectionPages.manage      -> collections.pages.add/remove

Kernel: V2Resource.doBridge/doBridgeAt replace the hand-rolled transport.request copies;
1..BRIDGE_MAX_IDS (100) ids enforced client-side (RangeError/TypeError before any request).
The *ManageRequest/*ManageResponse model types are gone from the public surface (one
internal models/v2/Bridge.ts shape backs the kernel); the types-bundle export snapshot is
regenerated intentionally (1450 -> 1425 entries).

New server-side lookups via doFindOne:
- Roles.findBySlug(slug, { namespace? })
- EstimatePoints.findByKey(estimateId, key)
- WorkItemPropertyOptions.findByName / WorkspaceWorkItemPropertyOptions.findByName / WorkItemPropertyContexts.findByName (propertyId, name)

Cycles/Modules/Milestones moved from flat files into folders (index.ts + WorkItems.ts) per the
sub-resource convention; import paths are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QwQ1tqb3831E7rezg5zqs
@Prashant-Surya

Copy link
Copy Markdown
Member Author

Review feedback landed as one commit on top (3a244c0), so the delta is reviewable on its own. Public method tree stays identical to the Python SDK (513 = 513 after normalisation).

Feedback What changed
attach/detachlink/unlink (work item type properties, matches the web app's "Unlink property") workItemTypes.properties.link(typeId, ids) / .unlink(typeId, id) in both scopes
manageWorkItemsx.y.workItems.add / remove Every manage* is gone. Bridges are sub-resources: proj.cycles.workItems.add(cycleId, ids) / .remove(...), same for modules, milestones, customers, releases, initiatives (.workItems, .projects), ws.releases.labels.add(releaseId, ids), ws.initiatives.labels.add(...), ws.wiki.collections.pages.add(...), .members.add(...). Each verb sends only its own key; 0 or >100 ids throw a RangeError before any request; resolves to the ids actually changed.
Lookup by slug / name ws.roles.findBySlug(slug, { namespace }), proj.estimates.points.findByKey(estimateId, key), findByName on work item properties (both scopes), property options and contexts. name on properties is the machine key (story-points); lookup by the UI label needs a ?display_name= filter, which is on a plane-ee branch pending spec review, and findByDisplayName will follow it.
archiveThenDelete Parked. Only pages gate delete on archive, and that reads as an app defect to fix server-side rather than mirror here.
findByName + state group Skipped: state names are unique per project/workspace under governance.
Workspace by slug No workspace endpoint exists in v1 or v2 today; GET /api/v2/workspaces/{slug}/ (+ list) is on a plane-ee branch pending spec review, then ws.retrieve() lands here.
Batching chained calls On hold. Chaining is zero-I/O (only the leaf call hits the network); there is no multi-op batch endpoint, and the per-resource bulk* methods are the batching primitive.

Checks on the new commit: jest tests/unit/v2 473 passed, operations coverage 406/406, tsc 0, oxlint at baseline, build + export snapshot regenerated (1425 entries). Live e2e not re-run (dev API was stopped).

@coldtea-pr-lens

coldtea-pr-lens Bot commented Sep 3, 2026

Copy link
Copy Markdown

◈ PR Lens

🟢 +18 new · 🟠 ~2 changed · 🔴 -0 removed · 3 flows · 94 files · commit 3a244c0


Architecture

Architecture diagram for makeplane/plane-node-sdk at 3a244c0

20 components touched across 6 lanes.

Open full size


Inside the changed components — 4 views

Component view — V2 Kernel & Transport

Internal modules of the v2 transport engine, resource base class, pagination iterator, and OpenAPI constants validation.

Architecture view of Component view — V2 Kernel & Transport in makeplane/plane-node-sdk

Component view — V2 Locators & Scope Chaining

Zero-I/O chained locator hierarchy binding workspace, project, and wiki path scopes without network requests.

Architecture view of Component view — V2 Locators & Scope Chaining in makeplane/plane-node-sdk

Component view — V2 Work Items & Project Tracking

Work items, sub-resources, cycles, modules, milestone bridges, and planning resources connected to the V2 resource base.

Architecture view of Component view — V2 Work Items & Project Tracking in makeplane/plane-node-sdk

Component view — V2 Governance, Workflows & Catalog

Workspace catalog types, custom work item properties, workflow states and transitions, RBAC permissions, and automations.

Architecture view of Component view — V2 Governance, Workflows & Catalog in makeplane/plane-node-sdk

Data flow

Data flow diagram for makeplane/plane-node-sdk at 3a244c0

Chained scope resolution and sparse field query · Membership bridge association · Bulk write execution and failure checking

Open full size


The other flows — 2 sequences

Membership bridge association

Sequence diagram of Membership bridge association in makeplane/plane-node-sdk

Bulk write execution and failure checking

Sequence diagram of Bulk write execution and failure checking in makeplane/plane-node-sdk

Drill down
Client Layer — 2 components
🟡 CHANGED PlaneClient

Main SDK entry point, updated to initialize the new v2 namespace alongside existing v1 resource bindings.

🟢 NEW V2 Namespace

Entry point for Plane API v2 on PlaneClient.v2, exposing top-level resources and locator factories for zero-I/O scope binding.

Transport & Kernel Layer — 6 components
🟡 CHANGED SDK Errors

RFC 9457 structured error handling with PlaneApiError, PlaneNetworkError, and identity lookup errors.

🟢 NEW V2 Kernel

Core runtime for API v2 providing Axios transport, resource base methods, parameter validation, pagination generators, and bulk helpers.

🟢 NEW V2 Transport

Axios-based transport targeting /api/v2 with API key / Bearer token authentication and RFC 9457 error decoding.

🟢 NEW V2Resource Base

Abstract base class for all v2 resources implementing CRUD, URL interpolation, query validation against generated constants, bulk operations, and bridge helpers.

🟢 NEW Pagination & Bulk Helpers

Async generator for cursor and offset pagination with loop detection, plus error extraction for partial batch writes.

🟢 NEW Generated OpenAPI Constants

Compile-time metadata generated from the OpenAPI spec defining valid fields, order_by parameters, expand options, and bulk limits.

Work Items & Tracking — 3 components
🟢 NEW V2 WorkItems Resource

V2 project and workspace work item operations, human key lookups, bulk write APIs, and sub-resource handlers.

🟢 NEW V2 Cycles, Modules & Milestones

V2 project cycle, module, and milestone management including membership bridge operations for assigning work items.

🟢 NEW V2 Project Planning Resources

Project-scoped states, labels, estimate points, intakes, pages, views, and worklog tracking.

Workspace & Projects — 2 components
🟢 NEW Workspace Locator

Zero-I/O locator binding workspace slug to expose workspace-scoped resources and create project-scoped locators.

🟢 NEW Project Locator

Zero-I/O locator binding project identifier to expose project-scoped resources like work items, cycles, modules, states, and workflows.

Governance & Workflows — 2 components
🟢 NEW V2 Workspace Catalog & Types

Workspace and project-level work item types, custom properties, options, relations definitions, and templates.

🟢 NEW V2 Governance & Workflows

Workflow transitions, automations (workspace and project), RBAC roles, permissions, permission schemes, group sync, and audit logging.

Collaboration & Integrations — 5 components
🟢 NEW Wiki Locator

Workspace-scoped wiki locator providing access to wiki pages and collection management.

🟢 NEW V2 Releases Resource

V2 release lifecycle management including release work item bridges, changelogs, labels, tags, comments, and links.

🟢 NEW V2 Wiki & Collections

Wiki pages, document collections with membership management, and stickies.

🟢 NEW V2 Customers Resource

Customer tracking, customer properties, request management, and customer-associated work items.

🟢 NEW V2 Integrations & Administration

Webhooks, webhook delivery logs, file/asset uploads, artifacts, user identity, invitations, teamspaces, initiatives, and workspace views.


View

  • Architecture lens
  • Data flow lens
  • Expand every detail
  • Show unchanged neighbours

Tip

Would you rather run it from CI on a key of your own? Add .github/workflows/pr-lens.yml with coldteadotai/pr-lens/packages/action@v0 and a model key in your repository secrets, say GEMINI_API_KEY. The Action asks Gemini by default, or OpenAI and any endpoint speaking /chat/completions through its provider input.

🪧 More tips
  • Run PR Lens on your own machine: npx skills add coldteadotai/pr-lens installs the agent skill. Then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."
  • Draw a diff before it is even a pull request: npx @coldtea/pr-lens-cli analyze --base origin/main reads the diff with your own model key, and npx @coldtea/pr-lens-cli render .pr-lens/graph.json draws the same lenses on your machine.
  • The boxes under View are live. Tick Architecture lens or Data flow lens to choose which diagrams appear, or Expand every detail to open every drill-down at once. The comment redraws in place a few seconds later.
  • Show unchanged neighbours lists the components this change did not touch alongside the ones it did, so the drill-down shows what the changed code sits next to.
  • GitHub will not let you zoom an image in a comment. The link under each diagram opens it full size on a page of its own, where you can.
  • The CLI's render picks up .github/pr-lens.yml automatically and applies your corrections (renames, exclusions, lane pins) at draw time.
  • PR Lens is free for open source. A star on the repository is what keeps it going.
  • Push a new commit and the whole comment re-renders for the new head. An older run never overwrites a newer one, so a slow render cannot put a stale diagram back.
  • The diagrams follow your GitHub theme, so dark mode gets the dark render and light mode the light one, and the moving dots show this pull request's data in motion.

◈ Rendered by PR Lens · crafted with ❤️ by the Coldtea team · Come say hi on Discord

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants