@crvouga/mockingbird-service-plane 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1011,7 +1011,40 @@ var decodeBody = (contentType, bytes) => {
1011
1011
  return { kind: "bytes", value: bytes };
1012
1012
  };
1013
1013
  var readBody = async (message) => {
1014
- const bytes = new Uint8Array(await message.arrayBuffer());
1014
+ if (!(message instanceof Request) || !message.body) {
1015
+ if (message instanceof Request)
1016
+ message.signal.throwIfAborted();
1017
+ return decodeBody(message.headers.get("content-type"), new Uint8Array(await message.arrayBuffer()));
1018
+ }
1019
+ message.signal.throwIfAborted();
1020
+ const reader = message.body.getReader();
1021
+ const cancel = () => {
1022
+ void reader.cancel(message.signal.reason).catch(() => {
1023
+ });
1024
+ };
1025
+ message.signal.addEventListener("abort", cancel, { once: true });
1026
+ const chunks = [];
1027
+ let size = 0;
1028
+ try {
1029
+ for (; ; ) {
1030
+ message.signal.throwIfAborted();
1031
+ const { done, value } = await reader.read();
1032
+ message.signal.throwIfAborted();
1033
+ if (done)
1034
+ break;
1035
+ chunks.push(value);
1036
+ size += value.byteLength;
1037
+ }
1038
+ } finally {
1039
+ message.signal.removeEventListener("abort", cancel);
1040
+ reader.releaseLock();
1041
+ }
1042
+ const bytes = new Uint8Array(size);
1043
+ let offset = 0;
1044
+ for (const chunk of chunks) {
1045
+ bytes.set(chunk, offset);
1046
+ offset += chunk.byteLength;
1047
+ }
1015
1048
  return decodeBody(message.headers.get("content-type"), bytes);
1016
1049
  };
1017
1050
 
@@ -1790,7 +1823,42 @@ var verifyOperations = (document2, handlers) => {
1790
1823
  }
1791
1824
  return problems;
1792
1825
  };
