@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.
- package/CHANGELOG.md +12 -4
- package/README.md +18 -1
- package/SUPPORT.md +8 -3
- package/dist/{chunk-4RCG3YYZ.js → chunk-EQQXMBQ4.js} +2 -2
- package/dist/{chunk-NSDJM2TL.js → chunk-ZF6D32HZ.js} +317 -14
- package/dist/chunk-ZF6D32HZ.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +66 -6
- package/dist/index.js +1 -1
- package/dist/server.d.ts +61 -1
- package/dist/server.js +2 -2
- package/openapi.yaml +445 -1
- package/package.json +1 -1
- package/dist/chunk-NSDJM2TL.js.map +0 -7
- /package/dist/{chunk-4RCG3YYZ.js.map → chunk-EQQXMBQ4.js.map} +0 -0
|
@@ -1011,7 +1011,40 @@ var decodeBody = (contentType, bytes) => {
|
|
|
1011
1011
|
return { kind: "bytes", value: bytes };
|
|
1012
1012
|
};
|
|
1013
1013
|
var readBody = async (message) => {
|
|
1014
|
-
|
|
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
|
|
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:
|
|
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(),
|
|
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.
|
|
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 ??
|
|
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
|
|
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-
|
|
4084
|
+
//# sourceMappingURL=chunk-ZF6D32HZ.js.map
|