@cycleplatform/api-client-typescript 0.3.4 → 0.3.6
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/README.md +38 -0
- package/dist/index.js +2 -1
- package/dist/index.umd.cjs +1 -1
- package/package.json +2 -1
- package/src/generated/types.ts +5 -4
- package/src/index.ts +1 -1
- package/src/jobs.ts +2 -2
package/README.md
CHANGED
|
@@ -65,6 +65,44 @@ const resp = await client.GET("/v1/containers/{containerId}", {
|
|
|
65
65
|
console.log(resp.data, resp.error);
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
### Tracking a Job
|
|
69
|
+
|
|
70
|
+
Cycle utilizes an asynchronous job system for handling background tasks. Often it is useful to keep tabs on the
|
|
71
|
+
progress of these jobs, or to wait for a job to complete (or fail) before continuing. This API client includes
|
|
72
|
+
a job tracking utility function to simplify this process.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { client, trackJob } from "@cycleplatform/api-client-typescript";
|
|
76
|
+
|
|
77
|
+
const baseUrl = "https://api.cycle.io";
|
|
78
|
+
|
|
79
|
+
const client = getClient({
|
|
80
|
+
baseUrl,
|
|
81
|
+
apiKey: "<your-api-key>",
|
|
82
|
+
hubId: "<your-hub-id>",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const tracker = trackJob(client, "<job-id>");
|
|
86
|
+
|
|
87
|
+
// It's possible to listen for progress updates on a job as it executes
|
|
88
|
+
tracker.addEventListener("progress", (event) => {
|
|
89
|
+
console.log((event as CustomEvent).detail);
|
|
90
|
+
// {
|
|
91
|
+
// total: number;
|
|
92
|
+
// completed: number;
|
|
93
|
+
// failed: number;
|
|
94
|
+
// percent: number;
|
|
95
|
+
// state: components["schemas"]["JobState"]["current"];
|
|
96
|
+
// }
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Wait for job to complete
|
|
100
|
+
const job = await tracker.promise;
|
|
101
|
+
console.log(job.state.current); // "completed"
|
|
102
|
+
|
|
103
|
+
// throws on job failure
|
|
104
|
+
```
|
|
105
|
+
|
|
68
106
|
## Development
|
|
69
107
|
|
|
70
108
|
### Cloning submodules
|
package/dist/index.js
CHANGED
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(p,R){typeof exports=="object"&&typeof module<"u"?R(exports):typeof define=="function"&&define.amd?define(["exports"],R):(p=typeof globalThis<"u"?globalThis:p||self,R(p["Cycle API Client"]={}))})(this,function(p){"use strict";const R=/\{[^{}]+\}/g,N=()=>{var r,t;return typeof process=="object"&&Number.parseInt((t=(r=process==null?void 0:process.versions)==null?void 0:r.node)==null?void 0:t.substring(0,2))>=18&&process.versions.undici};function B(){return Math.random().toString(36).slice(2,11)}function F(r){let{baseUrl:t="",Request:e=globalThis.Request,fetch:o=globalThis.fetch,querySerializer:n,bodySerializer:i,headers:s,requestInitExt:l=void 0,...y}={...r};l=N()?l:void 0,t=H(t);const h=[];async function m(f,a){const{baseUrl:b,fetch:J=o,Request:re=e,headers:Y,params:j={},parseAs:q="json",querySerializer:T,bodySerializer:L=i??G,body:M,...I}=a||{};b&&(t=H(b));let x=typeof n=="function"?n:D(n);T&&(x=typeof T=="function"?T:D({...typeof n=="object"?n:{},...T}));const k=M===void 0?void 0:L(M),ee=k===void 0||k instanceof FormData?{}:{"Content-Type":"application/json"},te={redirect:"follow",...y,...I,body:k,headers:_(ee,s,Y,j.header)};let $,A,w=new e(Q(f,{baseUrl:t,params:j,querySerializer:x}),te);for(const u in I)u in w||(w[u]=I[u]);if(h.length){$=B(),A=Object.freeze({baseUrl:t,fetch:J,parseAs:q,querySerializer:x,bodySerializer:L});for(const u of h)if(u&&typeof u=="object"&&typeof u.onRequest=="function"){const d=await u.onRequest({request:w,schemaPath:f,params:j,options:A,id:$});if(d){if(!(d instanceof e))throw new Error("onRequest: must return new Request() when modifying the request");w=d}}}let c;try{c=await J(w,l)}catch(u){let d=u;if(h.length)for(let g=h.length-1;g>=0;g--){const C=h[g];if(C&&typeof C=="object"&&typeof C.onError=="function"){const E=await C.onError({request:w,error:d,schemaPath:f,params:j,options:A,id:$});if(E){if(E instanceof Response){d=void 0,c=E;break}if(E instanceof Error){d=E;continue}throw new Error("onError: must return new Response() or instance of Error")}}}if(d)throw d}if(h.length)for(let u=h.length-1;u>=0;u--){const d=h[u];if(d&&typeof d=="object"&&typeof d.onResponse=="function"){const g=await d.onResponse({request:w,response:c,schemaPath:f,params:j,options:A,id:$});if(g){if(!(g instanceof Response))throw new Error("onResponse: must return new Response() when modifying the response");c=g}}}if(c.status===204||c.headers.get("Content-Length")==="0")return c.ok?{data:void 0,response:c}:{error:void 0,response:c};if(c.ok)return q==="stream"?{data:c.body,response:c}:{data:await c[q](),response:c};let v=await c.text();try{v=JSON.parse(v)}catch{}return{error:v,response:c}}return{request(f,a,b){return m(a,{...b,method:f.toUpperCase()})},GET(f,a){return m(f,{...a,method:"GET"})},PUT(f,a){return m(f,{...a,method:"PUT"})},POST(f,a){return m(f,{...a,method:"POST"})},DELETE(f,a){return m(f,{...a,method:"DELETE"})},OPTIONS(f,a){return m(f,{...a,method:"OPTIONS"})},HEAD(f,a){return m(f,{...a,method:"HEAD"})},PATCH(f,a){return m(f,{...a,method:"PATCH"})},TRACE(f,a){return m(f,{...a,method:"TRACE"})},use(...f){for(const a of f)if(a){if(typeof a!="object"||!("onRequest"in a||"onResponse"in a||"onError"in a))throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");h.push(a)}},eject(...f){for(const a of f){const b=h.indexOf(a);b!==-1&&h.splice(b,1)}}}}function S(r,t,e){if(t==null)return"";if(typeof t=="object")throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");return`${r}=${(e==null?void 0:e.allowReserved)===!0?t:encodeURIComponent(t)}`}function O(r,t,e){if(!t||typeof t!="object")return"";const o=[],n={simple:",",label:".",matrix:";"}[e.style]||"&";if(e.style!=="deepObject"&&e.explode===!1){for(const l in t)o.push(l,e.allowReserved===!0?t[l]:encodeURIComponent(t[l]));const s=o.join(",");switch(e.style){case"form":return`${r}=${s}`;case"label":return`.${s}`;case"matrix":return`;${r}=${s}`;default:return s}}for(const s in t){const l=e.style==="deepObject"?`${r}[${s}]`:s;o.push(S(l,t[s],e))}const i=o.join(n);return e.style==="label"||e.style==="matrix"?`${n}${i}`:i}function U(r,t,e){if(!Array.isArray(t))return"";if(e.explode===!1){const i={form:",",spaceDelimited:"%20",pipeDelimited:"|"}[e.style]||",",s=(e.allowReserved===!0?t:t.map(l=>encodeURIComponent(l))).join(i);switch(e.style){case"simple":return s;case"label":return`.${s}`;case"matrix":return`;${r}=${s}`;default:return`${r}=${s}`}}const o={simple:",",label:".",matrix:";"}[e.style]||"&",n=[];for(const i of t)e.style==="simple"||e.style==="label"?n.push(e.allowReserved===!0?i:encodeURIComponent(i)):n.push(S(r,i,e));return e.style==="label"||e.style==="matrix"?`${o}${n.join(o)}`:n.join(o)}function D(r){return function(e){const o=[];if(e&&typeof e=="object")for(const n in e){const i=e[n];if(i!=null){if(Array.isArray(i)){if(i.length===0)continue;o.push(U(n,i,{style:"form",explode:!0,...r==null?void 0:r.array,allowReserved:(r==null?void 0:r.allowReserved)||!1}));continue}if(typeof i=="object"){o.push(O(n,i,{style:"deepObject",explode:!0,...r==null?void 0:r.object,allowReserved:(r==null?void 0:r.allowReserved)||!1}));continue}o.push(S(n,i,r))}}return o.join("&")}}function W(r,t){let e=r;for(const o of r.match(R)??[]){let n=o.substring(1,o.length-1),i=!1,s="simple";if(n.endsWith("*")&&(i=!0,n=n.substring(0,n.length-1)),n.startsWith(".")?(s="label",n=n.substring(1)):n.startsWith(";")&&(s="matrix",n=n.substring(1)),!t||t[n]===void 0||t[n]===null)continue;const l=t[n];if(Array.isArray(l)){e=e.replace(o,U(n,l,{style:s,explode:i}));continue}if(typeof l=="object"){e=e.replace(o,O(n,l,{style:s,explode:i}));continue}if(s==="matrix"){e=e.replace(o,`;${S(n,l)}`);continue}e=e.replace(o,s==="label"?`.${encodeURIComponent(l)}`:encodeURIComponent(l))}return e}function G(r){return r instanceof FormData?r:JSON.stringify(r)}function Q(r,t){var n;let e=`${t.baseUrl}${r}`;(n=t.params)!=null&&n.path&&(e=W(e,t.params.path));let o=t.querySerializer(t.params.query??{});return o.startsWith("?")&&(o=o.substring(1)),o&&(e+=`?${o}`),e}function _(...r){const t=new Headers;for(const e of r){if(!e||typeof e!="object")continue;const o=e instanceof Headers?e.entries():Object.entries(e);for(const[n,i]of o)if(i===null)t.delete(n);else if(Array.isArray(i))for(const s of i)t.append(n,s);else i!==void 0&&t.set(n,i)}return t}function H(r){return r.endsWith("/")?r.substring(0,r.length-1):r}class X extends EventTarget{constructor(t,e,o){super(),this.promise=this.track(t,e,o)}async track(t,e,o){const n=typeof e=="object"?e.id:e,i={pollingInterval:2e3,...o};let s=0;for(;;){const l=await t.GET("/v1/jobs/{jobId}",{params:{path:{jobId:n}}});if(l.error){if(s<5&&l.error.error.code==="404.job"){s++,await this.delay(i.pollingInterval);continue}throw l.error}const y=l.data.data,h=P(y);if(this.dispatchEvent(new CustomEvent("progress",{detail:{...h,state:y.state.current}})),Z(y)){if(y.state.current==="error")throw y;return this.dispatchEvent(new CustomEvent("done",{detail:y})),y}await this.delay(i.pollingInterval)}}delay(t=2e3){return new Promise(e=>setTimeout(e,t))}}function Z(r){return["completed","error","expired"].includes(r.state.current)}const z="0001-01-01T00:00:00Z";function P(r){if(!r.tasks||r.tasks.length===0)return{total:0,completed:0,failed:0,percent:100};const t=r.tasks.reduce((e,o)=>{var i,s,l;const n=((i=o.steps)==null?void 0:i.length)||1;if(e.total+=n,o.state.current==="pending")return e;if(!((s=o.steps)!=null&&s.length)){switch(o.state.current){case"completed":e.completed+=1;break;case"error":e.failed+=1}return e}return(l=o.steps)==null||l.forEach(y=>{if(y.completed!==z){e.completed+=1;return}["error","completed"].includes(o.state.current||"")&&y.started!==z&&(e.failed+=1)}),e},{total:0,completed:0,failed:0});return{...t,percent:t.completed/t.total*100}}function K(r,t,e){return new X(r,t,e)}function V({apiKey:r,baseUrl:t="https://api.cycle.io",hubId:e,fetch:o}){const n=F({baseUrl:t,fetch:o||fetch}),i={async onRequest({request:s}){return s.headers.set("Authorization",`Bearer ${r}`),s.headers.set("X-Hub-Id",e),s}};return n.use(i),n}p.getClient=V,p.getJobProgress=P,p.trackJob=K,p.zeroTimeString=z,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cycleplatform/api-client-typescript",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "A Cycle API client for the web/nodejs with type safety.",
|
|
5
5
|
"main": "./dist/index.umd.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
|
+
"types": "./src/index.ts",
|
|
20
21
|
"scripts": {
|
|
21
22
|
"test": "vitest",
|
|
22
23
|
"test:ts": "tsc --noEmit",
|
package/src/generated/types.ts
CHANGED
|
@@ -4719,6 +4719,7 @@ export interface components {
|
|
|
4719
4719
|
description: string;
|
|
4720
4720
|
updates: components["schemas"]["AnnouncementUpdate"][];
|
|
4721
4721
|
affected_integrations?: string[];
|
|
4722
|
+
affected_services?: string[];
|
|
4722
4723
|
creator: components["schemas"]["CreatorScope"];
|
|
4723
4724
|
state: {
|
|
4724
4725
|
/**
|
|
@@ -21036,7 +21037,7 @@ export interface operations {
|
|
|
21036
21037
|
};
|
|
21037
21038
|
};
|
|
21038
21039
|
responses: {
|
|
21039
|
-
/** @description Returns a
|
|
21040
|
+
/** @description Returns a job descriptor. */
|
|
21040
21041
|
202: {
|
|
21041
21042
|
headers: {
|
|
21042
21043
|
[name: string]: unknown;
|
|
@@ -21115,14 +21116,14 @@ export interface operations {
|
|
|
21115
21116
|
};
|
|
21116
21117
|
};
|
|
21117
21118
|
responses: {
|
|
21118
|
-
/** @description Returns a
|
|
21119
|
-
|
|
21119
|
+
/** @description Returns a job descriptor. */
|
|
21120
|
+
202: {
|
|
21120
21121
|
headers: {
|
|
21121
21122
|
[name: string]: unknown;
|
|
21122
21123
|
};
|
|
21123
21124
|
content: {
|
|
21124
21125
|
"application/json": {
|
|
21125
|
-
data: components["schemas"]["
|
|
21126
|
+
data: components["schemas"]["JobDescriptor"];
|
|
21126
21127
|
};
|
|
21127
21128
|
};
|
|
21128
21129
|
};
|
package/src/index.ts
CHANGED
package/src/jobs.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getClient } from ".";
|
|
2
2
|
import { type components } from "./generated/types";
|
|
3
3
|
|
|
4
|
-
type TrackJobSettings = {
|
|
4
|
+
export type TrackJobSettings = {
|
|
5
5
|
pollingInterval?: number;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
type JobProgressEvent = ReturnType<typeof getJobProgress> & {
|
|
8
|
+
export type JobProgressEvent = ReturnType<typeof getJobProgress> & {
|
|
9
9
|
state: components["schemas"]["JobState"]["current"];
|
|
10
10
|
};
|
|
11
11
|
|