1793
- var honoPath = (template) => template.replace(/\{([^}]+)\}/g, ":$1");
1826
+ var escapePattern = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1827
+ var serviceRoute = (template) => {
1828
+ const names = [];
1829
+ let pattern = "", end = 0;
1830
+ for (const match of template.matchAll(/\{([^}]+)\}/g)) {
1831
+ pattern += `${escapePattern(template.slice(end, match.index))}([^/]+?)`;
1832
+ const name = match[1];
1833
+ if (!name)
1834
+ throw new Error(`Invalid OpenAPI route template: ${template}`);
1835
+ names.push(name);
1836
+ end = match.index + match[0].length;
1837
+ }
1838
+ pattern += escapePattern(template.slice(end));
1839
+ const matcher = new RegExp(`^${pattern}$`);
1840
+ const path = template.split("/").map((segment, index) => {
1841
+ if (!segment.includes("{"))
1842
+ return segment;
1843
+ const literal = /^\{([^}]+)\}$/.exec(segment);
1844
+ if (literal)
1845
+ return `:${literal[1]}`;
1846
+ let expression = "", offset = 0;
1847
+ for (const match of segment.matchAll(/\{[^}]+\}/g)) {
1848
+ expression += `${escapePattern(segment.slice(offset, match.index))}[^/]+?`;
1849
+ offset = match.index + match[0].length;
1850
+ }
1851
+ expression += escapePattern(segment.slice(offset));
1852
+ return `:mockingbirdSegment${index}{${expression}}`;
1853
+ }).join("/");
1854
+ return {
1855
+ path,
1856
+ params: (pathname) => {
1857
+ const values = matcher.exec(pathname);
1858
+ return Object.fromEntries(names.map((name, index) => [name, decodeURIComponent(values?.[index + 1] ?? "")]));
1859
+ }
1860
+ };
1861
+ };
1794
1862
  var routeOrder = (a, b) => {
1795
1863
  const sa = a.path.split("/");
1796
1864
  const sb = b.path.split("/");
@@ -1825,6 +1893,7 @@ var createService = (options) => {
1825
1893
  for (const operation of operations) {
1826
1894
  const metadata = operationMetadata(operation.operation);
1827
1895
  const handler = options.handlers[operation.operationId];
1896
+ const registeredRoute = serviceRoute(operation.path);
1828
1897
  const route = async (c) => {
1829
1898
  const request = c.req.raw;
1830
1899
  if (!metadata.supported || !handler) {
@@ -1834,7 +1903,7 @@ var createService = (options) => {
1834
1903
  const context = {
1835
1904
  request,
1836
1905
  url,
1837
- params: c.req.param(),
1906
+ params: registeredRoute.params(url.pathname),
1838
1907
  query: queryOf(url),
1839
1908
  body: await readBody(request),
1840
1909
  sqlite: options.sqlite,
@@ -1846,7 +1915,7 @@ var createService = (options) => {
1846
1915
  const short = await options.before?.(context);
1847
1916
  return withIssues(request, short ?? await handler(context));
1848
1917
  };
1849
- app.on(operation.method.toUpperCase(), honoPath(operation.path), route);
1918
+ app.on(operation.method.toUpperCase(), registeredRoute.path, route);
1850
1919
  }
1851
1920
  return {
1852
1921
  app,
@@ -2315,7 +2384,7 @@ var stateAdminRoutes = (routes) => {
2315
2384
  };
2316
2385
 
2317
2386
  // ../core/dist/version.js
2318
- var PACKAGE_VERSION = true ? "2.1.0" : UNRELEASED_VERSION;
2387
+ var PACKAGE_VERSION = true ? "2.2.0" : UNRELEASED_VERSION;
2319
2388
 
2320
2389
  // ../core/dist/webhooks.js
2321
2390
  var json4 = (status, body) => new Response(JSON.stringify(body), {
@@ -3131,9 +3200,9 @@ var presetRoutes = (presets, runtime, adminPrefix) => ({
3131
3200
  });
3132
3201
 
3133
3202
  // src/generated/openapi.ts
3134
- var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Plane REST API (Mockingbird subset)","description":"Stateful mock subset of Plane's public REST API v1 for one project: work items (cursor-paginated list, get, create, patch), comments, links, states and labels. Hand-authored from Plane's API reference and the consumer's zod schemas (plane-response.ts).\\n","version":"1","x-mockingbird-upstream":{"note":"Shapes from https://developers.plane.so/api-reference; consumer: apps/backend/src/modules/bug-reports/adapters/native-fetch-plane.adapter.ts, plane-http-client.ts, plane-response.ts."}},"servers":[{"url":"https://api.plane.so"}],"security":[{"apiKey":[]}],"paths":{"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/":{"get":{"operationId":"ListWorkItems","description":"Cursor-paginated work items (\`cursor=<per_page>:<page>:<is_prev>\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItemPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/OrderBy"}]},"post":{"operationId":"CreateWorkItem","description":"Create a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkItemBody"}}}}},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"GetWorkItem","description":"One work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The work item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}}},"patch":{"operationId":"UpdateWorkItem","description":"Partial update (the consumer sends \`state\` or \`labels\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkItemBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/comments/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"ListComments","description":"Comments on a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateComment","description":"Add a comment.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/links/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"ListLinks","description":"Links on a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateLink","description":"Attach a link (the same URL twice is a 400).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The URL is already linked (carries the existing link id)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/states/":{"get":{"operationId":"ListStates","description":"The project's workflow states.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatePage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]},"/api/v1/workspaces/{slug}/projects/{project_id}/labels/":{"get":{"operationId":"ListLabels","description":"The project's labels.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabelPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateLabel","description":"Create a label (a duplicate name is a 409 carrying the existing id).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Label"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Duplicate name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLabelBody"}}}}},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"}},"parameters":{"Slug":{"name":"slug","in":"path","required":true,"schema":{"type":"string","enum":["acme"]}},"ProjectId":{"name":"project_id","in":"path","required":true,"schema":{"type":"string","enum":["33333333-3333-4333-8333-333333333333"]}},"WorkItemId":{"name":"work_item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"work_item","missing":"00000000-0000-4000-8000-000000000000"}}},"PerPage":{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},"Cursor":{"name":"cursor","in":"query","required":false,"schema":{"type":"string","enum":["2:0:0","2:1:0","2:2:0","100:0:0"]}},"OrderBy":{"name":"order_by","in":"query","required":false,"schema":{"type":"string","enum":["-created_at","created_at","sequence_id","-sequence_id","name","-name"]}}},"responses":{"Unauthorized":{"description":"Missing or invalid X-API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"NotFound":{"description":"Unknown workspace, project or item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Throttled":{"description":"Rate limited (60 requests per minute per key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}},"schemas":{"WorkItem":{"type":"object","required":["id","sequence_id","name","description_html","state","labels","priority","created_at","updated_at","project","workspace"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"work_item","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"sequence_id":{"type":"integer"},"name":{"type":"string"},"description_html":{"type":"string"},"description_stripped":{"type":["string","null"]},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]},"state":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"labels":{"type":"array","items":{"type":"string","x-mockingbird-volatile":{"kind":"id"}}},"assignees":{"type":"array","items":{"type":"string"}},"parent":{"type":["string","null"]},"start_date":{"type":["string","null"]},"target_date":{"type":["string","null"]},"completed_at":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"archived_at":{"type":["string","null"]},"is_draft":{"type":"boolean"},"sort_order":{"type":"number"},"project":{"type":"string"},"workspace":{"type":"string"},"created_by":{"type":["string","null"]},"updated_by":{"type":["string","null"]},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"State":{"type":"object","required":["id","name","group","color","sequence","default"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"state","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"group":{"type":"string","enum":["backlog","unstarted","started","completed","cancelled","triage"]},"color":{"type":"string"},"sequence":{"type":"number"},"default":{"type":"boolean"},"description":{"type":"string"},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Label":{"type":"object","required":["id","name","color"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"label","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"color":{"type":"string"},"description":{"type":"string"},"parent":{"type":["string","null"]},"sort_order":{"type":"number"},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Comment":{"type":"object","required":["id","comment_html","issue","created_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"comment_html":{"type":"string"},"comment_stripped":{"type":"string"},"access":{"type":"string"},"issue":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"actor":{"type":["string","null"]},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Link":{"type":"object","required":["id","url","title","issue","created_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"url":{"type":"string"},"title":{"type":["string","null"]},"metadata":{"type":"object"},"issue":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"WorkItemPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/WorkItem"}}}},"StatePage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/State"}}}},"LabelPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Label"}}}},"CommentPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}},"LinkPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Link"}}}},"CreateWorkItemBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description_html":{"type":"string","maxLength":2000},"state":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"state","missing":"00000000-0000-4000-8000-000000000000"}},"labels":{"type":"array","maxItems":3,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"label","missing":"00000000-0000-4000-8000-000000000000"}}},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]}}},"UpdateWorkItemBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description_html":{"type":"string","maxLength":2000},"state":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"state","missing":"00000000-0000-4000-8000-000000000000"}},"labels":{"type":"array","maxItems":3,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"label","missing":"00000000-0000-4000-8000-000000000000"}}},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]}}},"CreateCommentBody":{"type":"object","required":["comment_html"],"properties":{"comment_html":{"type":"string","minLength":1,"maxLength":2000},"access":{"type":"string","enum":["INTERNAL","EXTERNAL"]}}},"CreateLinkBody":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","pattern":"^https://","maxLength":200},"title":{"type":"string","minLength":1,"maxLength":255}}},"CreateLabelBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"description":{"type":"string","maxLength":255}}},"ErrorBody":{"type":"object","properties":{"error":{"type":"string"},"detail":{"type":"string"},"id":{"type":"string"}}},"ValidationError":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}}}`);
3135
- var operationIds = ["ListWorkItems", "CreateWorkItem", "GetWorkItem", "UpdateWorkItem", "ListComments", "CreateComment", "ListLinks", "CreateLink", "ListStates", "ListLabels", "CreateLabel"];
3136
- var supportedOperationIds = ["ListWorkItems", "CreateWorkItem", "GetWorkItem", "UpdateWorkItem", "ListComments", "CreateComment", "ListLinks", "CreateLink", "ListStates", "ListLabels", "CreateLabel"];
3203
+ var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Plane REST API (Mockingbird subset)","description":"Stateful mock subset of Plane's public REST API v1 for one project: work items (cursor-paginated list, get, create, patch), comments, links, states, labels, cycles and work-item types. Hand-authored from Plane's API reference and the consumer's zod schemas (plane-response.ts).\\n","version":"1","x-mockingbird-upstream":{"note":"Shapes from https://developers.plane.so/api-reference; consumer: apps/backend/src/modules/bug-reports/adapters/native-fetch-plane.adapter.ts, plane-http-client.ts, plane-response.ts."}},"servers":[{"url":"https://api.plane.so"}],"security":[{"apiKey":[]}],"paths":{"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/":{"get":{"operationId":"ListWorkItems","description":"Cursor-paginated work items (\`cursor=<per_page>:<page>:<is_prev>\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItemPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/OrderBy"}]},"post":{"operationId":"CreateWorkItem","description":"Create a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkItemBody"}}}}},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"GetWorkItem","description":"One work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The work item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}}},"patch":{"operationId":"UpdateWorkItem","description":"Partial update (the consumer sends \`state\` or \`labels\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkItemBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/comments/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"ListComments","description":"Comments on a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateComment","description":"Add a comment.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/links/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"ListLinks","description":"Links on a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateLink","description":"Attach a link (the same URL twice is a 400).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The URL is already linked (carries the existing link id)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/states/":{"get":{"operationId":"ListStates","description":"The project's workflow states.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatePage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]},"/api/v1/workspaces/{slug}/projects/{project_id}/labels/":{"get":{"operationId":"ListLabels","description":"The project's labels.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabelPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateLabel","description":"Create a label (a duplicate name is a 409 carrying the existing id).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Label"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Duplicate name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLabelBody"}}}}},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]},"/api/v1/workspaces/{slug}/projects/{project_id}/cycles/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}],"get":{"operationId":"ListCycles","description":"Cycles, paginated except cycle_view=current (a bare array).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Cycle response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CycleList"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CycleError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"},{"name":"cycle_view","in":"query","schema":{"type":"string","enum":["all","current","upcoming","completed","draft","incomplete"]}},{"name":"order_by","in":"query","schema":{"type":"string","enum":["created_at","-created_at","name","-name","start_date","-start_date","end_date","-end_date"]}}]},"post":{"operationId":"CreateCycle","description":"Create a draft or a dated cycle in a UTC project.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cycle"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CycleError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Duplicate external source and id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCycleBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/cycles/{cycle_id}/cycle-issues/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"name":"cycle_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"cycle","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"ListCycleWorkItems","description":"Paginated live work items assigned to the cycle.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Cycle response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItemPage"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CycleError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"AddCycleWorkItems","description":"Add or move work items; unknown or foreign item ids are ignored.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"200":{"description":"Cycle response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CycleMemberships"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CycleError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCycleWorkItemsBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/work-item-types/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}],"get":{"operationId":"ListWorkItemTypes","description":"All work-item types for the project, as a bare array.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Work-item types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WorkItemType"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"}},"parameters":{"Slug":{"name":"slug","in":"path","required":true,"schema":{"type":"string","enum":["acme"]}},"ProjectId":{"name":"project_id","in":"path","required":true,"schema":{"type":"string","enum":["33333333-3333-4333-8333-333333333333"]}},"WorkItemId":{"name":"work_item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"work_item","missing":"00000000-0000-4000-8000-000000000000"}}},"PerPage":{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},"Cursor":{"name":"cursor","in":"query","required":false,"schema":{"type":"string","enum":["2:0:0","2:1:0","2:2:0","100:0:0"]}},"OrderBy":{"name":"order_by","in":"query","required":false,"schema":{"type":"string","enum":["-created_at","created_at","sequence_id","-sequence_id","name","-name"]}}},"responses":{"Unauthorized":{"description":"Missing or invalid X-API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"NotFound":{"description":"Unknown workspace, project or item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Throttled":{"description":"Rate limited (60 requests per minute per key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}},"schemas":{"WorkItem":{"type":"object","required":["id","sequence_id","name","description_html","state","labels","priority","created_at","updated_at","project","workspace"],"properties":{"type_id":{"type":["string","null"],"format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"type":{"type":["string","null"],"format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"work_item","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"sequence_id":{"type":"integer"},"name":{"type":"string"},"description_html":{"type":"string"},"description_stripped":{"type":["string","null"]},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]},"state":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"labels":{"type":"array","items":{"type":"string","x-mockingbird-volatile":{"kind":"id"}}},"assignees":{"type":"array","items":{"type":"string"}},"parent":{"type":["string","null"]},"start_date":{"type":["string","null"]},"target_date":{"type":["string","null"]},"completed_at":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"archived_at":{"type":["string","null"]},"is_draft":{"type":"boolean"},"sort_order":{"type":"number"},"project":{"type":"string"},"workspace":{"type":"string"},"created_by":{"type":["string","null"]},"updated_by":{"type":["string","null"]},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"State":{"type":"object","required":["id","name","group","color","sequence","default"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"state","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"group":{"type":"string","enum":["backlog","unstarted","started","completed","cancelled","triage"]},"color":{"type":"string"},"sequence":{"type":"number"},"default":{"type":"boolean"},"description":{"type":"string"},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Label":{"type":"object","required":["id","name","color"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"label","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"color":{"type":"string"},"description":{"type":"string"},"parent":{"type":["string","null"]},"sort_order":{"type":"number"},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Comment":{"type":"object","required":["id","comment_html","issue","created_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"comment_html":{"type":"string"},"comment_stripped":{"type":"string"},"access":{"type":"string"},"issue":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"actor":{"type":["string","null"]},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Link":{"type":"object","required":["id","url","title","issue","created_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"url":{"type":"string"},"title":{"type":["string","null"]},"metadata":{"type":"object"},"issue":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"WorkItemPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/WorkItem"}}}},"StatePage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/State"}}}},"LabelPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Label"}}}},"CommentPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}},"LinkPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Link"}}}},"CreateWorkItemBody":{"type":"object","required":["name"],"properties":{"type_id":{"type":["string","null"],"format":"uuid","x-mockingbird-resource-ref":{"type":"work_item_type","missing":"00000000-0000-4000-8000-000000000000"}},"name":{"type":"string","minLength":1,"maxLength":255},"description_html":{"type":"string","maxLength":2000},"state":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"state","missing":"00000000-0000-4000-8000-000000000000"}},"labels":{"type":"array","maxItems":3,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"label","missing":"00000000-0000-4000-8000-000000000000"}}},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]}}},"UpdateWorkItemBody":{"type":"object","properties":{"type_id":{"type":["string","null"],"format":"uuid","x-mockingbird-resource-ref":{"type":"work_item_type","missing":"00000000-0000-4000-8000-000000000000"}},"name":{"type":"string","minLength":1,"maxLength":255},"description_html":{"type":"string","maxLength":2000},"state":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"state","missing":"00000000-0000-4000-8000-000000000000"}},"labels":{"type":"array","maxItems":3,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"label","missing":"00000000-0000-4000-8000-000000000000"}}},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]}}},"CreateCommentBody":{"type":"object","required":["comment_html"],"properties":{"comment_html":{"type":"string","minLength":1,"maxLength":2000},"access":{"type":"string","enum":["INTERNAL","EXTERNAL"]}}},"CreateLinkBody":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","pattern":"^https://","maxLength":200},"title":{"type":"string","minLength":1,"maxLength":255}}},"CreateLabelBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"description":{"type":"string","maxLength":255}}},"ErrorBody":{"type":"object","properties":{"error":{"type":"string"},"detail":{"type":"string"},"id":{"type":"string"}}},"ValidationError":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},"Cycle":{"type":"object","required":["id","name","start_date","end_date","project","workspace","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"cycle","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"description":{"type":"string"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]},"owned_by":{"type":["string","null"]},"timezone":{"type":"string"},"external_source":{"type":["string","null"]},"external_id":{"type":["string","null"]},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"archived_at":{"type":["string","null"]},"deleted_at":{"type":["string","null"]},"total_issues":{"type":"integer"},"completed_issues":{"type":"integer"},"cancelled_issues":{"type":"integer"},"started_issues":{"type":"integer"},"unstarted_issues":{"type":"integer"},"backlog_issues":{"type":"integer"}}},"CyclePage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Cycle"}}}},"CycleList":{"oneOf":[{"$ref":"#/components/schemas/CyclePage"},{"type":"array","items":{"$ref":"#/components/schemas/Cycle"}}]},"CreateCycleBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description":{"type":"string"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]},"owned_by":{"type":["string","null"],"format":"uuid"},"timezone":{"type":"string"},"external_source":{"type":["string","null"]},"external_id":{"type":["string","null"]}}},"CycleMembership":{"type":"object","required":["id","cycle","issue","project","workspace","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"cycle_membership","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"cycle":{"type":"string","format":"uuid"},"issue":{"type":"string","format":"uuid"},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"deleted_at":{"type":["string","null"]}}},"CycleMemberships":{"type":"array","items":{"$ref":"#/components/schemas/CycleMembership"}},"AddCycleWorkItemsBody":{"type":"object","properties":{"issues":{"type":"array","items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"work_item","missing":"00000000-0000-4000-8000-000000000000"}}}}},"CycleError":{"anyOf":[{"$ref":"#/components/schemas/ValidationError"},{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"code":{"type":"string"},"id":{"type":"string"}}},{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"WorkItemType":{"type":"object","required":["id","name","project_ids","is_default","is_active","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"work_item_type","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"description":{"type":"string"},"project_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"logo_props":{"type":"object"},"is_epic":{"type":"boolean"},"is_default":{"type":"boolean"},"is_active":{"type":"boolean"},"level":{"type":"number"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"deleted_at":{"type":["string","null"]}}}}}}`);
3204
+ var operationIds = ["ListWorkItems", "CreateWorkItem", "GetWorkItem", "UpdateWorkItem", "ListComments", "CreateComment", "ListLinks", "CreateLink", "ListStates", "ListLabels", "CreateLabel", "ListCycles", "CreateCycle", "ListCycleWorkItems", "AddCycleWorkItems", "ListWorkItemTypes"];
3205
+ var supportedOperationIds = ["ListWorkItems", "CreateWorkItem", "GetWorkItem", "UpdateWorkItem", "ListComments", "CreateComment", "ListLinks", "CreateLink", "ListStates", "ListLabels", "CreateLabel", "ListCycles", "CreateCycle", "ListCycleWorkItems", "AddCycleWorkItems", "ListWorkItemTypes"];
3137
3206
 
