@runappsai/sdk 0.7.9 → 0.8.1
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 +13 -3
- package/dist/client.d.ts +7 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -2
- package/dist/client.js.map +1 -1
- package/dist/files.d.ts +40 -2
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +89 -15
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/sdk.umd.js +3 -3
- package/dist/sdk.umd.js.map +1 -1
- package/dist/transport.d.ts +7 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +19 -2
- package/dist/transport.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +9 -2
- package/src/files.ts +99 -17
- package/src/index.ts +1 -0
- package/src/transport.ts +19 -2
package/dist/transport.d.ts
CHANGED
|
@@ -40,6 +40,13 @@ export declare class Transport {
|
|
|
40
40
|
private readonly onUnauthorized;
|
|
41
41
|
private readonly fetchImpl;
|
|
42
42
|
constructor(opts: TransportOptions);
|
|
43
|
+
/** Absolute URLs pass through; paths are joined to the base. The files
|
|
44
|
+
* service uses this to send file calls to the files host. */
|
|
45
|
+
private resolve;
|
|
46
|
+
/** A short, non-secret fingerprint of the current token, so a service
|
|
47
|
+
* can notice that the signed-in user changed and drop per-user state
|
|
48
|
+
* (the files base is derived from the user). */
|
|
49
|
+
tokenFingerprint(): Promise<string>;
|
|
43
50
|
/** Resolve the bearer token for the next request. */
|
|
44
51
|
private resolveToken;
|
|
45
52
|
/** The current bearer token, for connections fetch can't make (WebSocket). */
|
package/dist/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/dist/transport.js
CHANGED
|
@@ -21,6 +21,23 @@ export class Transport {
|
|
|
21
21
|
// for any binding their wrapper needs.
|
|
22
22
|
this.fetchImpl = opts.fetchImpl ?? fetch.bind(globalThis);
|
|
23
23
|
}
|
|
24
|
+
/** Absolute URLs pass through; paths are joined to the base. The files
|
|
25
|
+
* service uses this to send file calls to the files host. */
|
|
26
|
+
resolve(path) {
|
|
27
|
+
return /^https?:\/\//i.test(path) ? path : this.baseURL + path;
|
|
28
|
+
}
|
|
29
|
+
/** A short, non-secret fingerprint of the current token, so a service
|
|
30
|
+
* can notice that the signed-in user changed and drop per-user state
|
|
31
|
+
* (the files base is derived from the user). */
|
|
32
|
+
async tokenFingerprint() {
|
|
33
|
+
const t = await this.resolveToken();
|
|
34
|
+
if (!t)
|
|
35
|
+
return "";
|
|
36
|
+
let h = 0;
|
|
37
|
+
for (let i = 0; i < t.length; i++)
|
|
38
|
+
h = (h * 31 + t.charCodeAt(i)) | 0;
|
|
39
|
+
return (h >>> 0).toString(36) + ":" + t.length;
|
|
40
|
+
}
|
|
24
41
|
/** Resolve the bearer token for the next request. */
|
|
25
42
|
async resolveToken() {
|
|
26
43
|
if (this.apiKeyResolver)
|
|
@@ -40,7 +57,7 @@ export class Transport {
|
|
|
40
57
|
* `onUnauthorized` is absent or already retried.
|
|
41
58
|
*/
|
|
42
59
|
async fetchWithAuthRetry(path, build) {
|
|
43
|
-
const url = this.
|
|
60
|
+
const url = this.resolve(path);
|
|
44
61
|
let resp = await this.fetchImpl(url, await this.buildInit(build));
|
|
45
62
|
if (resp.status !== 401 || !this.onUnauthorized)
|
|
46
63
|
return resp;
|
|
@@ -100,7 +117,7 @@ export class Transport {
|
|
|
100
117
|
* token — in browser sign-in mode that would send a signed-out user to
|
|
101
118
|
* the sign-in page just to read the model catalogue. */
|
|
102
119
|
async getPublicJSON(path, init) {
|
|
103
|
-
const resp = await this.fetchImpl(this.
|
|
120
|
+
const resp = await this.fetchImpl(this.resolve(path), {
|
|
104
121
|
method: "GET",
|
|
105
122
|
cache: "no-store",
|
|
106
123
|
...(init?.signal ? { signal: init.signal } : {}),
|
package/dist/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAsCvC,MAAM,OAAO,SAAS;IACX,OAAO,CAAS;IACR,MAAM,CAAqB;IAC3B,cAAc,CAA+C;IAC7D,cAAc,CAA2C;IACzD,SAAS,CAAe;IAEzC,YAAY,IAAsB;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CACb,gFAAgF,CACjF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC1C,6DAA6D;QAC7D,6DAA6D;QAC7D,wDAAwD;QACxD,yDAAyD;QACzD,kEAAkE;QAClE,uCAAuC;QACvC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC;IAED,qDAAqD;IAC7C,KAAK,CAAC,YAAY;QACxB,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,8EAA8E;IAC9E,WAAW;QACT,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,kBAAkB,CAC9B,IAAY,EACZ,KAAiC;QAEjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -99,6 +99,13 @@ export interface ClientOptions {
|
|
|
99
99
|
* pair.
|
|
100
100
|
*/
|
|
101
101
|
project?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Where file calls go. By default the SDK asks the gateway for a
|
|
104
|
+
* per-user base on the files host (`https://files.runapps.ai/u/<hash>`)
|
|
105
|
+
* and falls back to the classic `/v1/files` paths on older gateways.
|
|
106
|
+
* `false` keeps the classic paths; a URL overrides the base.
|
|
107
|
+
*/
|
|
108
|
+
filesBase?: string | false;
|
|
102
109
|
/** Override the default base URL, `https://www.runapps.ai` (the
|
|
103
110
|
* platform: personal keys and app tokens are both accepted there). */
|
|
104
111
|
baseURL?: string;
|
|
@@ -260,7 +267,7 @@ export class RunApps {
|
|
|
260
267
|
// `project` also scopes the file URLs (/v1/p/<project>/files/...),
|
|
261
268
|
// so two apps never issue byte-identical file requests. Omitted →
|
|
262
269
|
// legacy unscoped /v1/files/... paths.
|
|
263
|
-
this.files = new FilesService(transport, options.project, this.events);
|
|
270
|
+
this.files = new FilesService(transport, options.project, this.events, options.filesBase);
|
|
264
271
|
this.embeddings = new EmbeddingsService(transport, this.events);
|
|
265
272
|
this.realtime = new RealtimeService(transport, this.events);
|
|
266
273
|
|
|
@@ -274,7 +281,7 @@ export class RunApps {
|
|
|
274
281
|
{
|
|
275
282
|
// Its own file service, without the event bus: sync traffic
|
|
276
283
|
// must not spin the badge every minute.
|
|
277
|
-
remote: new FilesRemote(new FilesService(transport, options.project)),
|
|
284
|
+
remote: new FilesRemote(new FilesService(transport, options.project, undefined, options.filesBase)),
|
|
278
285
|
events: this.events,
|
|
279
286
|
userId: () => auth.ownerId(),
|
|
280
287
|
onAuthChange: (cb) => auth.onTokenChange(() => cb()),
|
package/src/files.ts
CHANGED
|
@@ -48,6 +48,14 @@ export interface FileRead {
|
|
|
48
48
|
etag?: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
export interface SignOptions {
|
|
52
|
+
/** How long the link stays valid, in seconds. Default 3600, at most 7 days. */
|
|
53
|
+
expiresIn?: number;
|
|
54
|
+
/** When true the link downloads instead of displaying inline. */
|
|
55
|
+
download?: boolean;
|
|
56
|
+
signal?: AbortSignal;
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
export interface ListOptions {
|
|
52
60
|
prefix?: string;
|
|
53
61
|
cursor?: string;
|
|
@@ -118,7 +126,11 @@ export class FilesService {
|
|
|
118
126
|
* rejects a scope that disagrees with it, so this is a correctness
|
|
119
127
|
* measure, not a permission one.
|
|
120
128
|
*/
|
|
121
|
-
private readonly
|
|
129
|
+
private readonly legacyBase: string;
|
|
130
|
+
private readonly project: string | undefined;
|
|
131
|
+
private readonly filesBase: string | false | undefined;
|
|
132
|
+
private baseCache: { fp: string; base: string } | null = null;
|
|
133
|
+
private basePending: Promise<string> | null = null;
|
|
122
134
|
|
|
123
135
|
constructor(
|
|
124
136
|
private readonly transport: Transport,
|
|
@@ -127,12 +139,51 @@ export class FilesService {
|
|
|
127
139
|
* badge can show it in flight; the sync engine's own file traffic
|
|
128
140
|
* uses a service without one. */
|
|
129
141
|
private readonly events?: SDKEvents,
|
|
142
|
+
/** `false`: stay on the classic /v1 paths; a string: use this as the
|
|
143
|
+
* per-user base instead of asking the gateway. */
|
|
144
|
+
filesBase?: string | false,
|
|
130
145
|
) {
|
|
131
|
-
this.
|
|
146
|
+
this.project = project;
|
|
147
|
+
this.filesBase = filesBase;
|
|
148
|
+
this.legacyBase = project
|
|
132
149
|
? "/v1/p/" + encodeURIComponent(project) + "/files"
|
|
133
150
|
: "/v1/files";
|
|
134
151
|
}
|
|
135
152
|
|
|
153
|
+
/**
|
|
154
|
+
* The URL prefix for file calls, resolved once per signed-in user.
|
|
155
|
+
*
|
|
156
|
+
* Newer gateways answer `GET /v1/files-base` with a per-user base on
|
|
157
|
+
* the files host — `https://files.runapps.ai/u/<hash>` — so every
|
|
158
|
+
* file URL is unique to its user as well as to its app, and file
|
|
159
|
+
* traffic leaves the main site. The `/files` or `/p/<app>/files` tail
|
|
160
|
+
* is appended here. A gateway without that endpoint, or a failure to
|
|
161
|
+
* reach it, falls back to the classic path on the main base. The
|
|
162
|
+
* result is cached against a fingerprint of the token: a different
|
|
163
|
+
* user signing in gets their own base.
|
|
164
|
+
*/
|
|
165
|
+
private async base(): Promise<string> {
|
|
166
|
+
if (this.filesBase === false) return this.legacyBase;
|
|
167
|
+
const tail = this.project ? "/p/" + encodeURIComponent(this.project) + "/files" : "/files";
|
|
168
|
+
if (typeof this.filesBase === "string") return this.filesBase.replace(/\/+$/, "") + tail;
|
|
169
|
+
const fp = await this.transport.tokenFingerprint();
|
|
170
|
+
if (this.baseCache && this.baseCache.fp === fp) return this.baseCache.base;
|
|
171
|
+
if (!this.basePending) {
|
|
172
|
+
this.basePending = (async () => {
|
|
173
|
+
let base = this.legacyBase;
|
|
174
|
+
try {
|
|
175
|
+
const r = await this.transport.getJSON<{ base?: string }>("/v1/files-base");
|
|
176
|
+
if (r && typeof r.base === "string" && /^https?:\/\//i.test(r.base)) base = r.base.replace(/\/+$/, "") + tail;
|
|
177
|
+
} catch {
|
|
178
|
+
// Older gateway or a transient failure: the classic path still works.
|
|
179
|
+
}
|
|
180
|
+
this.baseCache = { fp, base };
|
|
181
|
+
return base;
|
|
182
|
+
})().finally(() => { this.basePending = null; });
|
|
183
|
+
}
|
|
184
|
+
return this.basePending;
|
|
185
|
+
}
|
|
186
|
+
|
|
136
187
|
/** Run one file call, with badge events when the service has a bus. */
|
|
137
188
|
private run<T>(op: string, fn: () => Promise<T>): Promise<T> {
|
|
138
189
|
return this.events ? wrapEvents(this.events, { model: op, capability: "files" }, fn) : fn();
|
|
@@ -154,7 +205,7 @@ export class FilesService {
|
|
|
154
205
|
const headers: Record<string, string> = {};
|
|
155
206
|
if (opts?.ifNoneMatch) headers["If-None-Match"] = "*";
|
|
156
207
|
if (opts?.ifMatch) headers["If-Match"] = `"${cleanETag(opts.ifMatch)}"`;
|
|
157
|
-
return this.run("files.put", () => this.transport.putBytes<FileObject>(pathToURL(this.base, path), body, {
|
|
208
|
+
return this.run("files.put", async () => this.transport.putBytes<FileObject>(pathToURL(await this.base(), path), body, {
|
|
158
209
|
contentType: opts?.contentType,
|
|
159
210
|
headers: Object.keys(headers).length ? headers : undefined,
|
|
160
211
|
signal: opts?.signal,
|
|
@@ -193,7 +244,7 @@ export class FilesService {
|
|
|
193
244
|
}
|
|
194
245
|
|
|
195
246
|
private async readRaw(path: string, init?: { signal?: AbortSignal; ifNoneMatch?: string }): Promise<FileRead> {
|
|
196
|
-
const { data, contentType, etag, notModified } = await this.transport.getRaw(pathToURL(this.base, path), init);
|
|
247
|
+
const { data, contentType, etag, notModified } = await this.transport.getRaw(pathToURL(await this.base(), path), init);
|
|
197
248
|
return {
|
|
198
249
|
blob: new Blob([new Uint8Array(data)], { type: contentType || "application/octet-stream" }),
|
|
199
250
|
contentType,
|
|
@@ -227,7 +278,7 @@ export class FilesService {
|
|
|
227
278
|
|
|
228
279
|
/** Stat: HEAD-only object metadata. */
|
|
229
280
|
async stat(path: string, init?: { signal?: AbortSignal }): Promise<FileObject> {
|
|
230
|
-
const { status, headers } = await this.run("files.stat", () => this.transport.head(pathToURL(this.base, path), init));
|
|
281
|
+
const { status, headers } = await this.run("files.stat", async () => this.transport.head(pathToURL(await this.base(), path), init));
|
|
231
282
|
if (status === 404) {
|
|
232
283
|
throw Object.assign(new Error("not found"), { status: 404 });
|
|
233
284
|
}
|
|
@@ -246,13 +297,13 @@ export class FilesService {
|
|
|
246
297
|
|
|
247
298
|
/** Returns true iff the path resolves to an existing object. */
|
|
248
299
|
async exists(path: string, init?: { signal?: AbortSignal }): Promise<boolean> {
|
|
249
|
-
const { status } = await this.run("files.exists", () => this.transport.head(pathToURL(this.base, path), init));
|
|
300
|
+
const { status } = await this.run("files.exists", async () => this.transport.head(pathToURL(await this.base(), path), init));
|
|
250
301
|
return status >= 200 && status < 400;
|
|
251
302
|
}
|
|
252
303
|
|
|
253
304
|
/** Delete the object at `path`. Idempotent. */
|
|
254
305
|
async del(path: string, init?: { signal?: AbortSignal }): Promise<void> {
|
|
255
|
-
await this.run("files.del", () => this.transport.deletePath<{ ok: boolean }>(pathToURL(this.base, path), init));
|
|
306
|
+
await this.run("files.del", async () => this.transport.deletePath<{ ok: boolean }>(pathToURL(await this.base(), path), init));
|
|
256
307
|
}
|
|
257
308
|
|
|
258
309
|
/** List objects. Pass an empty / omitted prefix for the root. */
|
|
@@ -263,8 +314,8 @@ export class FilesService {
|
|
|
263
314
|
if (opts?.limit) params.set("limit", String(opts.limit));
|
|
264
315
|
if (opts?.glob) params.set("glob", opts.glob);
|
|
265
316
|
const qs = params.toString();
|
|
266
|
-
return this.run("files.list", () => this.transport.getJSON<FileListResult>(
|
|
267
|
-
this.base + (qs ? "?" + qs : ""),
|
|
317
|
+
return this.run("files.list", async () => this.transport.getJSON<FileListResult>(
|
|
318
|
+
(await this.base()) + (qs ? "?" + qs : ""),
|
|
268
319
|
opts?.signal ? { signal: opts.signal } : undefined,
|
|
269
320
|
));
|
|
270
321
|
}
|
|
@@ -283,8 +334,8 @@ export class FilesService {
|
|
|
283
334
|
opts: { prefix?: string; glob?: string },
|
|
284
335
|
init?: { signal?: AbortSignal },
|
|
285
336
|
): Promise<{ deleted: number }> {
|
|
286
|
-
return this.run("files.deleteMany", () => this.transport.postJSON<{ deleted: number }>(
|
|
287
|
-
this.base + "/delete",
|
|
337
|
+
return this.run("files.deleteMany", async () => this.transport.postJSON<{ deleted: number }>(
|
|
338
|
+
(await this.base()) + "/delete",
|
|
288
339
|
{ prefix: opts.prefix ?? "", glob: opts.glob ?? "" },
|
|
289
340
|
init,
|
|
290
341
|
));
|
|
@@ -292,12 +343,43 @@ export class FilesService {
|
|
|
292
343
|
|
|
293
344
|
/** Atomic rename (copy + delete server-side). */
|
|
294
345
|
async move(from: string, to: string, init?: { signal?: AbortSignal }): Promise<FileObject> {
|
|
295
|
-
return this.run("files.move", () => this.transport.postJSON<FileObject>(this.base + "/move", { from, to }, init));
|
|
346
|
+
return this.run("files.move", async () => this.transport.postJSON<FileObject>((await this.base()) + "/move", { from, to }, init));
|
|
296
347
|
}
|
|
297
348
|
|
|
298
349
|
/** Server-side copy. */
|
|
299
350
|
async copy(from: string, to: string, init?: { signal?: AbortSignal }): Promise<FileObject> {
|
|
300
|
-
return this.run("files.copy", () => this.transport.postJSON<FileObject>(this.base + "/copy", { from, to }, init));
|
|
351
|
+
return this.run("files.copy", async () => this.transport.postJSON<FileObject>((await this.base()) + "/copy", { from, to }, init));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* A time-limited link to a private file that needs no token: put it in
|
|
356
|
+
* `<img src>`, `<video src>` or `<a href download>`. The link is for
|
|
357
|
+
* this user's copy of the file in this app; it expires after
|
|
358
|
+
* `expiresIn` seconds (default one hour, at most seven days) and is
|
|
359
|
+
* never cached, so it always shows the current bytes. For a permanent
|
|
360
|
+
* public address use the FileObject's `url` instead.
|
|
361
|
+
*/
|
|
362
|
+
async url(path: string, opts?: SignOptions): Promise<string> {
|
|
363
|
+
const urls = await this.urls([path], opts);
|
|
364
|
+
const u = urls[path];
|
|
365
|
+
if (!u) throw new Error("RunApps: no signed URL returned for " + path);
|
|
366
|
+
return u;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** Signed links for several paths at once (up to 200): `{ path: url }`. */
|
|
370
|
+
async urls(paths: string[], opts?: SignOptions): Promise<Record<string, string>> {
|
|
371
|
+
const body: { paths: string[]; expires_in?: number } = { paths };
|
|
372
|
+
if (opts?.expiresIn) body.expires_in = Math.floor(opts.expiresIn);
|
|
373
|
+
const r = await this.run("files.sign", async () => this.transport.postJSON<{ urls: Record<string, string> }>(
|
|
374
|
+
(await this.base()) + "/sign",
|
|
375
|
+
body,
|
|
376
|
+
opts?.signal ? { signal: opts.signal } : undefined,
|
|
377
|
+
));
|
|
378
|
+
const out: Record<string, string> = {};
|
|
379
|
+
for (const [p, u] of Object.entries(r.urls || {})) {
|
|
380
|
+
out[p] = opts?.download ? u + (u.includes("?") ? "&" : "?") + "download=1" : u;
|
|
381
|
+
}
|
|
382
|
+
return out;
|
|
301
383
|
}
|
|
302
384
|
|
|
303
385
|
/**
|
|
@@ -310,8 +392,8 @@ export class FilesService {
|
|
|
310
392
|
srcURL: string,
|
|
311
393
|
opts?: PutFromURLOptions,
|
|
312
394
|
): Promise<FileObject> {
|
|
313
|
-
return this.run("files.putFromURL", () => this.transport.postJSON<FileObject>(
|
|
314
|
-
this.base + "/put-url",
|
|
395
|
+
return this.run("files.putFromURL", async () => this.transport.postJSON<FileObject>(
|
|
396
|
+
(await this.base()) + "/put-url",
|
|
315
397
|
{
|
|
316
398
|
path,
|
|
317
399
|
src_url: srcURL,
|
|
@@ -347,7 +429,7 @@ export class FilesService {
|
|
|
347
429
|
const chunkSize = 30;
|
|
348
430
|
if (ops.length <= chunkSize) {
|
|
349
431
|
const resp = await this.transport.postJSON<{ results: BatchResult[] }>(
|
|
350
|
-
this.base + "/batch",
|
|
432
|
+
(await this.base()) + "/batch",
|
|
351
433
|
{ ops },
|
|
352
434
|
init,
|
|
353
435
|
);
|
|
@@ -357,7 +439,7 @@ export class FilesService {
|
|
|
357
439
|
for (let i = 0; i < ops.length; i += chunkSize) {
|
|
358
440
|
const chunk = ops.slice(i, i + chunkSize);
|
|
359
441
|
const resp = await this.transport.postJSON<{ results: BatchResult[] }>(
|
|
360
|
-
this.base + "/batch",
|
|
442
|
+
(await this.base()) + "/batch",
|
|
361
443
|
{ ops: chunk },
|
|
362
444
|
init,
|
|
363
445
|
);
|
package/src/index.ts
CHANGED
package/src/transport.ts
CHANGED
|
@@ -62,6 +62,23 @@ export class Transport {
|
|
|
62
62
|
this.fetchImpl = opts.fetchImpl ?? fetch.bind(globalThis);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/** Absolute URLs pass through; paths are joined to the base. The files
|
|
66
|
+
* service uses this to send file calls to the files host. */
|
|
67
|
+
private resolve(path: string): string {
|
|
68
|
+
return /^https?:\/\//i.test(path) ? path : this.baseURL + path;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** A short, non-secret fingerprint of the current token, so a service
|
|
72
|
+
* can notice that the signed-in user changed and drop per-user state
|
|
73
|
+
* (the files base is derived from the user). */
|
|
74
|
+
async tokenFingerprint(): Promise<string> {
|
|
75
|
+
const t = await this.resolveToken();
|
|
76
|
+
if (!t) return "";
|
|
77
|
+
let h = 0;
|
|
78
|
+
for (let i = 0; i < t.length; i++) h = (h * 31 + t.charCodeAt(i)) | 0;
|
|
79
|
+
return (h >>> 0).toString(36) + ":" + t.length;
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
/** Resolve the bearer token for the next request. */
|
|
66
83
|
private async resolveToken(): Promise<string> {
|
|
67
84
|
if (this.apiKeyResolver) return await this.apiKeyResolver();
|
|
@@ -85,7 +102,7 @@ export class Transport {
|
|
|
85
102
|
path: string,
|
|
86
103
|
build: () => Promise<RequestInit>,
|
|
87
104
|
): Promise<Response> {
|
|
88
|
-
const url = this.
|
|
105
|
+
const url = this.resolve(path);
|
|
89
106
|
let resp = await this.fetchImpl(url, await this.buildInit(build));
|
|
90
107
|
if (resp.status !== 401 || !this.onUnauthorized) return resp;
|
|
91
108
|
try {
|
|
@@ -157,7 +174,7 @@ export class Transport {
|
|
|
157
174
|
path: string,
|
|
158
175
|
init?: { signal?: AbortSignal },
|
|
159
176
|
): Promise<T> {
|
|
160
|
-
const resp = await this.fetchImpl(this.
|
|
177
|
+
const resp = await this.fetchImpl(this.resolve(path), {
|
|
161
178
|
method: "GET",
|
|
162
179
|
cache: "no-store",
|
|
163
180
|
...(init?.signal ? { signal: init.signal } : {}),
|