@omg-dev/cloud 0.6.41
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/LICENSE +21 -0
- package/dist/auth.d.ts +78 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +206 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/control-plane.d.ts +116 -0
- package/dist/control-plane.d.ts.map +1 -0
- package/dist/control-plane.js +163 -0
- package/dist/control-plane.js.map +1 -0
- package/dist/grant.d.ts +35 -0
- package/dist/grant.d.ts.map +1 -0
- package/dist/grant.js +85 -0
- package/dist/grant.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/readiness.d.ts +74 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +82 -0
- package/dist/readiness.js.map +1 -0
- package/dist/shared-binding.d.ts +135 -0
- package/dist/shared-binding.d.ts.map +1 -0
- package/dist/shared-binding.js +202 -0
- package/dist/shared-binding.js.map +1 -0
- package/dist/transports.d.ts +44 -0
- package/dist/transports.d.ts.map +1 -0
- package/dist/transports.js +119 -0
- package/dist/transports.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Addressing someone else's machine.
|
|
3
|
+
*
|
|
4
|
+
* A binding id identifies a machine everywhere: it keys the transport cache,
|
|
5
|
+
* the grant owner, and the persisted preference. A shared machine needs to be
|
|
6
|
+
* addressable by the same KIND of string, so it is spelled
|
|
7
|
+
* `shared:<ownerUserId>:<bindingId>`, exactly as the control plane expects it
|
|
8
|
+
* (`control-plane/lib/computer-access.ts` in BennyKok/vibes). Both halves are
|
|
9
|
+
* needed because sharing is PER MACHINE. This is a contract with the server,
|
|
10
|
+
* not a client convention. Do not change the format here alone.
|
|
11
|
+
*/
|
|
12
|
+
export const SHARED_BINDING_PREFIX = "shared:";
|
|
13
|
+
export function sharedBindingId(ownerUserId, bindingId) {
|
|
14
|
+
return `${SHARED_BINDING_PREFIX}${ownerUserId}:${bindingId}`;
|
|
15
|
+
}
|
|
16
|
+
export function isSharedBindingId(bindingId) {
|
|
17
|
+
return bindingId.startsWith(SHARED_BINDING_PREFIX);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The (owner, machine) pair behind a shared binding id, or null for an
|
|
21
|
+
* ordinary machine.
|
|
22
|
+
*
|
|
23
|
+
* Splits on the FIRST colon only: the owner is a uuid and never contains one,
|
|
24
|
+
* while the trailing binding id is passed through untouched so it survives
|
|
25
|
+
* whatever spelling relay chooses for it.
|
|
26
|
+
*/
|
|
27
|
+
export function parseSharedBindingId(bindingId) {
|
|
28
|
+
if (!isSharedBindingId(bindingId))
|
|
29
|
+
return null;
|
|
30
|
+
const rest = bindingId.slice(SHARED_BINDING_PREFIX.length);
|
|
31
|
+
const split = rest.indexOf(":");
|
|
32
|
+
if (split <= 0)
|
|
33
|
+
return null;
|
|
34
|
+
const ownerUserId = rest.slice(0, split).trim();
|
|
35
|
+
const target = rest.slice(split + 1).trim();
|
|
36
|
+
if (!ownerUserId || !target)
|
|
37
|
+
return null;
|
|
38
|
+
return { ownerUserId, bindingId: target };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* What the session-auth mint endpoint should be asked for, for any binding id
|
|
42
|
+
* this app might have selected. The mint route (control-plane
|
|
43
|
+
* `handleSessionAuthMint`, POST /__omg/session-auth) takes the RAW binding id
|
|
44
|
+
* plus an optional `ownerUserId` — it does not understand the `shared:`
|
|
45
|
+
* spelling itself, that decoding is entirely this app's job.
|
|
46
|
+
*/
|
|
47
|
+
export function mintTargetForBinding(bindingId) {
|
|
48
|
+
const shared = parseSharedBindingId(bindingId);
|
|
49
|
+
return shared ? { bindingId: shared.bindingId, ownerUserId: shared.ownerUserId } : { bindingId };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Detail for a revoked share — mint 403 or a `shared:` preference that is no
|
|
53
|
+
* longer in `listSharedComputers`. The empty-state TITLE is already
|
|
54
|
+
* "No longer available"; this line says why, instead of restating that title.
|
|
55
|
+
*/
|
|
56
|
+
export const SHARED_REVOKED_DETAIL = "This computer is no longer shared with you.";
|
|
57
|
+
/** "Ada" / "ada@example.com" — whichever the share row actually carries. */
|
|
58
|
+
export function sharedComputerOwnerLabel(computer) {
|
|
59
|
+
return computer.name?.trim() || computer.email;
|
|
60
|
+
}
|
|
61
|
+
export function looksLikeEmail(value) {
|
|
62
|
+
return value.includes("@");
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* First name from a real display name. Never an email — possessivizing
|
|
66
|
+
* `ada@example.com` produced "ada@example.com's computer", which is the
|
|
67
|
+
* string this helper exists to stop shipping.
|
|
68
|
+
*/
|
|
69
|
+
export function sharedComputerFirstName(computer) {
|
|
70
|
+
const named = computer.name?.trim() || computer.ownerName?.trim();
|
|
71
|
+
const fromName = firstNameToken(named);
|
|
72
|
+
if (fromName)
|
|
73
|
+
return fromName;
|
|
74
|
+
return firstNameToken(computer.ownerLabel?.trim());
|
|
75
|
+
}
|
|
76
|
+
function firstNameToken(raw) {
|
|
77
|
+
if (!raw || looksLikeEmail(raw))
|
|
78
|
+
return null;
|
|
79
|
+
const first = raw.split(/\s+/)[0] ?? "";
|
|
80
|
+
if (!first || looksLikeEmail(first))
|
|
81
|
+
return null;
|
|
82
|
+
return `${first.charAt(0).toUpperCase()}${first.slice(1)}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Which machine this share is, when the server said. Hostname first, then
|
|
86
|
+
* an explicit name, then the same URL/folder fallbacks `bindingLabel` uses
|
|
87
|
+
* for a box you own. Missing is fine — the title falls back to "computer"
|
|
88
|
+
* and collisions get a short tail.
|
|
89
|
+
*/
|
|
90
|
+
export function sharedComputerMachineIdentity(computer) {
|
|
91
|
+
const nested = computer.binding;
|
|
92
|
+
const candidates = [
|
|
93
|
+
computer.machineLabel,
|
|
94
|
+
computer.hostname,
|
|
95
|
+
computer.computerName,
|
|
96
|
+
computer.machineName,
|
|
97
|
+
nested?.hostname,
|
|
98
|
+
nested?.computerName,
|
|
99
|
+
nested?.machineName,
|
|
100
|
+
hostnameFromUrl(computer.computerUrl),
|
|
101
|
+
hostnameFromUrl(nested?.computerUrl),
|
|
102
|
+
folderBasename(computer.defaultFolder),
|
|
103
|
+
folderBasename(nested?.defaultFolder),
|
|
104
|
+
];
|
|
105
|
+
for (const candidate of candidates) {
|
|
106
|
+
const trimmed = typeof candidate === "string" ? candidate.trim() : "";
|
|
107
|
+
if (trimmed && !looksLikeEmail(trimmed))
|
|
108
|
+
return trimmed;
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
function hostnameFromUrl(url) {
|
|
113
|
+
if (!url)
|
|
114
|
+
return undefined;
|
|
115
|
+
try {
|
|
116
|
+
const host = new URL(url).hostname.split(".")[0];
|
|
117
|
+
if (host && host !== "localhost" && !/^\d+$/.test(host))
|
|
118
|
+
return host;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
/* fall through */
|
|
122
|
+
}
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
function folderBasename(folder) {
|
|
126
|
+
const name = folder?.split("/").filter(Boolean).pop()?.trim();
|
|
127
|
+
return name || undefined;
|
|
128
|
+
}
|
|
129
|
+
function ownerBindingId(computer) {
|
|
130
|
+
if (computer.ownerBindingId?.trim())
|
|
131
|
+
return computer.ownerBindingId.trim();
|
|
132
|
+
if (computer.bindingId?.trim()) {
|
|
133
|
+
const parsed = parseSharedBindingId(computer.bindingId);
|
|
134
|
+
return parsed?.bindingId ?? computer.bindingId.trim();
|
|
135
|
+
}
|
|
136
|
+
if (computer.id) {
|
|
137
|
+
const parsed = parseSharedBindingId(computer.id);
|
|
138
|
+
if (parsed)
|
|
139
|
+
return parsed.bindingId;
|
|
140
|
+
}
|
|
141
|
+
return "";
|
|
142
|
+
}
|
|
143
|
+
function uniqueTail(computer) {
|
|
144
|
+
const compact = ownerBindingId(computer).replace(/[^a-zA-Z0-9]/g, "");
|
|
145
|
+
if (compact.length >= 6)
|
|
146
|
+
return compact.slice(-6);
|
|
147
|
+
if (compact.length > 0)
|
|
148
|
+
return compact;
|
|
149
|
+
return "share";
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Title for a shared machine.
|
|
153
|
+
*
|
|
154
|
+
* - Owner has a name: first-name possessive + machine identity when we have
|
|
155
|
+
* one ("Ada's MacBook" / "Ada's studio"), else "Ada's computer".
|
|
156
|
+
* - Owner is email-only: "Shared computer". Never `"ada@example.com's computer"`.
|
|
157
|
+
* - Two rows that would otherwise match get a short unique tail.
|
|
158
|
+
*
|
|
159
|
+
* Distinct from `bindingLabel` (format.ts), which reads a machine YOU own.
|
|
160
|
+
* Never call that on a synthesized shared binding: a guest has no
|
|
161
|
+
* `computerUrl` of their own, and it would fall through to a truncated id.
|
|
162
|
+
*/
|
|
163
|
+
export function sharedBindingLabel(computer, siblings = []) {
|
|
164
|
+
const title = sharedBindingBaseTitle(computer);
|
|
165
|
+
const collisions = siblings.filter((other) => sharedBindingBaseTitle(other) === title);
|
|
166
|
+
if (collisions.length <= 1)
|
|
167
|
+
return title;
|
|
168
|
+
return `${title} · ${uniqueTail(computer)}`;
|
|
169
|
+
}
|
|
170
|
+
export function sharedBindingBaseTitle(computer) {
|
|
171
|
+
const first = sharedComputerFirstName(computer);
|
|
172
|
+
if (!first)
|
|
173
|
+
return "Shared computer";
|
|
174
|
+
const machine = sharedComputerMachineIdentity(computer);
|
|
175
|
+
return `${first}’s ${machine ?? "computer"}`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Second line on the manage screen.
|
|
179
|
+
*
|
|
180
|
+
* Attribution is the section + title. A named owner gets liveness
|
|
181
|
+
* (Online / Offline). Email-only puts the email here — that is the only
|
|
182
|
+
* place the address belongs, and possessivizing it as a title is the
|
|
183
|
+
* thing this policy forbids.
|
|
184
|
+
*/
|
|
185
|
+
export function sharedComputerSubtitle(computer) {
|
|
186
|
+
if (!sharedComputerFirstName(computer)) {
|
|
187
|
+
const email = computer.email?.trim();
|
|
188
|
+
if (email)
|
|
189
|
+
return email;
|
|
190
|
+
const label = computer.ownerLabel?.trim();
|
|
191
|
+
if (label && looksLikeEmail(label))
|
|
192
|
+
return label;
|
|
193
|
+
return computer.online === false ? "Offline" : "Online";
|
|
194
|
+
}
|
|
195
|
+
return computer.online === false ? "Offline" : "Online";
|
|
196
|
+
}
|
|
197
|
+
/** Picker row: the title, plus a title-case "Offline" suffix when down. */
|
|
198
|
+
export function sharedComputerPickerLabel(computer, siblings = []) {
|
|
199
|
+
const title = sharedBindingLabel(computer, siblings);
|
|
200
|
+
return computer.online === false ? `${title} — Offline` : title;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=shared-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-binding.js","sourceRoot":"","sources":["../src/shared-binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One grant and one transport per machine.
|
|
3
|
+
*
|
|
4
|
+
* `createGrantTransport` from @omg-dev/client already attaches the bearer
|
|
5
|
+
* grant, retries once on 401 with forceRefresh, and opens the live socket
|
|
6
|
+
* with the `lfg-bearer.<grant>` subprotocol. What this file adds is the part
|
|
7
|
+
* every host used to keep in its own code: owning exactly one grant mint in
|
|
8
|
+
* flight per binding, and one transport that every screen shares.
|
|
9
|
+
*
|
|
10
|
+
* Module scope was the bug fix, not an accident. A hook shares code, never
|
|
11
|
+
* state; several independent consumers booting at once each observed an empty
|
|
12
|
+
* cache and minted their own grant. That shipped on the web and cost five
|
|
13
|
+
* /token + five /__omg/session-auth calls on every cold open.
|
|
14
|
+
*/
|
|
15
|
+
import { type OmgGrant, type OmgTransport } from "@omg-dev/client";
|
|
16
|
+
import { type CloudEndpoints, type FetchLike } from "./config";
|
|
17
|
+
import type { MintSessionGrant } from "./grant";
|
|
18
|
+
export interface TransportCacheOptions {
|
|
19
|
+
endpoints?: Partial<CloudEndpoints>;
|
|
20
|
+
mintSessionGrant: MintSessionGrant;
|
|
21
|
+
fetch?: FetchLike;
|
|
22
|
+
WebSocket?: typeof globalThis.WebSocket;
|
|
23
|
+
now?: () => number;
|
|
24
|
+
}
|
|
25
|
+
export interface MachineTransports {
|
|
26
|
+
/** The hosted transport for a machine, shared by every consumer of it. */
|
|
27
|
+
get(bindingId: string): OmgTransport;
|
|
28
|
+
/** Seed a binding's grant from a value the server already handed over. */
|
|
29
|
+
prime(bindingId: string, grant: OmgGrant): void;
|
|
30
|
+
/** Drop a machine's cached transport, e.g. after sign-out or unpairing. */
|
|
31
|
+
forget(bindingId: string): void;
|
|
32
|
+
forgetAll(): void;
|
|
33
|
+
}
|
|
34
|
+
export declare function createMachineTransports(options: TransportCacheOptions): MachineTransports;
|
|
35
|
+
/**
|
|
36
|
+
* A transport for a box reachable directly on the network (`omg serve` on a
|
|
37
|
+
* laptop, over Tailscale). That server has no application-layer auth, so this
|
|
38
|
+
* is plain HTTP/WS against the given origin. The perimeter is the network.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createDirectTransport(baseUrl: string, options?: {
|
|
41
|
+
fetch?: FetchLike;
|
|
42
|
+
WebSocket?: typeof globalThis.WebSocket;
|
|
43
|
+
}): OmgTransport;
|
|
44
|
+
//# sourceMappingURL=transports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transports.d.ts","sourceRoot":"","sources":["../src/transports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAyB,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AA2ChD,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACpC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,SAAS,CAAC;IACxC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAAC;IACrC,0EAA0E;IAC1E,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IAChD,2EAA2E;IAC3E,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,IAAI,IAAI,CAAC;CACnB;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,qBAAqB,GAAG,iBAAiB,CAgCzF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,SAAS,CAAA;CAAO,GAC3E,YAAY,CAsCd"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One grant and one transport per machine.
|
|
3
|
+
*
|
|
4
|
+
* `createGrantTransport` from @omg-dev/client already attaches the bearer
|
|
5
|
+
* grant, retries once on 401 with forceRefresh, and opens the live socket
|
|
6
|
+
* with the `lfg-bearer.<grant>` subprotocol. What this file adds is the part
|
|
7
|
+
* every host used to keep in its own code: owning exactly one grant mint in
|
|
8
|
+
* flight per binding, and one transport that every screen shares.
|
|
9
|
+
*
|
|
10
|
+
* Module scope was the bug fix, not an accident. A hook shares code, never
|
|
11
|
+
* state; several independent consumers booting at once each observed an empty
|
|
12
|
+
* cache and minted their own grant. That shipped on the web and cost five
|
|
13
|
+
* /token + five /__omg/session-auth calls on every cold open.
|
|
14
|
+
*/
|
|
15
|
+
import { createGrantTransport, } from "@omg-dev/client";
|
|
16
|
+
import { resolveCloudEndpoints } from "./config";
|
|
17
|
+
const GRANT_SKEW_MS = 30_000;
|
|
18
|
+
function createGrantOwner(bindingId, mint, now) {
|
|
19
|
+
let cached = null;
|
|
20
|
+
let pending = null;
|
|
21
|
+
return {
|
|
22
|
+
async get({ forceRefresh }) {
|
|
23
|
+
// 30 s of slack so a grant about to die is not handed to a request
|
|
24
|
+
// that will outlive it.
|
|
25
|
+
if (!forceRefresh && cached && cached.expiresAt - now() > GRANT_SKEW_MS)
|
|
26
|
+
return cached;
|
|
27
|
+
if (!forceRefresh && pending)
|
|
28
|
+
return pending;
|
|
29
|
+
pending = mint(bindingId)
|
|
30
|
+
.then((grant) => {
|
|
31
|
+
cached = grant;
|
|
32
|
+
return grant;
|
|
33
|
+
})
|
|
34
|
+
.finally(() => {
|
|
35
|
+
pending = null;
|
|
36
|
+
});
|
|
37
|
+
return pending;
|
|
38
|
+
},
|
|
39
|
+
prime(grant) {
|
|
40
|
+
cached = grant;
|
|
41
|
+
},
|
|
42
|
+
reset() {
|
|
43
|
+
cached = null;
|
|
44
|
+
pending = null;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function createMachineTransports(options) {
|
|
49
|
+
const endpoints = resolveCloudEndpoints(options.endpoints);
|
|
50
|
+
const now = options.now ?? Date.now;
|
|
51
|
+
const entries = new Map();
|
|
52
|
+
const entryFor = (bindingId) => {
|
|
53
|
+
const existing = entries.get(bindingId);
|
|
54
|
+
if (existing)
|
|
55
|
+
return existing;
|
|
56
|
+
const owner = createGrantOwner(bindingId, options.mintSessionGrant, now);
|
|
57
|
+
const transport = createGrantTransport({
|
|
58
|
+
baseUrl: endpoints.sessionOrigin,
|
|
59
|
+
getGrant: owner.get,
|
|
60
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
61
|
+
...(options.WebSocket ? { WebSocket: options.WebSocket } : {}),
|
|
62
|
+
});
|
|
63
|
+
const entry = { transport, owner };
|
|
64
|
+
entries.set(bindingId, entry);
|
|
65
|
+
return entry;
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
get: (bindingId) => entryFor(bindingId).transport,
|
|
69
|
+
prime: (bindingId, grant) => entryFor(bindingId).owner.prime(grant),
|
|
70
|
+
forget(bindingId) {
|
|
71
|
+
entries.get(bindingId)?.owner.reset();
|
|
72
|
+
entries.delete(bindingId);
|
|
73
|
+
},
|
|
74
|
+
forgetAll() {
|
|
75
|
+
for (const entry of entries.values())
|
|
76
|
+
entry.owner.reset();
|
|
77
|
+
entries.clear();
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A transport for a box reachable directly on the network (`omg serve` on a
|
|
83
|
+
* laptop, over Tailscale). That server has no application-layer auth, so this
|
|
84
|
+
* is plain HTTP/WS against the given origin. The perimeter is the network.
|
|
85
|
+
*/
|
|
86
|
+
export function createDirectTransport(baseUrl, options = {}) {
|
|
87
|
+
const origin = baseUrl.trim().replace(/\/+$/, "");
|
|
88
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
89
|
+
const WebSocketImpl = options.WebSocket ?? globalThis.WebSocket;
|
|
90
|
+
const socketUrl = (path) => `${origin.replace(/^http/, "ws")}${path}`;
|
|
91
|
+
const doFetch = (path, init) => fetchImpl(`${origin}${path}`, init);
|
|
92
|
+
return {
|
|
93
|
+
fetch: doFetch,
|
|
94
|
+
async request(path, init = {}) {
|
|
95
|
+
const response = await doFetch(path, init);
|
|
96
|
+
const text = await response.text().catch(() => "");
|
|
97
|
+
let data = {};
|
|
98
|
+
try {
|
|
99
|
+
data = text ? JSON.parse(text) : {};
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
data = {};
|
|
103
|
+
}
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new Error(data?.error ??
|
|
106
|
+
`${init.method ?? "GET"} ${path} failed (${response.status})`);
|
|
107
|
+
}
|
|
108
|
+
return data;
|
|
109
|
+
},
|
|
110
|
+
async openSocket(path) {
|
|
111
|
+
return new WebSocketImpl(socketUrl(path));
|
|
112
|
+
},
|
|
113
|
+
async openLiveSocket(query) {
|
|
114
|
+
const suffix = query ? `?${query.replace(/^\?/, "")}` : "";
|
|
115
|
+
return new WebSocketImpl(socketUrl(`/api/live/ws${suffix}`));
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=transports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transports.js","sourceRoot":"","sources":["../src/transports.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@omg-dev/cloud",
|
|
3
|
+
"version": "0.6.41",
|
|
4
|
+
"description": "omg Cloud account client: sign-in, machine list, session grants, and one transport per machine.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://omg.dev",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/BennyKok/omg.dev.git",
|
|
10
|
+
"directory": "packages/cloud"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/BennyKok/omg.dev/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@omg-dev/client": "0.6.41"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
}
|
|
32
|
+
}
|