@soba-so/sdk 0.0.5 → 0.0.7
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/dist/client.d.ts +19 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +4 -4
- package/dist/resources.d.ts +100 -0
- package/dist/version.d.ts +1 -1
- package/package.json +6 -7
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Message, RouteRequest, RunPolicy } from "./protocol.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ConnectContextResponse, MachineListItem, PlanListResponse, SobaUser, UsagePage, UsageQuery } from "./resources.js";
|
|
3
3
|
import { type Approver, Run } from "./run.js";
|
|
4
4
|
import { type ToolDefinition } from "./tools.js";
|
|
5
5
|
/**
|
|
@@ -84,13 +84,29 @@ export declare class Soba {
|
|
|
84
84
|
/** What this user has: plan, allowance, usage this period, what they connected. */
|
|
85
85
|
get(id: string): Promise<SobaUser>;
|
|
86
86
|
/** Each connected machine, its runtimes, cost classes and live state. */
|
|
87
|
-
|
|
87
|
+
/** In the SAME shape `<ComputeStatus />` renders, so a server can fetch
|
|
88
|
+
* it and pass it to `<SobaProvider initialMachines>`. */
|
|
89
|
+
compute(id: string): Promise<MachineListItem[]>;
|
|
88
90
|
};
|
|
89
91
|
readonly usage: {
|
|
90
92
|
list(query?: UsageQuery): Promise<UsagePage>;
|
|
91
93
|
};
|
|
94
|
+
/** The app's name and connect key — the frame a compute panel renders
|
|
95
|
+
* around before it has anything to show. */
|
|
96
|
+
readonly connect: () => Promise<ConnectContextResponse>;
|
|
92
97
|
readonly plans: {
|
|
93
|
-
|
|
98
|
+
/**
|
|
99
|
+
* The app's price list, in the SAME shape a browser gets from
|
|
100
|
+
* `<SobaPlans />`'s endpoint — so a server can fetch it, hand it to
|
|
101
|
+
* `<SobaProvider initialPlans>`, and the page renders its prices on the
|
|
102
|
+
* first paint instead of after a session mint and a fetch.
|
|
103
|
+
*
|
|
104
|
+
* `user` is optional and is the same external id a run is attributed to.
|
|
105
|
+
* Pass it to learn which plan that person is on.
|
|
106
|
+
*/
|
|
107
|
+
list(options?: {
|
|
108
|
+
user?: string;
|
|
109
|
+
}): Promise<PlanListResponse>;
|
|
94
110
|
};
|
|
95
111
|
constructor(options?: SobaOptions);
|
|
96
112
|
get baseURL(): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { DEFAULT_BASE_URL, type RunParams, Soba, type SobaOptions } from "./client.js";
|
|
2
2
|
export { SobaError, type SobaErrorCode } from "./errors.js";
|
|
3
3
|
export { type AgentEvent, type AgentEventType, type CostClass, isCostClass, isMetered, isTerminal, METERED_CLASSES, type Message, type PermissionMode, type RouteRequest, type RunPolicy, type RunUsage, TOOL_SLUGS, type ToolSchema, type ToolSlug, } from "./protocol.js";
|
|
4
|
-
export type { Allowance, ConnectedMachine, MachineRuntime, PlanSummary, SobaUser, UsagePage, UsageQuery, UsageRow, } from "./resources.js";
|
|
4
|
+
export type { Allowance, ConnectContextResponse, ConnectedMachine, CurrentPlanItem, MachineListItem, MachineListState, MachineRuntime, PlanListItem, PlanListResponse, PlanSummary, RuntimeListItem, SobaUser, UsagePage, UsageQuery, UsageRow, } from "./resources.js";
|
|
5
5
|
export { type ApprovalDecision, type ApprovalRequest, type Approver, Run, } from "./run.js";
|
|
6
6
|
export { type ToolContext, type ToolDefinition, tool } from "./tools.js";
|
|
7
7
|
export { VERSION } from "./version.js";
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var s=class extends Error{code;type;status;retryable;retryAfterMs;runId;constructor(e){super(e.message,e.cause===void 0?void 0:{cause:e.cause}),this.name="SobaError",this.code=e.code,this.type=e.type??e.code,this.status=e.status,this.retryable=e.retryable??F.has(e.code),this.retryAfterMs=e.retryAfterMs,this.runId=e.runId}},F=new Set(["rate_limited","server_error","connection","timeout","stream_truncated"]),j={400:"invalid_request",401:"unauthorized",402:"payment_required",403:"forbidden",404:"not_found",409:"no_compute",422:"user_required",429:"rate_limited"};function W(t){let e=j[t];return e||(t>=500?"server_error":t>=400?"invalid_request":"unknown")}async function k(t){let e=t.status,n="";try{n=await t.text()}catch{}let r=B(n);return new s({code:r?.code??W(e),type:r?.type,message:r?.message??
|
|
2
|
-
`);if(l===-1)break;let b=q(a.slice(0,l));if(a=a.slice(l+1),r){let p=b.trim()?
|
|
3
|
-
`);if(c=[],p==="[DONE]")return;let A=p?
|
|
4
|
-
`);if(m&&m!=="[DONE]"){let d=
|
|
1
|
+
var s=class extends Error{code;type;status;retryable;retryAfterMs;runId;constructor(e){super(e.message,e.cause===void 0?void 0:{cause:e.cause}),this.name="SobaError",this.code=e.code,this.type=e.type??e.code,this.status=e.status,this.retryable=e.retryable??F.has(e.code),this.retryAfterMs=e.retryAfterMs,this.runId=e.runId}},F=new Set(["rate_limited","server_error","connection","timeout","stream_truncated"]),j={400:"invalid_request",401:"unauthorized",402:"payment_required",403:"forbidden",404:"not_found",409:"no_compute",422:"user_required",429:"rate_limited"};function W(t){let e=j[t];return e||(t>=500?"server_error":t>=400?"invalid_request":"unknown")}async function k(t){let e=t.status,n="";try{n=await t.text()}catch{}let r=B(n);return new s({code:r?.code??W(e),type:r?.type,message:r?.message??K(e,t.statusText,n),status:e,retryAfterMs:J(t.headers.get("retry-after")),runId:t.headers.get("soba-run-id")??void 0})}function B(t){if(!t)return null;let e;try{e=JSON.parse(t)}catch{return null}if(!e||typeof e!="object")return null;let n=e.error;if(!n||typeof n!="object")return null;let r=n;return{message:typeof r.message=="string"&&r.message?r.message:void 0,type:typeof r.type=="string"&&r.type?r.type:void 0,code:G.has(r.code)?r.code:void 0}}var G=new Set(["invalid_request","user_required","unauthorized","payment_required","forbidden","not_found","no_compute","rate_limited","server_error","connection","timeout","stream_truncated","run_failed","canceled","unknown"]);function K(t,e,n){let r=n.trim().slice(0,200),o=r?`: ${r}`:"";return`Soba returned ${t}${e?` ${e}`:""}${o}`}function J(t){if(!t)return;let e=Number(t);if(Number.isFinite(e)&&e>=0)return Math.round(e*1e3);let n=Date.parse(t);if(!Number.isNaN(n))return Math.max(0,n-Date.now())}function f(t){if(t instanceof s)return t;let e=t;return e?.name==="AbortError"||e?.name==="TimeoutError"?new s({code:"canceled",message:e.message||"The request was aborted.",retryable:!1,cause:t}):new s({code:"connection",message:e?.message?`Could not reach Soba: ${e.message}`:"Could not reach Soba.",cause:t})}var w="0.0.7";var H=8e3,Y=3e4;async function g(t,e){let n=Q(t.baseURL,e.path,e.query),r=e.retry===!1?1:Math.max(0,t.maxRetries)+1,o;for(let i=0;i<r;i++){i>0&&await Z(X(i,o),e.signal);let a=new AbortController,c=S(e.signal,a),m=setTimeout(()=>{a.abort(new s({code:"timeout",message:`Soba did not answer within ${t.connectTimeoutMs}ms.`}))},t.connectTimeoutMs),d;try{d=await t.fetch(n,{method:e.method,headers:z(t,e),body:e.body===void 0?void 0:JSON.stringify(e.body),signal:a.signal})}catch(l){if(c(),o=f(a.signal.aborted?a.signal.reason??l:l),!o.retryable||i===r-1)throw o;continue}finally{clearTimeout(m)}if(d.ok)return d;if(c(),o=await k(d),!o.retryable||i===r-1)throw o}throw o??new s({code:"unknown",message:"The request failed with no error."})}async function C(t,e){let n=await g(t,{accept:"application/json",...e}),r=await n.text();if(r)try{return JSON.parse(r)}catch(o){throw new s({code:"server_error",message:`Soba returned a body that is not JSON: ${r.slice(0,200)}`,status:n.status,cause:o})}}function z(t,e){let n={authorization:`Bearer ${t.apiKey}`,accept:e.accept??"application/json","user-agent":V(),...t.headers};return e.body!==void 0&&(n["content-type"]="application/json"),n}function V(){let t=typeof process>"u"?"":` node/${process.versions?.node??"?"}`;return`soba-sdk/${w}${t}`}function Q(t,e,n){let r=t.replace(/\/+$/,""),o=new URL(`${r}${e.startsWith("/")?e:`/${e}`}`);for(let[i,a]of Object.entries(n??{}))a!==void 0&&o.searchParams.set(i,String(a));return o.toString()}function X(t,e){if(e?.retryAfterMs!==void 0)return Math.min(e.retryAfterMs,Y);let n=Math.min(H,500*2**(t-1));return Math.round(n*(.5+Math.random()/2))}function Z(t,e){return new Promise((n,r)=>{if(e?.aborted)return r(f(e.reason));let o=setTimeout(()=>{e?.removeEventListener("abort",i),n()},t);function i(){clearTimeout(o),r(f(e?.reason))}e?.addEventListener("abort",i,{once:!0})})}function S(t,e){if(!t)return()=>{};if(t.aborted)return e.abort(t.reason),()=>{};let n=()=>e.abort(t.reason);return t.addEventListener("abort",n,{once:!0}),()=>t.removeEventListener("abort",n)}var _=["open-weights","frontier"];function ee(t){return _.includes(t)}function te(t){return t==="user-hardware"||t==="user-subscription"||t==="open-weights"||t==="frontier"}function T(t){return t.type==="done"||t.type==="error"}var ne=["search","fetch","read","write","edit","bash","files","agent","todo","think","sources","tool"];var P=new Set(["delta","thinking","status","done","error"]);function R(t){let e;try{e=JSON.parse(t)}catch{return null}if(!e||typeof e!="object"||Array.isArray(e))return null;let n=e,r=u(n.runId);if(typeof n.type=="string"&&P.has(n.type)){let o=I(n);return o?{kind:"event",runId:r,event:o}:null}switch(n.type){case"event":{if(!n.event||typeof n.event!="object")return null;let o=I(n.event);return o?{kind:"event",runId:r,event:o}:null}case"usage":{let o=U(n.usage);return o?{kind:"usage",runId:r,usage:o}:null}case"tool_call":{let o=u(n.callId),i=u(n.name);return!o||!i?null:{kind:"tool_call",runId:r,callId:o,name:i,input:n.input}}case"approval_request":{let o=u(n.approvalId),i=u(n.tool);return!o||!i?null:{kind:"approval",runId:r,approvalId:o,tool:i,input:n.input,cwd:u(n.cwd)}}default:return null}}function I(t){let e=typeof t.type=="string"&&P.has(t.type)?t.type:null;if(!e)return null;let n={type:e},r=u(t.text);r!==void 0&&(n.text=r);let o=u(t.message);o!==void 0&&(n.message=o);let i=u(t.tool);i!==void 0&&(n.tool=i);let a=u(t.tier);a!==void 0&&(n.tier=a);let c=U(t.usage);return c&&(n.usage=c),n}function U(t){if(!t||typeof t!="object")return null;let e=t,n={model:u(e.model)??"unknown",inputTokens:y(e.inputTokens),outputTokens:y(e.outputTokens),cacheReadTokens:y(e.cacheReadTokens),cacheWriteTokens:y(e.cacheWriteTokens),webSearches:y(e.webSearches)},r=u(e.costClass);r!==void 0&&(n.costClass=r);let o=u(e.provider);return o!==void 0&&(n.provider=o),typeof e.costMicros=="number"&&Number.isFinite(e.costMicros)&&(n.costMicros=e.costMicros),n}function u(t){return typeof t=="string"&&t.length>0?t:void 0}function y(t){return typeof t=="number"&&Number.isFinite(t)?t:0}async function*O(t){let e=t.body;if(!e)throw new s({code:"connection",message:"The run response arrived with no body to stream.",status:t.status});let n=t.headers.get("content-type")??"",r=n.includes("ndjson")||n.includes("jsonlines"),o=e.getReader(),i=new TextDecoder,a="",c=[];try{for(;;){let d=await o.read();if(d.done)break;for(a+=i.decode(d.value,{stream:!0});;){let l=a.indexOf(`
|
|
2
|
+
`);if(l===-1)break;let b=q(a.slice(0,l));if(a=a.slice(l+1),r){let p=b.trim()?R(b):null;p&&(yield p);continue}if(b===""){let p=c.join(`
|
|
3
|
+
`);if(c=[],p==="[DONE]")return;let A=p?R(p):null;A&&(yield A);continue}M(b,c)}}!r&&a&&M(q(a),c);let m=r?a.trim():c.join(`
|
|
4
|
+
`);if(m&&m!=="[DONE]"){let d=R(m);d&&(yield d)}}finally{o.cancel().catch(()=>{})}}function M(t,e){if(t.startsWith(":"))return;let n=t.indexOf(":");if(n===-1||t.slice(0,n)!=="data")return;let r=t.slice(n+1);e.push(r.startsWith(" ")?r.slice(1):r)}function q(t){return t.endsWith("\r")?t.slice(0,-1):t}function re(t){return t}function L(t){let e=new Map;for(let n of t??[]){if(!n?.name)throw new s({code:"invalid_request",message:"Every tool needs a name."});if(typeof n.execute!="function")throw new s({code:"invalid_request",message:`Tool "${n.name}" has no execute function. A tool Soba cannot call is not a tool.`});if(e.has(n.name))throw new s({code:"invalid_request",message:`Two tools are named "${n.name}". Tool names must be unique within a run.`});e.set(n.name,n)}return e}function D(t){return[...t.values()].map(e=>({name:e.name,description:e.description??"",inputSchema:e.inputSchema??{type:"object"}}))}function N(t){if(t===void 0)return null;if(typeof t=="string")return t;try{return JSON.parse(JSON.stringify(t))}catch{return String(t)}}function v(t){return t instanceof Error?t.message||t.name:typeof t=="string"?t:String(t)}var h=class{#e;#n;#r;#a=!1;#t;#o=new AbortController;#s=new AbortController;#i=new Set;#u;constructor(e){this.#t=e,this.#e=e.response.headers.get("soba-run-id")??"",this.#u=S(e.signal,this.#o)}get runId(){return this.#e}get tier(){return this.#n}get usage(){return this.#r}[Symbol.asyncIterator](){return this.#d()}async text(){let e="";for await(let n of this)if(n.type==="delta"&&n.text&&(e+=n.text),n.type==="error")throw new s({code:"run_failed",message:n.message??"The run ended with an error.",runId:this.#e,retryable:!1});return e}async cancel(){if(this.#o.abort(new s({code:"canceled",message:"The run was cancelled."})),this.#s.abort(new s({code:"canceled",message:"The run was cancelled."})),!!this.#e)try{await g(this.#t.config,{method:"POST",path:`/runs/${encodeURIComponent(this.#e)}/cancel`,retry:!1})}catch(e){this.#t.onWarning("Could not tell Soba the run was cancelled.",e)}}async*#d(){if(this.#a)throw new s({code:"invalid_request",message:"This run has already been consumed. A run's events can only be read once.",runId:this.#e});this.#a=!0;let e=!1;try{for await(let n of O(this.#t.response)){if(n.runId&&!this.#e&&(this.#e=n.runId),n.kind==="event"){let r=n.event;if(r.tier&&(this.#n=r.tier),r.usage&&(this.#r=r.usage),e=T(r),yield r,e)return;continue}if(n.kind==="usage"){this.#r=n.usage;continue}this.#l(this.#p(n))}throw new s({code:"stream_truncated",message:"The run stream ended without a `done` or `error` event.",runId:this.#e})}finally{e||this.#s.abort(new s({code:"canceled",message:"The run ended before this tool finished."})),await Promise.allSettled([...this.#i]),this.#o.abort(),this.#u()}}#l(e){this.#i.add(e),e.finally(()=>this.#i.delete(e)).catch(()=>{})}async#p(e){if(e.kind==="tool_call")return this.#f(e);if(e.kind==="approval")return this.#g(e)}async#f(e){let n=this.#t.tools.get(e.name),r,o=!1;if(!n)r=`No tool named "${e.name}" is registered by this app.`,o=!0;else{let i={runId:this.#e,user:this.#t.user,callId:e.callId,signal:this.#s.signal};try{r=await n.execute(e.input,i)}catch(a){r=v(a),o=!0}}await this.#c(`/runs/${encodeURIComponent(this.#e)}/tool_result`,{callId:e.callId,result:N(r),isError:o})}async#g(e){let n="deny",r;if(!this.#t.approve)r="This app did not supply an approver, so escalations are denied.";else try{let o={runId:this.#e,approvalId:e.approvalId,tool:e.tool,input:e.input};e.cwd&&(o.cwd=e.cwd),n=await this.#t.approve(o)==="allow"?"allow":"deny"}catch(o){r=v(o)}await this.#c(`/runs/${encodeURIComponent(this.#e)}/approval`,{approvalId:e.approvalId,decision:n,...r?{reason:r}:{}})}async#c(e,n){if(!this.#e){this.#t.onWarning("Soba sent a frame before the run had an id, so it could not be answered.",n);return}try{await(await g(this.#t.config,{method:"POST",path:e,body:n})).text()}catch(r){this.#t.onWarning(`Could not deliver an answer to ${e}.`,f(r))}}};var $="https://api.soba.so/v1",oe=3e4,se=2,x=class{#e;#n;users;usage;connect;plans;constructor(e={}){let n=e.apiKey??E("SOBA_KEY")??E("SOBA_API_KEY");if(!n)throw new s({code:"unauthorized",message:"No Soba API key. Pass `apiKey`, or set SOBA_KEY. Keys are shaped sk_soba_<id>.<secret> and come from your dashboard."});if(ie()&&!e.dangerouslyAllowBrowser)throw new s({code:"invalid_request",message:"A Soba app key is a server credential and this looks like a browser. Call Soba from your server, or pass dangerouslyAllowBrowser if you are certain."});if(this.#n=e.onWarning??(()=>{}),this.#e={apiKey:n,baseURL:e.baseURL??E("SOBA_BASE_URL")??$,headers:e.headers??{},fetch:e.fetch??globalThis.fetch,connectTimeoutMs:e.connectTimeoutMs??oe,maxRetries:e.maxRetries??se},typeof this.#e.fetch!="function")throw new s({code:"invalid_request",message:"No global fetch. Run on Node 22 or newer, or pass your own `fetch`."});this.users={get:r=>this.request("GET",`/users/${encodeURIComponent(r)}`),compute:async r=>(await this.request("GET",`/users/${encodeURIComponent(r)}/compute`)).machines},this.usage={list:r=>this.request("GET","/usage",{query:{...r}})},this.connect=()=>this.request("GET","/connect"),this.plans={list:r=>this.request("GET","/plans",{...r?.user?{query:{user:r.user}}:{}})}}get baseURL(){return this.#e.baseURL}async run(e){if(!e.user)throw new s({code:"user_required",status:422,message:"`user` is required. A run with no user cannot be attributed or metered, so it cannot be defaulted."});if(!e.prompt&&!e.messages?.length)throw new s({code:"invalid_request",status:400,message:"A run needs a `prompt` or a non-empty `messages`."});let n=L(e.tools),r={user:e.user,model:e.model??"auto"};e.prompt&&(r.prompt=e.prompt),e.messages?.length&&(r.messages=e.messages),e.system&&(r.system=e.system),e.runtime&&(r.runtime=e.runtime),n.size&&(r.tools=D(n)),e.route&&(r.route=e.route),e.policy&&(r.policy=e.policy),e.metadata&&(r.metadata=e.metadata);let o=await g(this.#e,{method:"POST",path:"/runs",body:r,accept:"text/event-stream",signal:e.signal});return new h({config:this.#e,response:o,user:e.user,tools:n,approve:e.approve,onWarning:this.#n,signal:e.signal})}async request(e,n,r={}){return C(this.#e,{method:e,path:n,...r})}};function E(t){if(typeof process>"u")return;let e=process.env?.[t];return e||void 0}function ie(){let t=globalThis;return typeof t.window=="object"&&typeof t.window?.document=="object"}export{$ as DEFAULT_BASE_URL,_ as METERED_CLASSES,h as Run,x as Soba,s as SobaError,ne as TOOL_SLUGS,w as VERSION,te as isCostClass,ee as isMetered,T as isTerminal,re as tool};
|
package/dist/resources.d.ts
CHANGED
|
@@ -83,3 +83,103 @@ export interface UsagePage {
|
|
|
83
83
|
data: UsageRow[];
|
|
84
84
|
nextCursor?: string | null;
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* WHAT `GET /v1/plans` ACTUALLY RETURNS, which `PlanSummary` above never did.
|
|
88
|
+
*
|
|
89
|
+
* `PlanSummary` describes a plan in the SDK's own idiom — camelCase, integer
|
|
90
|
+
* micros — and that is right for everything the SDK reports. It is wrong here,
|
|
91
|
+
* because these objects have one job the others do not: they are handed
|
|
92
|
+
* straight to `<SobaProvider initialPlans>` and rendered by `<SobaPlans />`,
|
|
93
|
+
* which reads the browser shape. A server that had to translate between the two
|
|
94
|
+
* would be a server that eventually translated one field differently from the
|
|
95
|
+
* component, and the symptom would be a price that changes as the page hydrates.
|
|
96
|
+
*
|
|
97
|
+
* So this mirrors the wire exactly: snake_case, dollars, `selectable` derived.
|
|
98
|
+
* `PlanSummary` keeps its place inside `SobaUser`, where nothing renders it.
|
|
99
|
+
*/
|
|
100
|
+
export interface PlanListItem {
|
|
101
|
+
id: string;
|
|
102
|
+
name: string;
|
|
103
|
+
description: string | null;
|
|
104
|
+
/** Dollars per interval. */
|
|
105
|
+
price: number;
|
|
106
|
+
interval: string;
|
|
107
|
+
unit: string;
|
|
108
|
+
included_units: number | null;
|
|
109
|
+
/** Dollars per unit past the allowance. */
|
|
110
|
+
overage_per_unit: number;
|
|
111
|
+
trial_days: number;
|
|
112
|
+
route_prefer: string[];
|
|
113
|
+
route_allow: string[] | null;
|
|
114
|
+
/** Whether it can be taken without a payment rail. */
|
|
115
|
+
selectable: boolean;
|
|
116
|
+
}
|
|
117
|
+
export interface CurrentPlanItem {
|
|
118
|
+
plan_id: string;
|
|
119
|
+
units_used: number;
|
|
120
|
+
period_end: string | null;
|
|
121
|
+
trial_ends_at: string | null;
|
|
122
|
+
}
|
|
123
|
+
export interface PlanListResponse {
|
|
124
|
+
plans: PlanListItem[];
|
|
125
|
+
/** Null unless the call named a `user`, and null for a user with no plan. */
|
|
126
|
+
current: CurrentPlanItem | null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* WHAT `GET /v1/users/:id/compute` ACTUALLY RETURNS, on the same reasoning as
|
|
130
|
+
* `PlanListItem` above.
|
|
131
|
+
*
|
|
132
|
+
* `ConnectedMachine` is the SDK's own idiom — camelCase, optional everywhere —
|
|
133
|
+
* and it is right for the machine summary nested inside `SobaUser`, which is a
|
|
134
|
+
* report. It is wrong here, because these objects are handed straight to
|
|
135
|
+
* `<SobaProvider initialMachines>` and rendered: a server translating between
|
|
136
|
+
* two shapes eventually translates one field differently from the component,
|
|
137
|
+
* and `authenticated` is the field where that costs the most. It is TRI-STATE —
|
|
138
|
+
* signed in, signed out, could not tell — and a translation that flattens the
|
|
139
|
+
* third into the second tells somebody their working setup is broken.
|
|
140
|
+
*/
|
|
141
|
+
export interface RuntimeListItem {
|
|
142
|
+
id: string;
|
|
143
|
+
display_name: string;
|
|
144
|
+
version: string | null;
|
|
145
|
+
models: string[];
|
|
146
|
+
/** The same four the protocol has. Narrow, so this list can be handed to
|
|
147
|
+
* `<ComputeStatus />` without a cast — and a cast is where a fifth class
|
|
148
|
+
* would get invented at the one seam that decides who pays. */
|
|
149
|
+
cost_class: CostClass;
|
|
150
|
+
supports_tools: boolean;
|
|
151
|
+
/** Tri-state: true signed in, false signed OUT, null could not tell. */
|
|
152
|
+
authenticated: boolean | null;
|
|
153
|
+
auth_hint: string | null;
|
|
154
|
+
/** A runtime that appeared after pairing, waiting to be approved. */
|
|
155
|
+
quarantined: boolean;
|
|
156
|
+
first_seen_at: string;
|
|
157
|
+
}
|
|
158
|
+
/** The same three values `<ComputeStatus />` renders. Narrow rather than
|
|
159
|
+
* `string`, so a server can hand the list straight to the component without a
|
|
160
|
+
* cast — and a cast is where a fourth state would get invented. */
|
|
161
|
+
export type MachineListState = "online" | "busy" | "offline";
|
|
162
|
+
export interface MachineListItem {
|
|
163
|
+
id: string;
|
|
164
|
+
label: string;
|
|
165
|
+
platform: string | null;
|
|
166
|
+
arch: string | null;
|
|
167
|
+
version: string | null;
|
|
168
|
+
state: MachineListState;
|
|
169
|
+
active: number;
|
|
170
|
+
capacity: number;
|
|
171
|
+
always_on: boolean;
|
|
172
|
+
last_seen_at: string | null;
|
|
173
|
+
runtimes: RuntimeListItem[];
|
|
174
|
+
}
|
|
175
|
+
/** The app's name and connect key, for a page rendering the panel's frame. */
|
|
176
|
+
export interface ConnectContextResponse {
|
|
177
|
+
/** How this app wants the connect component themed. */
|
|
178
|
+
theme?: "light" | "dark" | "system";
|
|
179
|
+
app: {
|
|
180
|
+
name: string;
|
|
181
|
+
};
|
|
182
|
+
publishable_key: string | null;
|
|
183
|
+
connect_url: string | null;
|
|
184
|
+
command: string | null;
|
|
185
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.0.
|
|
1
|
+
export declare const VERSION = "0.0.7";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soba-so/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "One request that comes back finished, executed on compute the end user owns.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://soba.so/docs/runs",
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
"!dist/**/*.map",
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "node ../../scripts/build-sdk.mjs",
|
|
23
|
-
"prepublishOnly": "node ../../scripts/build-sdk.mjs"
|
|
24
|
-
},
|
|
25
21
|
"engines": {
|
|
26
22
|
"node": ">=22"
|
|
27
23
|
},
|
|
@@ -34,9 +30,12 @@
|
|
|
34
30
|
"byoc"
|
|
35
31
|
],
|
|
36
32
|
"devDependencies": {
|
|
37
|
-
"@soba-so/protocol": "
|
|
33
|
+
"@soba-so/protocol": "0.1.0"
|
|
38
34
|
},
|
|
39
35
|
"publishConfig": {
|
|
40
36
|
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "node ../../scripts/build-sdk.mjs"
|
|
41
40
|
}
|
|
42
|
-
}
|
|
41
|
+
}
|