@runappsai/sdk 0.5.1 → 0.6.2
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 +29 -0
- package/dist/activity-tracker.d.ts +8 -0
- package/dist/activity-tracker.d.ts.map +1 -1
- package/dist/activity-tracker.js +3 -0
- package/dist/activity-tracker.js.map +1 -1
- package/dist/browser-auth.d.ts +7 -0
- package/dist/browser-auth.d.ts.map +1 -1
- package/dist/browser-auth.js +105 -15
- package/dist/browser-auth.js.map +1 -1
- package/dist/client.d.ts +25 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +22 -0
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +20 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/files.d.ts +3 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +4 -1
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/sdk.umd.js +2 -2
- package/dist/sdk.umd.js.map +1 -1
- package/dist/sync/codec.d.ts +39 -0
- package/dist/sync/codec.d.ts.map +1 -0
- package/dist/sync/codec.js +364 -0
- package/dist/sync/codec.js.map +1 -0
- package/dist/sync/engine.d.ts +143 -0
- package/dist/sync/engine.d.ts.map +1 -0
- package/dist/sync/engine.js +727 -0
- package/dist/sync/engine.js.map +1 -0
- package/dist/sync/hook.d.ts +42 -0
- package/dist/sync/hook.d.ts.map +1 -0
- package/dist/sync/hook.js +426 -0
- package/dist/sync/hook.js.map +1 -0
- package/dist/sync/index.d.ts +6 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +6 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/log.d.ts +41 -0
- package/dist/sync/log.d.ts.map +1 -0
- package/dist/sync/log.js +143 -0
- package/dist/sync/log.js.map +1 -0
- package/dist/sync/remote.d.ts +38 -0
- package/dist/sync/remote.d.ts.map +1 -0
- package/dist/sync/remote.js +61 -0
- package/dist/sync/remote.js.map +1 -0
- package/dist/transport.d.ts +5 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +19 -6
- package/dist/transport.js.map +1 -1
- package/package.json +2 -1
- package/src/activity-tracker.ts +5 -0
- package/src/browser-auth.ts +103 -16
- package/src/client.ts +37 -0
- package/src/events.ts +22 -0
- package/src/files.ts +7 -5
- package/src/index.ts +13 -0
- package/src/sync/codec.ts +354 -0
- package/src/sync/engine.ts +818 -0
- package/src/sync/hook.ts +495 -0
- package/src/sync/index.ts +5 -0
- package/src/sync/log.ts +170 -0
- package/src/sync/remote.ts +59 -0
- package/src/transport.ts +20 -8
package/dist/sync/log.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// sync/log.ts — the SDK's own IndexedDB database.
|
|
2
|
+
//
|
|
3
|
+
// Holds what the sync engine needs to survive a reload:
|
|
4
|
+
// ops — local changes not yet pushed, in commit order. Values are kept
|
|
5
|
+
// as the app wrote them (structured clone, Blobs included);
|
|
6
|
+
// they are encoded only when pushed, so logging works offline.
|
|
7
|
+
// meta — small key/value state: the owner (user id the local data
|
|
8
|
+
// belongs to), shard ETags seen last, store clear marks.
|
|
9
|
+
//
|
|
10
|
+
// Opened through the untouched `indexedDB.open`, never the hooked one,
|
|
11
|
+
// and its name starts with `__runapps` so the hook leaves it alone.
|
|
12
|
+
export const SYNC_DB_NAME = "__runapps_sync__";
|
|
13
|
+
const SYNC_DB_VERSION = 1;
|
|
14
|
+
function req(r) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
r.onsuccess = () => resolve(r.result);
|
|
17
|
+
r.onerror = () => reject(r.error ?? new Error("IndexedDB request failed"));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function done(tx) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
tx.oncomplete = () => resolve();
|
|
23
|
+
tx.onabort = () => reject(tx.error ?? new Error("IndexedDB transaction aborted"));
|
|
24
|
+
tx.onerror = () => reject(tx.error ?? new Error("IndexedDB transaction failed"));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export class SyncLog {
|
|
28
|
+
open;
|
|
29
|
+
dbPromise = null;
|
|
30
|
+
constructor(open) {
|
|
31
|
+
this.open = open;
|
|
32
|
+
}
|
|
33
|
+
db() {
|
|
34
|
+
if (!this.dbPromise) {
|
|
35
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
36
|
+
const r = this.open(SYNC_DB_NAME, SYNC_DB_VERSION);
|
|
37
|
+
r.onupgradeneeded = () => {
|
|
38
|
+
const db = r.result;
|
|
39
|
+
if (!db.objectStoreNames.contains("ops")) {
|
|
40
|
+
const ops = db.createObjectStore("ops", { keyPath: "id", autoIncrement: true });
|
|
41
|
+
ops.createIndex("store", ["db", "store"], { unique: false });
|
|
42
|
+
}
|
|
43
|
+
if (!db.objectStoreNames.contains("meta"))
|
|
44
|
+
db.createObjectStore("meta");
|
|
45
|
+
};
|
|
46
|
+
r.onsuccess = () => {
|
|
47
|
+
const db = r.result;
|
|
48
|
+
// Another tab upgrading (a future SDK) must not be blocked by us.
|
|
49
|
+
db.onversionchange = () => {
|
|
50
|
+
db.close();
|
|
51
|
+
this.dbPromise = null;
|
|
52
|
+
};
|
|
53
|
+
resolve(db);
|
|
54
|
+
};
|
|
55
|
+
r.onerror = () => reject(r.error ?? new Error("cannot open sync log"));
|
|
56
|
+
r.onblocked = () => reject(new Error("sync log open blocked"));
|
|
57
|
+
});
|
|
58
|
+
this.dbPromise.catch(() => {
|
|
59
|
+
this.dbPromise = null;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return this.dbPromise;
|
|
63
|
+
}
|
|
64
|
+
async append(ops) {
|
|
65
|
+
if (ops.length === 0)
|
|
66
|
+
return;
|
|
67
|
+
const db = await this.db();
|
|
68
|
+
const tx = db.transaction("ops", "readwrite");
|
|
69
|
+
const st = tx.objectStore("ops");
|
|
70
|
+
for (const op of ops)
|
|
71
|
+
st.add(op);
|
|
72
|
+
await done(tx);
|
|
73
|
+
}
|
|
74
|
+
async pending() {
|
|
75
|
+
const db = await this.db();
|
|
76
|
+
const tx = db.transaction("ops", "readonly");
|
|
77
|
+
const all = (await req(tx.objectStore("ops").getAll()));
|
|
78
|
+
return all;
|
|
79
|
+
}
|
|
80
|
+
async pendingCount() {
|
|
81
|
+
const db = await this.db();
|
|
82
|
+
const tx = db.transaction("ops", "readonly");
|
|
83
|
+
return req(tx.objectStore("ops").count());
|
|
84
|
+
}
|
|
85
|
+
async remove(ids) {
|
|
86
|
+
if (ids.length === 0)
|
|
87
|
+
return;
|
|
88
|
+
const db = await this.db();
|
|
89
|
+
const tx = db.transaction("ops", "readwrite");
|
|
90
|
+
const st = tx.objectStore("ops");
|
|
91
|
+
for (const id of ids)
|
|
92
|
+
st.delete(id);
|
|
93
|
+
await done(tx);
|
|
94
|
+
}
|
|
95
|
+
async clearOps() {
|
|
96
|
+
const db = await this.db();
|
|
97
|
+
const tx = db.transaction("ops", "readwrite");
|
|
98
|
+
tx.objectStore("ops").clear();
|
|
99
|
+
await done(tx);
|
|
100
|
+
}
|
|
101
|
+
async getMeta(key) {
|
|
102
|
+
const db = await this.db();
|
|
103
|
+
const tx = db.transaction("meta", "readonly");
|
|
104
|
+
return (await req(tx.objectStore("meta").get(key)));
|
|
105
|
+
}
|
|
106
|
+
async setMeta(entries) {
|
|
107
|
+
const db = await this.db();
|
|
108
|
+
const tx = db.transaction("meta", "readwrite");
|
|
109
|
+
const st = tx.objectStore("meta");
|
|
110
|
+
for (const k of Object.keys(entries)) {
|
|
111
|
+
if (entries[k] === undefined)
|
|
112
|
+
st.delete(k);
|
|
113
|
+
else
|
|
114
|
+
st.put(entries[k], k);
|
|
115
|
+
}
|
|
116
|
+
await done(tx);
|
|
117
|
+
}
|
|
118
|
+
/** Every meta entry whose key starts with `prefix`, as a map. */
|
|
119
|
+
async metaWithPrefix(prefix) {
|
|
120
|
+
const db = await this.db();
|
|
121
|
+
const tx = db.transaction("meta", "readonly");
|
|
122
|
+
const st = tx.objectStore("meta");
|
|
123
|
+
const range = IDBKeyRange.bound(prefix, prefix + "");
|
|
124
|
+
const keys = (await req(st.getAllKeys(range)));
|
|
125
|
+
const vals = await req(st.getAll(range));
|
|
126
|
+
const out = new Map();
|
|
127
|
+
keys.forEach((k, i) => out.set(k, vals[i]));
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
async clearAll() {
|
|
131
|
+
const db = await this.db();
|
|
132
|
+
const tx = db.transaction(["ops", "meta"], "readwrite");
|
|
133
|
+
tx.objectStore("ops").clear();
|
|
134
|
+
tx.objectStore("meta").clear();
|
|
135
|
+
await done(tx);
|
|
136
|
+
}
|
|
137
|
+
close() {
|
|
138
|
+
this.dbPromise?.then((db) => db.close()).catch(() => { });
|
|
139
|
+
this.dbPromise = null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export { req as idbRequest, done as idbDone };
|
|
143
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/sync/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { FilesService } from "../files.js";
|
|
2
|
+
import type { SyncRemote } from "./engine.js";
|
|
3
|
+
export declare class FilesRemote implements SyncRemote {
|
|
4
|
+
private readonly files;
|
|
5
|
+
constructor(files: FilesService);
|
|
6
|
+
list(prefix: string): Promise<{
|
|
7
|
+
path: string;
|
|
8
|
+
etag: string;
|
|
9
|
+
}[]>;
|
|
10
|
+
getJSON(path: string, ifNoneMatch?: string): Promise<{
|
|
11
|
+
status: "unchanged";
|
|
12
|
+
value?: undefined;
|
|
13
|
+
etag?: undefined;
|
|
14
|
+
} | {
|
|
15
|
+
status: "missing";
|
|
16
|
+
value?: undefined;
|
|
17
|
+
etag?: undefined;
|
|
18
|
+
} | {
|
|
19
|
+
status: "ok";
|
|
20
|
+
value: {} | null;
|
|
21
|
+
etag: string;
|
|
22
|
+
}>;
|
|
23
|
+
putJSON(path: string, value: unknown, cond: {
|
|
24
|
+
ifMatch?: string;
|
|
25
|
+
ifNoneMatch?: boolean;
|
|
26
|
+
}): Promise<{
|
|
27
|
+
status: "ok";
|
|
28
|
+
etag: string;
|
|
29
|
+
serverTime: number | undefined;
|
|
30
|
+
} | {
|
|
31
|
+
status: "conflict";
|
|
32
|
+
etag?: undefined;
|
|
33
|
+
serverTime?: undefined;
|
|
34
|
+
}>;
|
|
35
|
+
putBlob(path: string, blob: Blob): Promise<void>;
|
|
36
|
+
getBlob(path: string): Promise<Blob>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/sync/remote.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,qBAAa,WAAY,YAAW,UAAU;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY;IAE1C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAW/D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;;;;;;;;;;;;;IAO1C,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE;;;;;;;;;IAevF,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGrC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// sync/remote.ts — the sync engine's storage, over the files API.
|
|
2
|
+
//
|
|
3
|
+
// Shards are plain JSON files in the user's file space for the app, so
|
|
4
|
+
// they share its quota, billing and deletion with everything else the
|
|
5
|
+
// app stores for that user. Conditional reads (304) and writes (412 /
|
|
6
|
+
// 409) come from the files API, which checks them against the store.
|
|
7
|
+
export class FilesRemote {
|
|
8
|
+
files;
|
|
9
|
+
constructor(files) {
|
|
10
|
+
this.files = files;
|
|
11
|
+
}
|
|
12
|
+
async list(prefix) {
|
|
13
|
+
const out = [];
|
|
14
|
+
let cursor;
|
|
15
|
+
do {
|
|
16
|
+
const page = await this.files.list({ prefix, limit: 1000, ...(cursor ? { cursor } : {}) });
|
|
17
|
+
for (const f of page.files)
|
|
18
|
+
if (f.etag)
|
|
19
|
+
out.push({ path: f.path, etag: f.etag });
|
|
20
|
+
cursor = page.next_cursor;
|
|
21
|
+
} while (cursor);
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
async getJSON(path, ifNoneMatch) {
|
|
25
|
+
const r = await this.files.readJSON(path, ifNoneMatch ? { ifNoneMatch } : undefined);
|
|
26
|
+
if (r.notModified)
|
|
27
|
+
return { status: "unchanged" };
|
|
28
|
+
if (r.value === undefined)
|
|
29
|
+
return { status: "missing" };
|
|
30
|
+
return { status: "ok", value: r.value, etag: r.etag ?? "" };
|
|
31
|
+
}
|
|
32
|
+
async putJSON(path, value, cond) {
|
|
33
|
+
try {
|
|
34
|
+
const obj = await this.files.put(path, JSON.stringify(value), {
|
|
35
|
+
contentType: "application/json",
|
|
36
|
+
...(cond.ifMatch ? { ifMatch: cond.ifMatch } : {}),
|
|
37
|
+
...(cond.ifNoneMatch ? { ifNoneMatch: true } : {}),
|
|
38
|
+
});
|
|
39
|
+
return { status: "ok", etag: obj.etag ?? "", serverTime: obj.last_modified ? Date.parse(obj.last_modified) : undefined };
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
const code = e.statusCode;
|
|
43
|
+
if (code === 412 || code === 409)
|
|
44
|
+
return { status: "conflict" };
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async putBlob(path, blob) {
|
|
49
|
+
try {
|
|
50
|
+
await this.files.put(path, blob, { contentType: blob.type || "application/octet-stream", ifNoneMatch: true });
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
if (e.statusCode !== 409)
|
|
54
|
+
throw e; // already stored: same bytes, same name
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
getBlob(path) {
|
|
58
|
+
return this.files.get(path);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/sync/remote.ts"],"names":[],"mappings":"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"}
|
package/dist/transport.d.ts
CHANGED
|
@@ -83,10 +83,13 @@ export declare class Transport {
|
|
|
83
83
|
* and the ETag of those bytes, when the server sends one. */
|
|
84
84
|
getRaw(path: string, init?: {
|
|
85
85
|
signal?: AbortSignal;
|
|
86
|
+
ifNoneMatch?: string;
|
|
86
87
|
}): Promise<{
|
|
87
88
|
data: Uint8Array;
|
|
88
89
|
contentType: string;
|
|
89
90
|
etag?: string;
|
|
91
|
+
notModified?: boolean;
|
|
92
|
+
serverTime?: number;
|
|
90
93
|
}>;
|
|
91
94
|
/** POST a multipart/form-data body. Used by audio.transcribe and image.edit. */
|
|
92
95
|
postMultipart<T>(path: string, form: FormData, init?: {
|
|
@@ -123,4 +126,6 @@ export declare class Transport {
|
|
|
123
126
|
private authHeaders;
|
|
124
127
|
private parseError;
|
|
125
128
|
}
|
|
129
|
+
/** The server's clock from a Date header, as ms since epoch. */
|
|
130
|
+
export declare function parseServerDate(h: string | null): number | undefined;
|
|
126
131
|
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;gDAK4C;IAC5C,cAAc,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,qBAAa,SAAS;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+C;IAC9E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2C;IAC1E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAE7B,IAAI,EAAE,gBAAgB;IAmBlC,qDAAqD;YACvC,YAAY;IAK1B;;;;;;;OAOG;YACW,kBAAkB;IAiBhC;;;;;;;;;;;;OAYG;YACW,SAAS;IAKvB,2CAA2C;IACrC,QAAQ,CAAC,CAAC,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC9B,OAAO,CAAC,CAAC,CAAC;IAab,qCAAqC;IAC/B,OAAO,CAAC,CAAC,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC9B,OAAO,CAAC,CAAC,CAAC;IAYb;;6DAEyD;IACnD,aAAa,CAAC,CAAC,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC9B,OAAO,CAAC,CAAC,CAAC;IAYb;kEAC8D;IACxD,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/dist/transport.js
CHANGED
|
@@ -109,18 +109,24 @@ export class Transport {
|
|
|
109
109
|
/** GET path; return raw bytes + content-type (for video/audio downloads)
|
|
110
110
|
* and the ETag of those bytes, when the server sends one. */
|
|
111
111
|
async getRaw(path, init) {
|
|
112
|
-
const resp = await this.fetchWithAuthRetry(path, async () =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
const resp = await this.fetchWithAuthRetry(path, async () => {
|
|
113
|
+
const headers = await this.authHeaders();
|
|
114
|
+
if (init?.ifNoneMatch)
|
|
115
|
+
headers["If-None-Match"] = `"${init.ifNoneMatch.replace(/"/g, "")}"`;
|
|
116
|
+
return { method: "GET", headers, signal: init?.signal };
|
|
117
|
+
});
|
|
118
|
+
const serverTime = parseServerDate(resp.headers.get("date"));
|
|
119
|
+
if (resp.status === 304) {
|
|
120
|
+
const etag = (resp.headers.get("etag") ?? "").replace(/"/g, "") || init?.ifNoneMatch;
|
|
121
|
+
return { data: new Uint8Array(0), contentType: "", etag, notModified: true, serverTime };
|
|
122
|
+
}
|
|
117
123
|
if (!resp.ok) {
|
|
118
124
|
throw await this.parseError(resp);
|
|
119
125
|
}
|
|
120
126
|
const buf = new Uint8Array(await resp.arrayBuffer());
|
|
121
127
|
const contentType = resp.headers.get("content-type") ?? "";
|
|
122
128
|
const etag = (resp.headers.get("etag") ?? "").replace(/"/g, "") || undefined;
|
|
123
|
-
return { data: buf, contentType, etag };
|
|
129
|
+
return { data: buf, contentType, etag, serverTime };
|
|
124
130
|
}
|
|
125
131
|
/** POST a multipart/form-data body. Used by audio.transcribe and image.edit. */
|
|
126
132
|
async postMultipart(path, form, init) {
|
|
@@ -225,4 +231,11 @@ export class Transport {
|
|
|
225
231
|
return new APIError(resp.status, type, message);
|
|
226
232
|
}
|
|
227
233
|
}
|
|
234
|
+
/** The server's clock from a Date header, as ms since epoch. */
|
|
235
|
+
export function parseServerDate(h) {
|
|
236
|
+
if (!h)
|
|
237
|
+
return undefined;
|
|
238
|
+
const t = Date.parse(h);
|
|
239
|
+
return Number.isNaN(t) ? undefined : t;
|
|
240
|
+
}
|
|
228
241
|
//# sourceMappingURL=transport.js.map
|
package/dist/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runappsai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "JavaScript / TypeScript client for the RunApps AI Gateway",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RunApps",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^20.0.0",
|
|
53
|
+
"fake-indexeddb": "^6.2.5",
|
|
53
54
|
"tsup": "^8.5.1",
|
|
54
55
|
"typescript": "^5.5.0"
|
|
55
56
|
}
|
package/src/activity-tracker.ts
CHANGED
|
@@ -85,6 +85,8 @@ export interface ActivitySnapshot {
|
|
|
85
85
|
active: ActiveCall[];
|
|
86
86
|
recent: CompletedCall[];
|
|
87
87
|
session: SessionStats;
|
|
88
|
+
/** Sync state, when RunApps Sync is on (see `client.sync`). */
|
|
89
|
+
sync?: { state: "off" | "idle" | "syncing" | "offline" | "error"; pending: number; lastSyncedAt?: number; error?: string };
|
|
88
90
|
/** Highest-priority status colour for the LED dot:
|
|
89
91
|
* "error" → recent failure within ERROR_HIGHLIGHT_MS
|
|
90
92
|
* "active" → at least one in-flight call
|
|
@@ -116,6 +118,7 @@ export class ActivityTracker {
|
|
|
116
118
|
* ring/LED stayed idle until the user opened the popover —
|
|
117
119
|
* events landed in the tracker but nobody told the DOM. */
|
|
118
120
|
private changeListeners = new Set<() => void>();
|
|
121
|
+
private sync: ActivitySnapshot["sync"] | undefined = undefined;
|
|
119
122
|
|
|
120
123
|
/**
|
|
121
124
|
* Subscribe the tracker to a bus. Returns a single disposer that
|
|
@@ -128,6 +131,7 @@ export class ActivityTracker {
|
|
|
128
131
|
events.on("request:streamDelta", (e) => { this.onDelta(e); this.notify(); }),
|
|
129
132
|
events.on("request:end", (e) => { this.onEnd(e); this.notify(); }),
|
|
130
133
|
events.on("request:error", (e) => { this.onError(e); this.notify(); }),
|
|
134
|
+
events.on("sync:state", (e) => { this.sync = { ...e }; this.notify(); }),
|
|
131
135
|
];
|
|
132
136
|
return () => {
|
|
133
137
|
for (const o of offs) o();
|
|
@@ -165,6 +169,7 @@ export class ActivityTracker {
|
|
|
165
169
|
active: Array.from(this.active.values()),
|
|
166
170
|
recent: this.recent.slice(),
|
|
167
171
|
session: { ...this.session },
|
|
172
|
+
...(this.sync ? { sync: { ...this.sync } } : {}),
|
|
168
173
|
status:
|
|
169
174
|
now - this.lastErrorAt < ERROR_HIGHLIGHT_MS
|
|
170
175
|
? "error"
|
package/src/browser-auth.ts
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import { ActivityTracker, type ActivitySnapshot, type SessionStats } from "./activity-tracker.js";
|
|
25
25
|
import type { SDKEvents } from "./events.js";
|
|
26
|
+
import { hash32 } from "./sync/codec.js";
|
|
26
27
|
|
|
27
28
|
export interface BrowserAuthOptions {
|
|
28
29
|
/**
|
|
@@ -310,6 +311,18 @@ export class BrowserAuth {
|
|
|
310
311
|
return this.tokenIsFresh();
|
|
311
312
|
}
|
|
312
313
|
|
|
314
|
+
/**
|
|
315
|
+
* A stable id for whose data is on this browser, or null when nobody
|
|
316
|
+
* is signed in. The user's id when the grant carried one; otherwise
|
|
317
|
+
* derived from the token, which is bound to one user and one app and
|
|
318
|
+
* never rotates. Used by Sync to tell an account switch.
|
|
319
|
+
*/
|
|
320
|
+
ownerId(): string | null {
|
|
321
|
+
if (!this.tokenIsFresh()) return null;
|
|
322
|
+
if (this.userInfo?.id) return this.userInfo.id;
|
|
323
|
+
return "t" + hash32(this.token as string).toString(36);
|
|
324
|
+
}
|
|
325
|
+
|
|
313
326
|
/**
|
|
314
327
|
* Clear the cached token / user / badge and the persisted copy in
|
|
315
328
|
* localStorage. Next gateway call will trigger a redirect to the
|
|
@@ -544,7 +557,7 @@ export class BrowserAuth {
|
|
|
544
557
|
.split("&")
|
|
545
558
|
.forEach((kv) => {
|
|
546
559
|
const i = kv.indexOf("=");
|
|
547
|
-
if (i >= 0) params[decodeURIComponent(kv.slice(0, i))] = decodeURIComponent(kv.slice(i + 1));
|
|
560
|
+
if (i >= 0) params[decodeURIComponent(kv.slice(0, i))] = decodeURIComponent(kv.slice(i + 1).replace(/\+/g, " "));
|
|
548
561
|
});
|
|
549
562
|
const token = params.runapps_token || params.runjobs_token;
|
|
550
563
|
if (!token) return false;
|
|
@@ -870,7 +883,7 @@ function mountActivityBadge(opts: MountOpts): HTMLButtonElement {
|
|
|
870
883
|
const el = document.createElement("button");
|
|
871
884
|
el.id = id;
|
|
872
885
|
el.type = "button";
|
|
873
|
-
el.title = "RunApps
|
|
886
|
+
el.title = user.name || "RunApps";
|
|
874
887
|
el.setAttribute("aria-label", "RunApps activity status");
|
|
875
888
|
el.style.cssText = [
|
|
876
889
|
"position:fixed",
|
|
@@ -878,9 +891,9 @@ function mountActivityBadge(opts: MountOpts): HTMLButtonElement {
|
|
|
878
891
|
"z-index:2147483647",
|
|
879
892
|
"display:flex",
|
|
880
893
|
"align-items:center",
|
|
881
|
-
"
|
|
882
|
-
"padding:
|
|
883
|
-
"border-radius:
|
|
894
|
+
"justify-content:center",
|
|
895
|
+
"padding:5px",
|
|
896
|
+
"border-radius:50%",
|
|
884
897
|
"font:500 12px/1 -apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif",
|
|
885
898
|
"color:#fff",
|
|
886
899
|
"background:rgba(15,15,20,0.55)",
|
|
@@ -889,7 +902,6 @@ function mountActivityBadge(opts: MountOpts): HTMLButtonElement {
|
|
|
889
902
|
"border:1px solid rgba(255,255,255,0.12)",
|
|
890
903
|
"box-shadow:0 4px 16px rgba(0,0,0,0.15)",
|
|
891
904
|
"user-select:none",
|
|
892
|
-
"max-width:220px",
|
|
893
905
|
"overflow:visible", // popover spills out the top
|
|
894
906
|
"cursor:pointer",
|
|
895
907
|
"appearance:none",
|
|
@@ -982,12 +994,7 @@ function mountActivityBadge(opts: MountOpts): HTMLButtonElement {
|
|
|
982
994
|
avatarWrap.appendChild(avatar);
|
|
983
995
|
avatarWrap.appendChild(led);
|
|
984
996
|
|
|
985
|
-
const name = document.createElement("span");
|
|
986
|
-
name.textContent = user.name || "Signed in";
|
|
987
|
-
name.style.cssText = "white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none";
|
|
988
|
-
|
|
989
997
|
el.appendChild(avatarWrap);
|
|
990
|
-
el.appendChild(name);
|
|
991
998
|
|
|
992
999
|
// ─── Popover (lazy, append on first open) ──────────────────
|
|
993
1000
|
//
|
|
@@ -1035,7 +1042,7 @@ function mountActivityBadge(opts: MountOpts): HTMLButtonElement {
|
|
|
1035
1042
|
return;
|
|
1036
1043
|
}
|
|
1037
1044
|
if (!popover) {
|
|
1038
|
-
popover = createPopover(dashboardUrl, currentPopoverCss, () => {
|
|
1045
|
+
popover = createPopover(user, dashboardUrl, currentPopoverCss, () => {
|
|
1039
1046
|
// Tear down our DOM before the auth flip runs so the popover
|
|
1040
1047
|
// doesn't briefly show "signed out" state to a user who's
|
|
1041
1048
|
// about to navigate away. closePopover() also removes the
|
|
@@ -1344,10 +1351,26 @@ function updateRing(
|
|
|
1344
1351
|
|
|
1345
1352
|
function updateLED(led: HTMLSpanElement, snap: ActivitySnapshot): void {
|
|
1346
1353
|
switch (snap.status) {
|
|
1347
|
-
case "idle":
|
|
1348
|
-
|
|
1349
|
-
|
|
1354
|
+
case "idle": {
|
|
1355
|
+
// Nothing in flight: the LED shows the sync instead — blue pulse
|
|
1356
|
+
// while syncing, amber while changes wait offline or after a
|
|
1357
|
+
// failed attempt, grey when everything is on the server.
|
|
1358
|
+
const sync = snap.sync;
|
|
1359
|
+
if (sync && sync.state === "syncing") {
|
|
1360
|
+
led.style.background = "#3b82f6";
|
|
1361
|
+
led.style.boxShadow = "0 0 0 0 rgba(59,130,246,0.7)";
|
|
1362
|
+
led.style.animation = "__runapps_led_pulse__ 1.2s ease-out infinite";
|
|
1363
|
+
} else if (sync && (sync.state === "offline" || sync.state === "error")) {
|
|
1364
|
+
led.style.background = "#f59e0b";
|
|
1365
|
+
led.style.boxShadow = "0 0 0 2px rgba(245,158,11,0.3)";
|
|
1366
|
+
led.style.animation = "";
|
|
1367
|
+
} else {
|
|
1368
|
+
led.style.background = "rgba(255,255,255,0.2)";
|
|
1369
|
+
led.style.boxShadow = "0 0 0 0 transparent";
|
|
1370
|
+
led.style.animation = "";
|
|
1371
|
+
}
|
|
1350
1372
|
break;
|
|
1373
|
+
}
|
|
1351
1374
|
case "active":
|
|
1352
1375
|
led.style.background = "#3b82f6";
|
|
1353
1376
|
// CSS-driven pulse via box-shadow ring expanding outward —
|
|
@@ -1363,7 +1386,7 @@ function updateLED(led: HTMLSpanElement, snap: ActivitySnapshot): void {
|
|
|
1363
1386
|
}
|
|
1364
1387
|
}
|
|
1365
1388
|
|
|
1366
|
-
function createPopover(dashboardUrl: string, anchorCss: string, onSignOut: () => void): HTMLDivElement {
|
|
1389
|
+
function createPopover(user: BrowserUser, dashboardUrl: string, anchorCss: string, onSignOut: () => void): HTMLDivElement {
|
|
1367
1390
|
const pop = document.createElement("div");
|
|
1368
1391
|
pop.style.cssText = [
|
|
1369
1392
|
"position:absolute",
|
|
@@ -1387,6 +1410,37 @@ function createPopover(dashboardUrl: string, anchorCss: string, onSignOut: () =>
|
|
|
1387
1410
|
pop.setAttribute("data-runapps-popover", "1");
|
|
1388
1411
|
pop.addEventListener("click", (e) => e.stopPropagation());
|
|
1389
1412
|
|
|
1413
|
+
// Who is signed in. The badge itself is only the avatar circle, so
|
|
1414
|
+
// the full name lives here, above the activity sections.
|
|
1415
|
+
const header = document.createElement("div");
|
|
1416
|
+
header.style.cssText = [
|
|
1417
|
+
"display:flex;align-items:center;gap:8px",
|
|
1418
|
+
"margin-bottom:10px;padding-bottom:8px",
|
|
1419
|
+
"border-bottom:1px solid rgba(255,255,255,0.08)",
|
|
1420
|
+
].join(";");
|
|
1421
|
+
const headAvatar = document.createElement("div");
|
|
1422
|
+
headAvatar.textContent = (user.name || "?").charAt(0).toUpperCase();
|
|
1423
|
+
headAvatar.style.cssText = [
|
|
1424
|
+
"width:24px;height:24px;border-radius:50%;flex-shrink:0",
|
|
1425
|
+
"display:flex;align-items:center;justify-content:center",
|
|
1426
|
+
"background:linear-gradient(135deg,#3b82f6,#8b5cf6)",
|
|
1427
|
+
"font-size:11px;font-weight:600;color:#fff",
|
|
1428
|
+
].join(";");
|
|
1429
|
+
const headName = document.createElement("div");
|
|
1430
|
+
headName.textContent = user.name || "Signed in";
|
|
1431
|
+
headName.title = user.name || "";
|
|
1432
|
+
headName.style.cssText = "font-size:12px;font-weight:500;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
1433
|
+
const headSub = document.createElement("div");
|
|
1434
|
+
headSub.textContent = "Signed in with RunApps";
|
|
1435
|
+
headSub.style.cssText = "font-size:10px;color:rgba(255,255,255,0.5)";
|
|
1436
|
+
const headText = document.createElement("div");
|
|
1437
|
+
headText.style.cssText = "min-width:0";
|
|
1438
|
+
headText.appendChild(headName);
|
|
1439
|
+
headText.appendChild(headSub);
|
|
1440
|
+
header.appendChild(headAvatar);
|
|
1441
|
+
header.appendChild(headText);
|
|
1442
|
+
pop.appendChild(header);
|
|
1443
|
+
|
|
1390
1444
|
// The popover's content is rebuilt on every redraw to keep DOM
|
|
1391
1445
|
// diffing simple. ~3 sections × ~6 children = ~20 nodes, no
|
|
1392
1446
|
// measurable cost at the 6 Hz redraw rate.
|
|
@@ -1448,9 +1502,42 @@ function updatePopover(pop: HTMLDivElement, snap: ActivitySnapshot): void {
|
|
|
1448
1502
|
const now = Date.now();
|
|
1449
1503
|
inner.appendChild(renderActiveSection(snap, now));
|
|
1450
1504
|
inner.appendChild(renderRecentSection(snap, now));
|
|
1505
|
+
if (snap.sync) inner.appendChild(renderSyncSection(snap.sync, now));
|
|
1451
1506
|
inner.appendChild(renderSessionSection(snap.session, now));
|
|
1452
1507
|
}
|
|
1453
1508
|
|
|
1509
|
+
function renderSyncSection(sync: NonNullable<ActivitySnapshot["sync"]>, now: number): HTMLDivElement {
|
|
1510
|
+
const sec = document.createElement("div");
|
|
1511
|
+
sec.style.marginBottom = "10px";
|
|
1512
|
+
const hint = sync.lastSyncedAt ? `synced ${relativeTime(now - sync.lastSyncedAt)}` : "—";
|
|
1513
|
+
sec.appendChild(sectionLabel("Sync", hint));
|
|
1514
|
+
const row = document.createElement("div");
|
|
1515
|
+
row.style.cssText = "display:flex;justify-content:space-between;gap:8px;padding:3px 0;font-size:10px";
|
|
1516
|
+
const left = document.createElement("span");
|
|
1517
|
+
const dot = document.createElement("span");
|
|
1518
|
+
dot.textContent = "● ";
|
|
1519
|
+
const label: Record<string, [string, string]> = {
|
|
1520
|
+
off: ["Not signed in", "rgba(255,255,255,0.4)"],
|
|
1521
|
+
idle: ["Up to date", "#10b981"],
|
|
1522
|
+
syncing: ["Syncing…", "#3b82f6"],
|
|
1523
|
+
offline: ["Offline", "#f59e0b"],
|
|
1524
|
+
error: ["Retrying", "#f59e0b"],
|
|
1525
|
+
};
|
|
1526
|
+
const [text, color] = label[sync.state] ?? ["", "#fff"];
|
|
1527
|
+
dot.style.color = color;
|
|
1528
|
+
left.style.color = "#fff";
|
|
1529
|
+
left.appendChild(dot);
|
|
1530
|
+
left.appendChild(document.createTextNode(text));
|
|
1531
|
+
const right = document.createElement("span");
|
|
1532
|
+
right.style.cssText = "color:rgba(255,255,255,0.7);font-variant-numeric:tabular-nums";
|
|
1533
|
+
right.textContent = sync.pending > 0 ? `${sync.pending} pending` : "";
|
|
1534
|
+
right.title = sync.error ?? "";
|
|
1535
|
+
row.appendChild(left);
|
|
1536
|
+
row.appendChild(right);
|
|
1537
|
+
sec.appendChild(row);
|
|
1538
|
+
return sec;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1454
1541
|
function renderActiveSection(snap: ActivitySnapshot, now: number): HTMLDivElement {
|
|
1455
1542
|
const sec = document.createElement("div");
|
|
1456
1543
|
sec.style.marginBottom = "10px";
|