totemlayer 0.1.21 → 0.1.24

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.
@@ -0,0 +1,298 @@
1
+ import { createLocalInspector, InspectionError } from "./inspector.js";
2
+ import type { ActionProposal, AssistantActionCheck, AssistantActionCheckList, AssistantActionReceiptResult, AssistantCheckOptions } from "./action-types.js";
3
+ import type { MissionCoordinationUpdate, MissionSessionReport, Agent, AssistantContext, AssistantMissionPermissions, Attachment, Chat, ChatCommand, ChatDetail, ChatEvent, ChatRun, RuntimeHeartbeat, Conversation, ListenOptions, ListMessages, ListMissions, ListTasks, Message, MessageContent, MessageHandler, Metadata, MissionArtifact, MissionDetail, MissionEvent, MissionEventInput, MissionSummary, MissionWorkItem, Page, Pagination, RequestOptions, RepoClaim, RepoClaimState, RepositoryCoordination, SearchAgents, SendMessage, Subscription, Task, TaskState, TotemOptions, WriteOptions } from "./types.js";
4
+ export * from "./types.js";
5
+ export * from "./errors.js";
6
+ export * from "./actions.js";
7
+ export { idempotencyKey } from "./transport.js";
8
+ export declare class Totem {
9
+ #private;
10
+ constructor(options: TotemOptions);
11
+ static connect(options: TotemOptions): Promise<ConnectedAgent>;
12
+ connect(): Promise<ConnectedAgent>;
13
+ agent(options?: RequestOptions): Promise<Agent>;
14
+ assistant: {
15
+ context: (options?: RequestOptions) => Promise<AssistantContext>;
16
+ checks: {
17
+ create: (missionId: string, input: {
18
+ workItemId: string;
19
+ leaseToken: string;
20
+ action: ActionProposal;
21
+ }, options: AssistantCheckOptions) => Promise<AssistantActionCheck>;
22
+ list: (missionId: string, workItemId: string, options?: RequestOptions) => Promise<AssistantActionCheckList>;
23
+ recordReceipt: (missionId: string, suiteId: string, input: {
24
+ workItemId: string;
25
+ }, options?: RequestOptions) => Promise<AssistantActionReceiptResult>;
26
+ };
27
+ permissions: (missionId: string, options?: RequestOptions) => Promise<AssistantMissionPermissions>;
28
+ };
29
+ resolve(address: string, options?: RequestOptions): Promise<Agent>;
30
+ agents: {
31
+ search: (query?: SearchAgents, options?: RequestOptions) => Promise<Page<Agent>>;
32
+ iterate: (query?: SearchAgents, options?: RequestOptions) => AsyncIterable<Agent>;
33
+ };
34
+ attachments: {
35
+ upload: (name: string, mediaType: string, bytes: Uint8Array, options?: RequestOptions) => Promise<Attachment>;
36
+ download: (id: string, options?: RequestOptions) => Promise<{
37
+ bytes: Uint8Array;
38
+ mediaType: string;
39
+ name: string;
40
+ sha256: string | null;
41
+ }>;
42
+ };
43
+ messages: {
44
+ send: (input: SendMessage, options?: WriteOptions) => Promise<Message>;
45
+ list: (query?: ListMessages, options?: RequestOptions) => Promise<Page<Message>>;
46
+ iterate: (query?: ListMessages, options?: RequestOptions) => AsyncIterable<Message>;
47
+ get: (id: string, options?: RequestOptions) => Promise<Message>;
48
+ reply: (id: string, text: string, options?: WriteOptions & {
49
+ metadata?: Metadata;
50
+ attachments?: string[];
51
+ }) => Promise<Message>;
52
+ replyContent: (id: string, content: MessageContent, options?: WriteOptions) => Promise<Message>;
53
+ ack: (id: string, options?: RequestOptions) => Promise<Message>;
54
+ };
55
+ send(input: SendMessage, options?: WriteOptions): Promise<Message>;
56
+ send(to: string, text: string, options?: WriteOptions): Promise<Message>;
57
+ conversations: {
58
+ create: (input: {
59
+ with: string;
60
+ metadata?: Metadata;
61
+ }, options?: RequestOptions) => Promise<ConversationHandle>;
62
+ list: (query?: Pagination, options?: RequestOptions) => Promise<Page<Conversation>>;
63
+ get: (id: string, options?: RequestOptions) => Promise<Conversation>;
64
+ messages: (id: string, query?: Pagination, options?: RequestOptions) => Promise<Page<Message>>;
65
+ };
66
+ startConversation(input: {
67
+ with: string;
68
+ metadata?: Metadata;
69
+ }, options?: RequestOptions): Promise<ConversationHandle>;
70
+ missions: {
71
+ list: (options?: RequestOptions) => Promise<MissionSummary[]>;
72
+ listPage: (query?: ListMissions, options?: RequestOptions) => Promise<Page<MissionSummary>>;
73
+ iterate: (query?: ListMissions, options?: RequestOptions) => AsyncIterable<MissionSummary>;
74
+ get: (id: string, options?: RequestOptions) => Promise<MissionDetail>;
75
+ coordination: (id: string, version?: string, options?: RequestOptions) => Promise<MissionCoordinationUpdate>;
76
+ sessions: {
77
+ report: (id: string, input: MissionSessionReport, options?: RequestOptions) => Promise<{
78
+ sessionId: string;
79
+ sequence: number;
80
+ }>;
81
+ };
82
+ workItems: (id: string, options?: RequestOptions) => Promise<MissionWorkItem[]>;
83
+ /** Empty data can still have a nextCursor: readiness is checked after scanning candidates. */
84
+ workItemsPage: (id: string, query?: Pagination, options?: RequestOptions) => Promise<Page<MissionWorkItem>>;
85
+ iterateWorkItems: (id: string, query?: Pagination, options?: RequestOptions) => AsyncIterable<MissionWorkItem>;
86
+ assign: (id: string, input: {
87
+ ownerMemberId: string;
88
+ objective: string;
89
+ requiredOutput: string;
90
+ dependsOnIds?: string[];
91
+ parentWorkItemId: string;
92
+ metadata?: Metadata;
93
+ }, options?: WriteOptions) => Promise<MissionWorkItem>;
94
+ claim: (id: string, workItemId: string, options?: WriteOptions) => Promise<{
95
+ workItem: MissionWorkItem;
96
+ leaseToken: string;
97
+ leaseExpiresAt: string;
98
+ }>;
99
+ renew: (id: string, workItemId: string, leaseToken: string, options?: RequestOptions) => Promise<{
100
+ workItem: MissionWorkItem;
101
+ leaseExpiresAt: string;
102
+ }>;
103
+ complete: (id: string, workItemId: string, input: {
104
+ leaseToken: string;
105
+ result?: Metadata;
106
+ artifact?: Pick<MissionArtifact, "kind" | "title"> & {
107
+ summary?: string;
108
+ uri?: string;
109
+ contentText?: string;
110
+ metadata?: Metadata;
111
+ };
112
+ event?: MissionEventInput;
113
+ }, options?: WriteOptions) => Promise<{
114
+ workItem: MissionWorkItem;
115
+ artifact?: MissionArtifact;
116
+ }>;
117
+ reserveEffect: (id: string, input: {
118
+ workItemId: string;
119
+ action: string;
120
+ resource: string;
121
+ leaseToken: string;
122
+ estimatedCostCents?: number;
123
+ parameters?: Metadata;
124
+ }, options?: WriteOptions) => Promise<{
125
+ id: string;
126
+ state: string;
127
+ action: string;
128
+ resource: string;
129
+ }>;
130
+ listEffects: (id: string, workItemId: string, options?: RequestOptions) => Promise<Array<{
131
+ id: string;
132
+ workItemId: string;
133
+ action: string;
134
+ resource: string;
135
+ state: string;
136
+ estimatedCostCents: number;
137
+ actualCostCents: number | null;
138
+ parameters?: Metadata | null;
139
+ receipt?: Metadata | null;
140
+ externalRef?: string | null;
141
+ createdAt: string;
142
+ updatedAt: string;
143
+ }>>;
144
+ dispatchEffect: (id: string, effectId: string, leaseToken: string, options?: RequestOptions) => Promise<{
145
+ effect: {
146
+ id: string;
147
+ state: string;
148
+ };
149
+ launchPermitted: true;
150
+ }>;
151
+ settleEffect: (id: string, effectId: string, input: {
152
+ state: "succeeded" | "failed" | "uncertain";
153
+ actualCostCents?: number;
154
+ receipt?: Metadata;
155
+ }, options?: RequestOptions) => Promise<{
156
+ id: string;
157
+ state: string;
158
+ }>;
159
+ events: {
160
+ list: (id: string, query?: Pagination, options?: RequestOptions) => Promise<Page<MissionEvent>>;
161
+ iterate: (id: string, query?: Pagination, options?: RequestOptions) => AsyncIterable<MissionEvent>;
162
+ post: (id: string, input: MissionEventInput, options?: WriteOptions) => Promise<MissionEvent>;
163
+ ack: (id: string, eventId: string, options?: RequestOptions) => Promise<MissionEvent>;
164
+ };
165
+ };
166
+ chats: {
167
+ list: (query?: Pagination, options?: RequestOptions) => Promise<Page<Chat>>;
168
+ get: (id: string, options?: RequestOptions & Pagination & {
169
+ before?: string;
170
+ }) => Promise<ChatDetail>;
171
+ /** Publish as the authenticated agent; this never creates a human command. */
172
+ updates: (id: string, text: string, options?: WriteOptions) => Promise<ChatEvent>;
173
+ };
174
+ chatCommands: {
175
+ list: (query?: Pagination, options?: RequestOptions) => Promise<Page<ChatCommand>>;
176
+ claim: (id: string, options?: RequestOptions) => Promise<{
177
+ run: ChatRun;
178
+ leaseToken: string;
179
+ }>;
180
+ renew: (id: string, leaseToken: string, options?: RequestOptions) => Promise<{
181
+ run: ChatRun;
182
+ }>;
183
+ complete: (id: string, input: {
184
+ leaseToken: string;
185
+ text: string;
186
+ }, options?: WriteOptions) => Promise<{
187
+ event: ChatEvent;
188
+ run: ChatRun;
189
+ }>;
190
+ fail: (id: string, input: {
191
+ leaseToken: string;
192
+ error: string;
193
+ }, options?: RequestOptions) => Promise<{
194
+ run: ChatRun;
195
+ }>;
196
+ };
197
+ runtime: {
198
+ start: (input: {
199
+ runId: string;
200
+ provider: string;
201
+ hostKind?: "local" | "hosted";
202
+ }, options?: RequestOptions) => Promise<{
203
+ runId: string;
204
+ state: string;
205
+ ready: boolean;
206
+ }>;
207
+ probe: (runId: string, options?: RequestOptions) => Promise<{
208
+ runId: string;
209
+ challenge: string;
210
+ completed: boolean;
211
+ protocol: string;
212
+ }>;
213
+ replyProbe: (input: {
214
+ runId: string;
215
+ reply: string;
216
+ }, options?: RequestOptions) => Promise<{
217
+ runId: string;
218
+ state: string;
219
+ ready: boolean;
220
+ }>;
221
+ heartbeat: (input?: {
222
+ label?: string;
223
+ runId?: string;
224
+ state?: "starting" | "online" | "offline" | "error";
225
+ errorCode?: string;
226
+ }, options?: RequestOptions) => Promise<RuntimeHeartbeat>;
227
+ };
228
+ tasks: {
229
+ create: (input: SendMessage, options?: WriteOptions) => Promise<Task>;
230
+ get: (id: string, options?: RequestOptions) => Promise<Task>;
231
+ list: (query?: ListTasks, options?: RequestOptions) => Promise<Page<Task>>;
232
+ iterate: (query?: ListTasks, options?: RequestOptions) => AsyncIterable<Task>;
233
+ postUpdate: (id: string, text: string, options?: WriteOptions) => Promise<Message>;
234
+ update: (id: string, input: {
235
+ state: Exclude<TaskState, "submitted" | "canceled">;
236
+ artifacts?: Task["artifacts"];
237
+ expectedVersion?: number;
238
+ }, options?: RequestOptions) => Promise<Task>;
239
+ cancel: (id: string, options?: RequestOptions) => Promise<Task>;
240
+ };
241
+ repositories: {
242
+ getTask: (taskId: string, options?: RequestOptions) => Promise<RepositoryCoordination>;
243
+ claim: (taskId: string, input: {
244
+ branch: string;
245
+ paths: string[];
246
+ expectedVersion?: number;
247
+ }, options?: RequestOptions) => Promise<RepoClaim>;
248
+ update: (taskId: string, input: {
249
+ state: Exclude<RepoClaimState, "planned">;
250
+ headCommit?: string;
251
+ pullRequestUrl?: string;
252
+ expectedVersion: number;
253
+ }, options?: RequestOptions) => Promise<RepoClaim>;
254
+ };
255
+ github: {
256
+ repositories: (options?: RequestOptions) => Promise<Array<{
257
+ repository: string;
258
+ repositoryId: string;
259
+ installationId: string;
260
+ }>>;
261
+ openPullRequest: (taskId: string, input: {
262
+ title: string;
263
+ body?: string;
264
+ }, options?: RequestOptions) => Promise<{
265
+ pullRequestUrl: string;
266
+ claim: RepoClaim;
267
+ }>;
268
+ };
269
+ }
270
+ export declare class ConversationHandle {
271
+ #private;
272
+ readonly id: string;
273
+ readonly conversation: Conversation;
274
+ constructor(totem: Totem, conversation: Conversation, recipient: string);
275
+ send(text: string, options?: WriteOptions): Promise<Message>;
276
+ messages(query?: Pagination, options?: RequestOptions): Promise<Page<Message>>;
277
+ }
278
+ export declare class ConnectedAgent {
279
+ #private;
280
+ readonly identity: Agent;
281
+ readonly address: string;
282
+ readonly client: Totem;
283
+ constructor(client: Totem, identity: Agent);
284
+ get lastError(): Error | undefined;
285
+ send(input: SendMessage, options?: WriteOptions): Promise<Message>;
286
+ send(to: string, text: string, options?: WriteOptions): Promise<Message>;
287
+ startConversation(input: {
288
+ with: string;
289
+ metadata?: Metadata;
290
+ }): Promise<ConversationHandle>;
291
+ on(event: "message", handler: MessageHandler, options?: ListenOptions): Subscription;
292
+ stop(): Promise<void>;
293
+ }
294
+ /** Compatibility name for callers who prefer `new TotemAgent({ address, apiKey })`. */
295
+ export declare class TotemAgent extends Totem {
296
+ }
297
+ export { createLocalInspector, InspectionError };
298
+ export type { LocalInspector, LocalInspectorOptions, InspectionOptions, InspectionReceipt, InspectionKind, } from "./inspector.js";
package/bin/sdk/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { TotemError } from "./errors.js";
2
+ import { createLocalInspector, InspectionError } from "./inspector.js";
2
3
  import { idempotencyKey, sleep, Transport } from "./transport.js";
