@cycleplatform/api-client-typescript 0.3.4 → 0.3.5

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 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
@@ -451,5 +451,6 @@ function te({
451
451
  export {
452
452
  te as getClient,
453
453
  V as getJobProgress,
454
- ee as trackJob
454
+ ee as trackJob,
455
+ D as zeroTimeString
455
456
  };
@@ -1 +1 @@
1
- (function(m,R){typeof exports=="object"&&typeof module<"u"?R(exports):typeof define=="function"&&define.amd?define(["exports"],R):(m=typeof globalThis<"u"?globalThis:m||self,R(m["Cycle API Client"]={}))})(this,function(m){"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:s,headers:i,requestInitExt:l=void 0,...y}={...r};l=N()?l:void 0,t=D(t);const h=[];async function p(f,a){const{baseUrl:b,fetch:J=o,Request:re=e,headers:Y,params:j={},parseAs:z="json",querySerializer:T,bodySerializer:L=s??G,body:M,...q}=a||{};b&&(t=D(b));let x=typeof n=="function"?n:U(n);T&&(x=typeof T=="function"?T:U({...typeof n=="object"?n:{},...T}));const I=M===void 0?void 0:L(M),ee=I===void 0||I instanceof FormData?{}:{"Content-Type":"application/json"},te={redirect:"follow",...y,...q,body:I,headers:_(ee,i,Y,j.header)};let $,A,w=new e(Q(f,{baseUrl:t,params:j,querySerializer:x}),te);for(const u in q)u in w||(w[u]=q[u]);if(h.length){$=B(),A=Object.freeze({baseUrl:t,fetch:J,parseAs:z,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 z==="stream"?{data:c.body,response:c}:{data:await c[z](),response:c};let k=await c.text();try{k=JSON.parse(k)}catch{}return{error:k,response:c}}return{request(f,a,b){return p(a,{...b,method:f.toUpperCase()})},GET(f,a){return p(f,{...a,method:"GET"})},PUT(f,a){return p(f,{...a,method:"PUT"})},POST(f,a){return p(f,{...a,method:"POST"})},DELETE(f,a){return p(f,{...a,method:"DELETE"})},OPTIONS(f,a){return p(f,{...a,method:"OPTIONS"})},HEAD(f,a){return p(f,{...a,method:"HEAD"})},PATCH(f,a){return p(f,{...a,method:"PATCH"})},TRACE(f,a){return p(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 v(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 i=o.join(",");switch(e.style){case"form":return`${r}=${i}`;case"label":return`.${i}`;case"matrix":return`;${r}=${i}`;default:return i}}for(const i in t){const l=e.style==="deepObject"?`${r}[${i}]`:i;o.push(S(l,t[i],e))}const s=o.join(n);return e.style==="label"||e.style==="matrix"?`${n}${s}`:s}function O(r,t,e){if(!Array.isArray(t))return"";if(e.explode===!1){const s={form:",",spaceDelimited:"%20",pipeDelimited:"|"}[e.style]||",",i=(e.allowReserved===!0?t:t.map(l=>encodeURIComponent(l))).join(s);switch(e.style){case"simple":return i;case"label":return`.${i}`;case"matrix":return`;${r}=${i}`;default:return`${r}=${i}`}}const o={simple:",",label:".",matrix:";"}[e.style]||"&",n=[];for(const s of t)e.style==="simple"||e.style==="label"?n.push(e.allowReserved===!0?s:encodeURIComponent(s)):n.push(S(r,s,e));return e.style==="label"||e.style==="matrix"?`${o}${n.join(o)}`:n.join(o)}function U(r){return function(e){const o=[];if(e&&typeof e=="object")for(const n in e){const s=e[n];if(s!=null){if(Array.isArray(s)){if(s.length===0)continue;o.push(O(n,s,{style:"form",explode:!0,...r==null?void 0:r.array,allowReserved:(r==null?void 0:r.allowReserved)||!1}));continue}if(typeof s=="object"){o.push(v(n,s,{style:"deepObject",explode:!0,...r==null?void 0:r.object,allowReserved:(r==null?void 0:r.allowReserved)||!1}));continue}o.push(S(n,s,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),s=!1,i="simple";if(n.endsWith("*")&&(s=!0,n=n.substring(0,n.length-1)),n.startsWith(".")?(i="label",n=n.substring(1)):n.startsWith(";")&&(i="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,O(n,l,{style:i,explode:s}));continue}if(typeof l=="object"){e=e.replace(o,v(n,l,{style:i,explode:s}));continue}if(i==="matrix"){e=e.replace(o,`;${S(n,l)}`);continue}e=e.replace(o,i==="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,s]of o)if(s===null)t.delete(n);else if(Array.isArray(s))for(const i of s)t.append(n,i);else s!==void 0&&t.set(n,s)}return t}function D(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,s={pollingInterval:2e3,...o};let i=0;for(;;){const l=await t.GET("/v1/jobs/{jobId}",{params:{path:{jobId:n}}});if(l.error){if(i<5&&l.error.error.code==="404.job"){i++,await this.delay(s.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(s.pollingInterval)}}delay(t=2e3){return new Promise(e=>setTimeout(e,t))}}function Z(r){return["completed","error","expired"].includes(r.state.current)}const H="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 s,i,l;const n=((s=o.steps)==null?void 0:s.length)||1;if(e.total+=n,o.state.current==="pending")return e;if(!((i=o.steps)!=null&&i.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!==H){e.completed+=1;return}["error","completed"].includes(o.state.current||"")&&y.started!==H&&(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}),s={async onRequest({request:i}){return i.headers.set("Authorization",`Bearer ${r}`),i.headers.set("X-Hub-Id",e),i}};return n.use(s),n}m.getClient=V,m.getJobProgress=P,m.trackJob=K,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})});
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.4",
3
+ "version": "0.3.5",
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",
@@ -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
  /**
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@ import type { paths, components, operations } from "./generated/types";
3
3
 
4
4
  export { paths, components, operations };
5
5
 
6
- export { trackJob, getJobProgress } from "./jobs";
6
+ export * from "./jobs";
7
7
 
8
8
  export function getClient({
9
9
  apiKey,
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