3138
3207
  // src/state.ts
3139
3208
  var DEFAULT_SETTINGS = { apiKeys: [], rateLimitPerMinute: null, projects: [] };
@@ -3162,6 +3231,9 @@ var PlaneState = class {
3162
3231
  this.items = new Collection(sqlite, namespace, "work_items");
3163
3232
  this.comments = new Collection(sqlite, namespace, "comments");
3164
3233
  this.links = new Collection(sqlite, namespace, "links");
3234
+ this.cycles = new Collection(sqlite, namespace, "cycles");
3235
+ this.memberships = new Collection(sqlite, namespace, "cycle_memberships");
3236
+ this.types = new Collection(sqlite, namespace, "work_item_types");
3165
3237
  this.settings = new Collection(sqlite, namespace, "settings");
3166
3238
  this.rateLimits = new Collection(sqlite, namespace, "rate_limits");
3167
3239
  this.ids = new IdSequence(sqlite, namespace, "plane");
@@ -3174,6 +3246,9 @@ var PlaneState = class {
3174
3246
  items;
3175
3247
  comments;
3176
3248
  links;
3249
+ cycles;
3250
+ memberships;
3251
+ types;
3177
3252
  settings;
3178
3253
  rateLimits;
3179
3254
  ids;
@@ -3287,6 +3362,9 @@ var PLANE_STATE = [
3287
3362
  },
3288
3363
  { name: "comments", label: "Comments" },
3289
3364
  { name: "links", label: "Links" },
3365
+ { name: "cycles", label: "Cycles" },
3366
+ { name: "cycle_memberships", label: "Cycle memberships" },
3367
+ { name: "work_item_types", label: "Work-item types" },
3290
3368
  {
3291
3369
  name: "settings",
3292
3370
  label: "Settings",
@@ -3298,6 +3376,30 @@ var json5 = (status, body) => new Response(JSON.stringify(body), { status, heade
3298
3376
  var adminError4 = (status, message) => json5(status, { error: { type: "mockingbird_admin", message } });
3299
3377
  var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3300
3378
  var adminRoutes = (runtime) => ({
3379
+ "POST /work-item-types": ({ body, namespace }) => {
3380
+ if (!isRecord5(body) || typeof body.workspace !== "string" || typeof body.project !== "string" || !Array.isArray(body.types)) {
3381
+ return adminError4(
3382
+ 400,
3383
+ 'expected {"workspace": "<slug>", "project": "<uuid>", "types": [{"name": "Bug"}]}'
3384
+ );
3385
+ }
3386
+ const types = [];
3387
+ for (const type of body.types) {
3388
+ if (!isRecord5(type) || typeof type.name !== "string" || !type.name.trim() || type.name.trim().length > 255 || type.description !== void 0 && typeof type.description !== "string" || type.is_default !== void 0 && typeof type.is_default !== "boolean") {
3389
+ return adminError4(
3390
+ 400,
3391
+ "each type requires a non-empty name (up to 255 characters), optional description and boolean is_default"
3392
+ );
3393
+ }
3394
+ types.push({
3395
+ name: type.name.trim(),
3396
+ ...typeof type.description === "string" ? { description: type.description } : {},
3397
+ ...typeof type.is_default === "boolean" ? { is_default: type.is_default } : {}
3398
+ });
3399
+ }
3400
+ const seeded = runtime.instance(namespace).seedWorkItemTypes(body.workspace, body.project, types);
3401
+ return seeded ? json5(200, seeded) : adminError4(409, "project is not in settings.projects");
3402
+ },
3301
3403
  "GET /work-items": ({ namespace }) => json5(200, { work_items: runtime.instance(namespace).workItems() }),
3302
3404
  "POST /work-items/:id/state": ({ params, body, namespace }) => {
3303
3405
  if (!isRecord5(body) || typeof body.state !== "string") {
@@ -3427,7 +3529,12 @@ var PlaneAPI = class {
3427
3529
  const project = this.project(context);
3428
3530
  return this.paginate(context, this.labelsOf(project.id));
3429
3531
  },
3430
- CreateLabel: (context) => this.createLabel(context)
3532
+ CreateLabel: (context) => this.createLabel(context),
3533
+ ListCycles: (context) => this.listCycles(context),
3534
+ CreateCycle: (context) => this.createCycle(context),
3535
+ ListCycleWorkItems: (context) => this.listCycleWorkItems(context),
3536
+ AddCycleWorkItems: (context) => this.addCycleWorkItems(context),
3537
+ ListWorkItemTypes: (context) => jsonRes(200, this.typesOf(this.project(context).id))
3431
3538
  });
3432
3539
  this.service = createService({
3433
3540
  document,
@@ -3527,13 +3634,44 @@ var PlaneAPI = class {
3527
3634
  labelsOf(projectId) {
3528
3635
  return this.state.labels.list({ order: "oldest", where: (l) => l.project === projectId }).map((r) => r.value);
3529
3636
  }
3637
+ typesOf(projectId) {
3638
+ return this.state.types.list({
3639
+ order: "oldest",
3640
+ where: (type) => type.project_ids.includes(projectId) && type.deleted_at === null
3641
+ }).map((row) => row.value);
3642
+ }
3643
+ /** Idempotent fixture provisioning; type IDs remain stable when metadata is reseeded. */
3644
+ seedWorkItemTypes(workspace, projectId, types) {
3645
+ const project = this.ensureProject(workspace, projectId);
3646
+ if (!project) return void 0;
3647
+ const now = this.iso();
3648
+ for (const type of types) {
3649
+ const id = uuidFrom(`${projectId}:type:${type.name}`);
3650
+ const existing = this.state.types.get(id);
3651
+ this.state.types.insert(id, {
3652
+ id,
3653
+ name: type.name,
3654
+ description: type.description ?? existing?.description ?? "",
3655
+ project_ids: [project.id],
3656
+ logo_props: {},
3657
+ is_epic: false,
3658
+ is_default: type.is_default ?? existing?.is_default ?? false,
3659
+ is_active: true,
3660
+ level: 0,
3661
+ created_at: existing?.created_at ?? now,
3662
+ updated_at: now,
3663
+ deleted_at: null
3664
+ });
3665
+ }
3666
+ return this.typesOf(project.id);
3667
+ }
3530
3668
  /** Plane's cursor paginator: `cursor=<per_page>:<page>:<is_prev>`, offset = page × per_page. */
3531
- paginate(context, rows) {
3669
+ paginate(context, rows, defaultSize = PAGE_SIZE) {
3532
3670
  const perPageResult = context.query.per_page === void 0 ? void 0 : coerce.integer(context.query.per_page);
3533
3671
  if (perPageResult && !perPageResult.ok) {
3534
3672
  return jsonRes(400, { error: "Invalid per_page parameter." });
3535
3673
  }
3536
- const perPage = Math.min(PAGE_SIZE, Math.max(1, perPageResult?.value ?? PAGE_SIZE));
3674
+ const perPage = Math.min(PAGE_SIZE, Math.max(1, perPageResult?.value ?? defaultSize));
3537
3675
  let page = 0;
3538
3676
  let cursorSize = perPage;
3539
3677
  if (context.query.cursor !== void 0) {
@@ -3585,14 +3723,175 @@ var PlaneAPI = class {
3585
3723
  });
3586
3724
  return this.paginate(context, rows);
3587
3725
  }
3726
+ cycle(context) {
3727
+ const project = this.project(context);
3728
+ const cycle = this.state.cycles.get(context.params.cycle_id ?? "");
3729
+ if (!cycle || cycle.project !== project.id) throw new HttpError(404, NOT_FOUND);
3730
+ return cycle;
3731
+ }
3732
+ cycleView(cycle) {
3733
+ const members = this.state.memberships.list({ where: (m) => m.cycle === cycle.id }).map((row) => this.state.items.get(row.value.issue)).filter((item) => !!item && !item.archived_at && !item.is_draft);
3734
+ const count = (group) => members.filter((item) => this.state.states.get(item.state)?.group === group).length;
3735
+ return {
3736
+ ...cycle,
3737
+ total_issues: members.length,
3738
+ completed_issues: count("completed"),
3739
+ cancelled_issues: count("cancelled"),
3740
+ started_issues: count("started"),
3741
+ unstarted_issues: count("unstarted"),
3742
+ backlog_issues: count("backlog")
3743
+ };
3744
+ }
3745
+ listCycles(context) {
3746
+ const project = this.project(context);
3747
+ const view = context.query.cycle_view ?? "all";
3748
+ const now = this.now();
3749
+ const rows = this.state.cycles.list({
3750
+ order: "newest",
3751
+ where: (cycle) => {
3752
+ if (cycle.project !== project.id || cycle.archived_at) return false;
3753
+ const start = cycle.start_date === null ? null : Date.parse(cycle.start_date);
3754
+ const end = cycle.end_date === null ? null : Date.parse(cycle.end_date);
3755
+ if (view === "current")
3756
+ return start !== null && end !== null && start <= now && end >= now;
3757
+ if (view === "upcoming") return start !== null && start > now;
3758
+ if (view === "completed") return end !== null && end < now;
3759
+ if (view === "draft") return start === null && end === null;
3760
+ if (view === "incomplete") return end === null || end >= now;
3761
+ return true;
3762
+ }
3763
+ }).map((row) => row.value);
3764
+ const orderBy = typeof context.query.order_by === "string" ? context.query.order_by : "-created_at";
3765
+ const descending = orderBy.startsWith("-");
3766
+ const field = descending ? orderBy.slice(1) : orderBy;
3767
+ rows.sort((a, b) => {
3768
+ const x = a[field] ?? "";
3769
+ const y = b[field] ?? "";
3770
+ const order = x < y ? -1 : x > y ? 1 : 0;
3771
+ return descending ? -order : order;
3772
+ });
3773
+ const results = rows.map((cycle) => this.cycleView(cycle));
3774
+ return view === "current" ? jsonRes(200, results) : this.paginate(context, results, 20);
3775
+ }
3776
+ createCycle(context) {
3777
+ const project = this.project(context);
3778
+ const body = this.body(context);
3779
+ const start = body.start_date ?? null;
3780
+ const end = body.end_date ?? null;
3781
+ if (start === null !== (end === null))
3782
+ throw new HttpError(400, {
3783
+ error: "Both start date and end date are either required or are to be null"
3784
+ });
3785
+ const date = (value, field) => {
3786
+ if (value === null) return null;
3787
+ const text = String(value);
3788
+ const day = text.slice(0, 10);
3789
+ const instant = Date.parse(text);
3790
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(day) || !Number.isFinite(instant) || new Date(Date.parse(day)).toISOString().slice(0, 10) !== day) {
3791
+ throw new HttpError(400, { [field]: ["Datetime has wrong format."] });
3792
+ }
3793
+ return day;
3794
+ };
3795
+ const startDay = date(start, "start_date");
3796
+ const endDay = date(end, "end_date");
3797
+ if (startDay && endDay && startDay > endDay)
3798
+ throw new HttpError(400, {
3799
+ non_field_errors: ["Start date cannot exceed end date"]
3800
+ });
3801
+ const now = this.iso();
3802
+ const existing = body.external_source && body.external_id ? this.state.cycles.list({
3803
+ where: (cycle2) => cycle2.project === project.id && cycle2.external_id === body.external_id && cycle2.external_source === body.external_source
3804
+ })[0]?.value : void 0;
3805
+ if (existing)
3806
+ return jsonRes(409, {
3807
+ error: "Cycle with the same external id and external source already exists",
3808
+ id: existing.id
3809
+ });
3810
+ const cycle = {
3811
+ id: this.state.uuid("cycle"),
3812
+ name: String(body.name).trim(),
3813
+ description: typeof body.description === "string" ? body.description : "",
3814
+ start_date: startDay ? startDay === now.slice(0, 10) ? now : `${startDay}T00:00:01.000Z` : null,
3815
+ end_date: endDay ? `${endDay}T23:59:00.000Z` : null,
3816
+ owned_by: typeof body.owned_by === "string" ? body.owned_by : uuidFrom("plane-bot"),
3817
+ timezone: typeof body.timezone === "string" ? body.timezone : "UTC",
3818
+ external_id: typeof body.external_id === "string" ? body.external_id : null,
3819
+ external_source: typeof body.external_source === "string" ? body.external_source : null,
3820
+ project: project.id,
3821
+ workspace: project.workspace,
3822
+ created_at: now,
3823
+ updated_at: now,
3824
+ archived_at: null,
3825
+ deleted_at: null
3826
+ };
3827
+ this.state.cycles.insert(cycle.id, cycle);
3828
+ return annotateResponse(jsonRes(201, cycle), { ids: { cycleId: cycle.id } });
3829
+ }
3830
+ listCycleWorkItems(context) {
3831
+ const project = this.project(context);
3832
+ const rows = this.state.memberships.list({
3833
+ order: "oldest",
3834
+ where: (m) => m.cycle === context.params.cycle_id && m.project === project.id
3835
+ }).flatMap((row) => {
3836
+ const item = this.state.items.get(row.value.issue);
3837
+ return item && item.project === project.id ? [{ ...item, bridge_id: row.value.id }] : [];
3838
+ }).sort((a, b) => a.created_at.localeCompare(b.created_at) || a.sequence_id - b.sequence_id);
3839
+ return this.paginate(context, rows, 20);
3840
+ }
3841
+ addCycleWorkItems(context) {
3842
+ const body = this.body(context);
3843
+ const ids = body.issues;
3844
+ if (!ids?.length)
3845
+ throw new HttpError(400, { error: "Work items are required", code: "MISSING_WORK_ITEMS" });
3846
+ const cycle = this.cycle(context);
3847
+ if (cycle.end_date && Date.parse(cycle.end_date) < this.now())
3848
+ throw new HttpError(400, {
3849
+ code: "CYCLE_COMPLETED",
3850
+ message: "The Cycle has already been completed so no new issues can be added"
3851
+ });
3852
+ for (const id of new Set(ids)) {
3853
+ const item = this.state.items.get(id);
3854
+ if (!item || item.project !== cycle.project || item.workspace !== cycle.workspace) continue;
3855
+ const membership = this.state.memberships.list({ where: (m) => m.issue === id })[0]?.value;
3856
+ if (membership) {
3857
+ if (membership.cycle !== cycle.id)
3858
+ this.state.memberships.update(membership.id, { ...membership, cycle: cycle.id });
3859
+ } else {
3860
+ const membershipId = this.state.uuid("cycle_membership");
3861
+ const now = this.iso();
3862
+ this.state.memberships.insert(membershipId, {
3863
+ id: membershipId,
3864
+ cycle: cycle.id,
3865
+ issue: id,
3866
+ project: cycle.project,
3867
+ workspace: cycle.workspace,
3868
+ created_at: now,
3869
+ updated_at: now,
3870
+ deleted_at: null
3871
+ });
3872
+ }
3873
+ }
3874
+ const rows = this.state.memberships.list({ order: "newest", where: (m) => m.cycle === cycle.id }).map((row) => row.value);
3875
+ return jsonRes(200, rows);
3876
+ }
3588
3877
  body(context) {
3589
3878
  const issues = bodyIssues(context);
3590
3879
  if (issues.length > 0) throw new HttpError(400, drfErrors(issues));
3591
3880
  return context.body.kind === "json" ? context.body.value : {};
3592
3881
  }
3593
- /** Validate `state` / `labels` references against the project, DRF-style. */
3882
+ /** Validate workflow references before any part of a write is persisted, DRF-style. */
3594
3883
  references(project, body) {
3595
3884
  const out = {};
3885
+ if (body.type_id === null) out.typeId = null;
3886
+ else if (typeof body.type_id === "string") {
3887
+ const type = this.state.types.get(body.type_id);
3888
+ if (!type?.project_ids.includes(project.id) || type.deleted_at !== null) {
3889
+ throw new HttpError(400, {
3890
+ type_id: [`Invalid pk "${body.type_id}" - object does not exist.`]
3891
+ });
3892
+ }
3893
+ out.typeId = type.id;
3894
+ }
3596
3895
  if (typeof body.state === "string") {
3597
3896
  const state = this.state.states.get(body.state);
3598
3897
  if (!state || state.project !== project.id) {
@@ -3617,6 +3916,7 @@ var PlaneAPI = class {
3617
3916
  const state = refs.state ?? this.statesOf(project.id).find((s) => s.default) ?? this.statesOf(project.id)[0];
3618
3917
  const now = this.iso();
3619
3918
  const html = typeof body.description_html === "string" ? body.description_html : "<p></p>";
3919
+ const typeId = refs.typeId ?? this.typesOf(project.id).find((type) => type.is_default)?.id ?? null;
3620
3920
  const item = {
3621
3921
  id: this.state.uuid("work_item"),
3622
3922
  sequence_id: project.nextSequence,
@@ -3625,6 +3925,8 @@ var PlaneAPI = class {
3625
3925
  description_stripped: stripTags(html) || null,
3626
3926
  priority: body.priority ?? "none",
3627
3927
  state: state?.id ?? "",
3928
+ type_id: typeId,
3929
+ type: typeId,
3628
3930
  labels: refs.labels ?? [],
3629
3931
  assignees: [],
3630
3932
  parent: null,
@@ -3658,7 +3960,8 @@ var PlaneAPI = class {
3658
3960
  } : {},
3659
3961
  ...typeof body.priority === "string" ? { priority: body.priority } : {},
3660
3962
  ...refs.labels ? { labels: refs.labels } : {},
3661
- ...refs.state ? { state: refs.state.id } : {}
3963
+ ...refs.state ? { state: refs.state.id } : {},
3964
+ ...refs.typeId !== void 0 ? { type_id: refs.typeId, type: refs.typeId } : {}
3662
3965
  });
3663
3966
  return annotateResponse(jsonRes(200, next), { ids: { workItemId: next.id } });
3664
3967
  }
@@ -3778,4 +4081,4 @@ export {
3778
4081
  apiKeyCredential,
3779
4082
  PlaneAPI
3780
4083
  };
3781
- //# sourceMappingURL=chunk-NSDJM2TL.js.map
4084
+ //# sourceMappingURL=chunk-ZF6D32HZ.js.map