3
4
  import { assertInputFields, assistantCheckOptions, signalOnlyOptions } from "./request-options.js";
4
5
  export * from "./types.js";
@@ -112,6 +113,11 @@ export class Totem {
112
113
  },
113
114
  idempotencyKey: options.idempotencyKey ?? `sdk:reply:${id}`,
114
115
  })).data,
116
+ replyContent: async (id, content, options = {}) => (await this.#transport.request("POST", `/messages/${encodeURIComponent(id)}/reply`, {
117
+ ...options,
118
+ body: { content },
119
+ idempotencyKey: options.idempotencyKey ?? idempotencyKey(),
120
+ })).data,
115
121
  ack: async (id, options) => (await this.#transport.request("POST", `/messages/${encodeURIComponent(id)}/ack`, {
116
122
  ...options,
117
123
  body: {},
@@ -155,8 +161,20 @@ export class Totem {
155
161
  artifacts: result.data.artifacts,
156
162
  events: result.data.events,
157
163
  budget: result.data.budget,
164
+ coordination: result.data.coordination,
158
165
  };
159
166
  },
167
+ coordination: async (id, version, options) => (await this.#transport.request("GET", `/missions/${encodeURIComponent(id)}/coordination`, {
168
+ ...options,
169
+ query: { version },
170
+ })).data,
171
+ sessions: {
172
+ report: async (id, input, options) => (await this.#transport.request("POST", `/missions/${encodeURIComponent(id)}/sessions`, {
173
+ ...options,
174
+ body: input,
175
+ retrySafe: true,
176
+ })).data,
177
+ },
160
178
  workItems: async (id, options) => (await this.#transport.request("GET", `/missions/${encodeURIComponent(id)}/work-items`, options)).data.workItems,
161
179
  /** Empty data can still have a nextCursor: readiness is checked after scanning candidates. */
162
180
  workItemsPage: async (id, query = {}, options) => {
@@ -223,6 +241,9 @@ export class Totem {
223
241
  fail: async (id, input, options) => (await this.#transport.request("POST", `/chat-commands/${encodeURIComponent(id)}/fail`, { ...options, body: input, retrySafe: true })).data,
224
242
  };
225
243
  runtime = {
244
+ start: async (input, options) => (await this.#transport.request("POST", "/runtime/start", { ...options, body: input, retrySafe: true })).data,
245
+ probe: async (runId, options) => (await this.#transport.request("GET", "/runtime/probe", { ...options, query: { runId } })).data,
246
+ replyProbe: async (input, options) => (await this.#transport.request("POST", "/runtime/probe", { ...options, body: input, retrySafe: true })).data,
226
247
  heartbeat: async (input = {}, options) => (await this.#transport.request("POST", "/runtime/heartbeat", {
227
248
  ...options,
228
249
  body: input,
@@ -317,6 +338,8 @@ export class ConnectedAgent {
317
338
  if (!Number.isFinite(interval) || interval < 10)
318
339
  throw new TotemError("pollIntervalMs must be at least 10.", { code: "INVALID_CONFIG" });
319
340
  const controller = new AbortController();
341
+ const inspector = options.inspector ?? createLocalInspector();
342
+ const blocked = new Set();
320
343
  const report = (cause) => {
321
344
  this.#lastError = cause instanceof Error ? cause : new Error(String(cause));
322
345
  try {
@@ -332,22 +355,42 @@ export class ConnectedAgent {
332
355
  for await (const message of this.client.messages.iterate({ direction: "inbound", unread: true, limit: 100 }, { signal: controller.signal })) {
333
356
  if (controller.signal.aborted)
334
357
  break;
335
- const incoming = {
336
- ...message,
337
- text: message.content.type === "text"
338
- ? message.content.text
339
- : JSON.stringify(message.content.data),
340
- reply: (text, writeOptions = {}) => this.client.messages.reply(message.id, text, {
341
- ...writeOptions,
342
- idempotencyKey: writeOptions.idempotencyKey ?? `reply:${message.id}:0`,
343
- }),
344
- ack: () => this.client.messages.ack(message.id),
345
- };
358
+ if (blocked.has(message.id))
359
+ continue;
346
360
  try {
361
+ if (message.content.type === "encrypted")
362
+ throw new TotemError("Use E2eeTotem and pinned endpoint keys to process encrypted messages.", { code: "E2EE_CLIENT_REQUIRED" });
363
+ await inspector.assertAllowed("input", { content: message.content, metadata: message.metadata ?? {} }, { signal: controller.signal });
364
+ const files = message.attachments ?? [];
365
+ const ids = new Set(files.map((file) => file.id));
366
+ if (message.content.type === "text" &&
367
+ message.content.attachments?.some((id) => !ids.has(id)))
368
+ throw new InspectionError("INSPECTION_UNSUPPORTED_FILE");
369
+ for (const file of files) {
370
+ const downloaded = await this.client.attachments.download(file.id, {
371
+ signal: controller.signal,
372
+ });
373
+ await inspector.inspectFile(file.name, file.mediaType, downloaded.bytes, {
374
+ signal: controller.signal,
375
+ });
376
+ }
377
+ const incoming = {
378
+ ...message,
379
+ text: message.content.type === "text"
380
+ ? message.content.text
381
+ : JSON.stringify(message.content.data),
382
+ reply: (text, writeOptions = {}) => inspector.runAction({ id: message.id, text }, (input) => this.client.messages.reply(input.id, input.text, {
383
+ ...writeOptions,
384
+ idempotencyKey: writeOptions.idempotencyKey ?? `reply:${message.id}:0`,
385
+ }), { signal: controller.signal }),
386
+ ack: () => this.client.messages.ack(message.id),
387
+ };
347
388
  await handler(incoming);
348
389
  await incoming.ack();
349
390
  }
350
391
  catch (error) {
392
+ if (error instanceof InspectionError && error.code !== "INSPECTION_UNAVAILABLE")
393
+ blocked.add(message.id);
351
394
  report(error);
352
395
  }
353
396
  }
@@ -385,3 +428,4 @@ export class ConnectedAgent {
385
428
  /** Compatibility name for callers who prefer `new TotemAgent({ address, apiKey })`. */
386
429
  export class TotemAgent extends Totem {
387
430
  }
431
+ export { createLocalInspector, InspectionError };
@@ -0,0 +1,40 @@
1
+ /** Customer-side screening. A passing inspection is never an authorization grant. */
2
+ export type InspectionKind = "input" | "tool-result" | "output" | "action" | "file";
3
+ export type InspectionCode = "INSPECTION_BLOCKED" | "INSPECTION_UNAVAILABLE" | "INSPECTION_LIMIT" | "INSPECTION_UNSUPPORTED_FILE";
4
+ export declare class InspectionError extends Error {
5
+ readonly code: InspectionCode;
6
+ readonly status = 422;
7
+ constructor(code: InspectionCode);
8
+ }
9
+ export interface InspectionOptions {
10
+ /** Trusted original user intent; never replace this with a peer's instructions. */
11
+ task?: string;
12
+ signal?: AbortSignal;
13
+ }
14
+ export interface InspectionReceipt {
15
+ version: 1;
16
+ policy: "totem-local-v1";
17
+ kind: InspectionKind;
18
+ mode: "rules" | "rules+classifier";
19
+ /** SHA-256 of the entire kind, task, and value actually screened. No plaintext. */
20
+ digest: string;
21
+ }
22
+ export interface LocalInspectorOptions {
23
+ maxBytes?: number;
24
+ classifier?: {
25
+ /** Exact loopback OpenAI-compatible chat endpoint. Redirects are prohibited. */
26
+ endpoint: string;
27
+ model: string;
28
+ timeoutMs?: number;
29
+ };
30
+ /** Customer-controlled transport, primarily for isolated tests. */
31
+ fetch?: typeof globalThis.fetch;
32
+ }
33
+ export interface LocalInspector {
34
+ readonly mode: InspectionReceipt["mode"];
35
+ assertAllowed(kind: InspectionKind, value: unknown, options?: InspectionOptions): Promise<InspectionReceipt>;
36
+ inspectFile(name: string, mediaType: string, bytes: Uint8Array, options?: InspectionOptions): Promise<InspectionReceipt>;
37
+ /** Execute only the immutable argument snapshot that passed inspection. */
38
+ runAction<T, R>(value: T, operation: (inspected: T) => Promise<R>, options?: InspectionOptions): Promise<R>;
39
+ }
40
+ export declare function createLocalInspector(options?: LocalInspectorOptions): LocalInspector;
@@ -0,0 +1,13 @@
1
+ import type { RequestOptions } from "./types.js";
2
+ export declare function requireActionChecksKey(apiKey: string): string;
3
+ export declare function assistantCheckOptions(options: RequestOptions & {
4
+ actionChecksApiKey: string;
5
+ }): {
6
+ headers: {
7
+ "X-Totem-Action-Key": string;
8
+ };
9
+ signal?: AbortSignal;
10
+ };
11
+ export declare function assertInputFields(input: object, allowed: string[]): void;
12
+ /** These APIs derive caller identity from credentials, never from caller options. */
13
+ export declare function signalOnlyOptions(options?: RequestOptions): RequestOptions;
@@ -0,0 +1,24 @@
1
+ import type { RequestOptions, TotemOptions } from "./types.js";
2
+ export declare function idempotencyKey(): string;
3
+ export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
4
+ export declare class Transport {
5
+ #private;
6
+ constructor(options: TotemOptions, api?: {
7
+ basePath: "/api/action-checks";
8
+ responseEnvelope: "object";
9
+ } | undefined);
10
+ request<T>(method: "GET" | "POST" | "PATCH", path: string, options?: RequestOptions & {
11
+ body?: unknown;
12
+ query?: object;
13
+ idempotencyKey?: string;
14
+ retrySafe?: boolean;
15
+ binaryBody?: Uint8Array;
16
+ headers?: Record<string, string>;
17
+ }): Promise<T>;
18
+ download(path: string, options?: RequestOptions): Promise<{
19
+ bytes: Uint8Array;
20
+ mediaType: string;
21
+ name: string;
22
+ sha256: string | null;
23
+ }>;
24
+ }