fauna-api 0.0.0-stage → 1.0.676
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/brands.d.ts +2 -0
- package/dist/brands.js +2 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +121 -0
- package/dist/src/ant/chat.d.ts +130 -0
- package/dist/src/ant/chat.js +467 -0
- package/dist/src/ant/format.d.ts +40 -0
- package/dist/src/ant/format.js +143 -0
- package/dist/src/ant/graph.d.ts +130 -0
- package/dist/src/ant/graph.js +449 -0
- package/dist/src/ant/index.d.ts +16 -0
- package/dist/src/ant/index.js +61 -0
- package/dist/src/ant/persona.d.ts +151 -0
- package/dist/src/ant/persona.js +136 -0
- package/dist/src/ant/timeline.d.ts +283 -0
- package/dist/src/ant/timeline.js +1025 -0
- package/dist/src/authentification.d.ts +45 -0
- package/dist/src/authentification.js +194 -0
- package/dist/src/billing.d.ts +135 -0
- package/dist/src/billing.js +128 -0
- package/dist/src/calendar.d.ts +83 -0
- package/dist/src/calendar.js +133 -0
- package/dist/src/chats.d.ts +113 -0
- package/dist/src/chats.js +100 -0
- package/dist/src/cicada/contacts.d.ts +31 -0
- package/dist/src/cicada/contacts.js +28 -0
- package/dist/src/cicada/conversations.d.ts +73 -0
- package/dist/src/cicada/conversations.js +236 -0
- package/dist/src/cicada/inboxes.d.ts +48 -0
- package/dist/src/cicada/inboxes.js +82 -0
- package/dist/src/cicada/index.d.ts +16 -0
- package/dist/src/cicada/index.js +61 -0
- package/dist/src/cicada/phone.d.ts +48 -0
- package/dist/src/cicada/phone.js +306 -0
- package/dist/src/drive.d.ts +80 -0
- package/dist/src/drive.js +472 -0
- package/dist/src/extensions/index.d.ts +4 -0
- package/dist/src/extensions/index.js +5 -0
- package/dist/src/extensions/web/index.d.ts +6 -0
- package/dist/src/extensions/web/index.js +7 -0
- package/dist/src/extensions/web/session.d.ts +106 -0
- package/dist/src/extensions/web/session.js +469 -0
- package/dist/src/extensions/web/tools.d.ts +13 -0
- package/dist/src/extensions/web/tools.js +72 -0
- package/dist/src/friends.d.ts +39 -0
- package/dist/src/friends.js +119 -0
- package/dist/src/groups.d.ts +82 -0
- package/dist/src/groups.js +269 -0
- package/dist/src/inbox.d.ts +11 -0
- package/dist/src/inbox.js +35 -0
- package/dist/src/integrations.d.ts +52 -0
- package/dist/src/integrations.js +205 -0
- package/dist/src/magpie/explorer.d.ts +14 -0
- package/dist/src/magpie/explorer.js +36 -0
- package/dist/src/magpie/index.d.ts +16 -0
- package/dist/src/magpie/index.js +61 -0
- package/dist/src/magpie/portfolio.d.ts +52 -0
- package/dist/src/magpie/portfolio.js +179 -0
- package/dist/src/magpie/quotes.d.ts +35 -0
- package/dist/src/magpie/quotes.js +47 -0
- package/dist/src/magpie/room.d.ts +61 -0
- package/dist/src/magpie/room.js +238 -0
- package/dist/src/maps.d.ts +159 -0
- package/dist/src/maps.js +171 -0
- package/dist/src/marmot/browser.d.ts +139 -0
- package/dist/src/marmot/browser.js +389 -0
- package/dist/src/marmot/index.d.ts +20 -0
- package/dist/src/marmot/index.js +65 -0
- package/dist/src/marmot/media.d.ts +56 -0
- package/dist/src/marmot/media.js +265 -0
- package/dist/src/marmot/research.d.ts +337 -0
- package/dist/src/marmot/research.js +1138 -0
- package/dist/src/marmot/scraper.d.ts +59 -0
- package/dist/src/marmot/scraper.js +94 -0
- package/dist/src/marmot/web.d.ts +402 -0
- package/dist/src/marmot/web.js +2586 -0
- package/dist/src/marmot/workspace.d.ts +81 -0
- package/dist/src/marmot/workspace.js +263 -0
- package/dist/src/parrot/agent.d.ts +53 -0
- package/dist/src/parrot/agent.js +93 -0
- package/dist/src/parrot/chat.d.ts +84 -0
- package/dist/src/parrot/chat.js +237 -0
- package/dist/src/parrot/format.d.ts +128 -0
- package/dist/src/parrot/format.js +639 -0
- package/dist/src/parrot/generative.d.ts +261 -0
- package/dist/src/parrot/generative.js +185 -0
- package/dist/src/parrot/index.d.ts +22 -0
- package/dist/src/parrot/index.js +67 -0
- package/dist/src/parrot/room.d.ts +225 -0
- package/dist/src/parrot/room.js +466 -0
- package/dist/src/parrot/routing.d.ts +90 -0
- package/dist/src/parrot/routing.js +78 -0
- package/dist/src/parrot/share.d.ts +126 -0
- package/dist/src/parrot/share.js +261 -0
- package/dist/src/parrot/socket.d.ts +41 -0
- package/dist/src/parrot/socket.js +478 -0
- package/dist/src/payments.d.ts +73 -0
- package/dist/src/payments.js +107 -0
- package/dist/src/private/cards.css +75 -0
- package/dist/src/rooms.d.ts +76 -0
- package/dist/src/rooms.js +168 -0
- package/dist/src/shared/schema.d.ts +24 -0
- package/dist/src/shared/schema.js +1 -0
- package/dist/src/shared/server.d.ts +65 -0
- package/dist/src/shared/server.js +302 -0
- package/dist/src/termite/environment.d.ts +110 -0
- package/dist/src/termite/environment.js +263 -0
- package/dist/src/termite/index.d.ts +14 -0
- package/dist/src/termite/index.js +59 -0
- package/dist/src/termite/os.d.ts +326 -0
- package/dist/src/termite/os.js +572 -0
- package/dist/src/termite/versioning.d.ts +94 -0
- package/dist/src/termite/versioning.js +217 -0
- package/dist/src/tickets.d.ts +43 -0
- package/dist/src/tickets.js +138 -0
- package/dist/src/travel.d.ts +85 -0
- package/dist/src/travel.js +44 -0
- package/dist/src/ui/authentification.d.ts +24 -0
- package/dist/src/ui/authentification.js +177 -0
- package/dist/src/ui/brands.css +11 -0
- package/dist/src/ui/brands.d.ts +7 -0
- package/dist/src/ui/brands.js +14 -0
- package/dist/src/ui/browser.d.ts +74 -0
- package/dist/src/ui/browser.js +470 -0
- package/dist/src/ui/chat.d.ts +183 -0
- package/dist/src/ui/chat.js +2379 -0
- package/dist/src/ui/chatPanel.d.ts +109 -0
- package/dist/src/ui/chatPanel.js +768 -0
- package/dist/src/ui/chatSequence.d.ts +36 -0
- package/dist/src/ui/chatSequence.js +42 -0
- package/dist/src/ui/crown.d.ts +19 -0
- package/dist/src/ui/crown.js +199 -0
- package/dist/src/ui/cursor.d.ts +73 -0
- package/dist/src/ui/cursor.js +175 -0
- package/dist/src/ui/device.d.ts +33 -0
- package/dist/src/ui/device.js +49 -0
- package/dist/src/ui/drive.d.ts +69 -0
- package/dist/src/ui/drive.js +1243 -0
- package/dist/src/ui/generative.d.ts +39 -0
- package/dist/src/ui/generative.js +313 -0
- package/dist/src/ui/hover.d.ts +6 -0
- package/dist/src/ui/hover.js +210 -0
- package/dist/src/ui/index.d.ts +42 -0
- package/dist/src/ui/index.js +87 -0
- package/dist/src/ui/integrations.d.ts +13 -0
- package/dist/src/ui/integrations.js +175 -0
- package/dist/src/ui/maps.d.ts +87 -0
- package/dist/src/ui/maps.js +547 -0
- package/dist/src/ui/roster.d.ts +32 -0
- package/dist/src/ui/roster.js +163 -0
- package/dist/src/ui/talk.d.ts +12 -0
- package/dist/src/ui/talk.js +560 -0
- package/dist/src/ui/tickets.d.ts +13 -0
- package/dist/src/ui/tickets.js +966 -0
- package/dist/src/ui/toast.d.ts +7 -0
- package/dist/src/ui/toast.js +258 -0
- package/dist/src/ui/tokenText.d.ts +18 -0
- package/dist/src/ui/tokenText.js +96 -0
- package/dist/src/ui/tokenized.d.ts +42 -0
- package/dist/src/ui/tokenized.js +622 -0
- package/dist/src/ui/ui.css +4763 -0
- package/dist/src/ui/view.d.ts +23 -0
- package/dist/src/ui/view.js +584 -0
- package/dist/src/view.d.ts +113 -0
- package/dist/src/view.js +386 -0
- package/dist/src/webhooks.d.ts +66 -0
- package/dist/src/webhooks.js +78 -0
- package/dist/ui.d.ts +1 -0
- package/dist/ui.js +1 -0
- package/package.json +89 -6
- package/README.md +0 -3
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { Fauna } from "../index.js";
|
|
2
|
+
import { mimeFromFileName } from "./marmot/media.js";
|
|
3
|
+
export { FaunaFile as File };
|
|
4
|
+
function sendWithProgress(url, headers, body, onProgress) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const xhr = new XMLHttpRequest();
|
|
7
|
+
xhr.open("POST", url);
|
|
8
|
+
for (const [name, value] of Object.entries(headers))
|
|
9
|
+
xhr.setRequestHeader(name, value);
|
|
10
|
+
xhr.upload.onprogress = (event) => {
|
|
11
|
+
if (event.lengthComputable && event.total > 0 && onProgress)
|
|
12
|
+
onProgress(event.loaded / event.total);
|
|
13
|
+
};
|
|
14
|
+
xhr.onload = () => resolve(xhr.status);
|
|
15
|
+
xhr.onerror = () => reject(new Error('Failed to upload file.'));
|
|
16
|
+
xhr.send(body);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
class FaunaFile {
|
|
20
|
+
get name() {
|
|
21
|
+
return this._name;
|
|
22
|
+
}
|
|
23
|
+
get online() {
|
|
24
|
+
return this._online;
|
|
25
|
+
}
|
|
26
|
+
constructor(authorization, name, online, contentType, contentLength, accessDate, createDate, data = undefined) {
|
|
27
|
+
Object.defineProperty(this, "authorization", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: void 0
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(this, "contentType", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
value: void 0
|
|
38
|
+
});
|
|
39
|
+
Object.defineProperty(this, "contentLength", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: void 0
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(this, "accessDate", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
writable: true,
|
|
49
|
+
value: void 0
|
|
50
|
+
});
|
|
51
|
+
Object.defineProperty(this, "createDate", {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
value: void 0
|
|
56
|
+
});
|
|
57
|
+
Object.defineProperty(this, "_name", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
configurable: true,
|
|
60
|
+
writable: true,
|
|
61
|
+
value: void 0
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(this, "_online", {
|
|
64
|
+
enumerable: true,
|
|
65
|
+
configurable: true,
|
|
66
|
+
writable: true,
|
|
67
|
+
value: void 0
|
|
68
|
+
});
|
|
69
|
+
Object.defineProperty(this, "data", {
|
|
70
|
+
enumerable: true,
|
|
71
|
+
configurable: true,
|
|
72
|
+
writable: true,
|
|
73
|
+
value: void 0
|
|
74
|
+
});
|
|
75
|
+
Object.defineProperty(this, "previewData", {
|
|
76
|
+
enumerable: true,
|
|
77
|
+
configurable: true,
|
|
78
|
+
writable: true,
|
|
79
|
+
value: void 0
|
|
80
|
+
});
|
|
81
|
+
this.authorization = authorization;
|
|
82
|
+
this._name = name;
|
|
83
|
+
this._online = online;
|
|
84
|
+
this.contentType = contentType;
|
|
85
|
+
this.contentLength = contentLength;
|
|
86
|
+
this.accessDate = accessDate;
|
|
87
|
+
this.createDate = createDate;
|
|
88
|
+
this.data = data;
|
|
89
|
+
}
|
|
90
|
+
static fromJSON(json, authorization) {
|
|
91
|
+
return new FaunaFile(authorization, json.name ?? "", true, json.contentType ?? "application/octet-stream", Number(json.contentLength ?? 0), new Date(json.accessDate ?? Date.now()), new Date(json.createDate ?? Date.now()));
|
|
92
|
+
}
|
|
93
|
+
async download(revalidate = false, onProgress) {
|
|
94
|
+
if (this.data && !revalidate) {
|
|
95
|
+
return this.data;
|
|
96
|
+
}
|
|
97
|
+
const auth = this.authorization;
|
|
98
|
+
const response = 'repository' in auth
|
|
99
|
+
? await fetch(`${Fauna.Termite.getURL()}/termite/repositories/${auth.repository}/files${auth.path.split('/').filter(Boolean).map((s) => '/' + encodeURIComponent(s)).join('')}?download=1`, {
|
|
100
|
+
method: "GET",
|
|
101
|
+
headers: {
|
|
102
|
+
"Authorization": 'email' in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
|
|
103
|
+
...(auth.group ? { "Group": auth.group } : {}),
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
: await fetch(`${Fauna.getURL()}/file/download`, {
|
|
107
|
+
method: "GET",
|
|
108
|
+
headers: {
|
|
109
|
+
"Authorization": 'email' in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
|
|
110
|
+
...('path' in auth ? {
|
|
111
|
+
"Path": this.contentType === 'application/x-directory' ? auth.path + '/' : auth.path,
|
|
112
|
+
...(auth.group ? { "Group": auth.group } : {})
|
|
113
|
+
} : {
|
|
114
|
+
"Access-Code": auth.accessCode
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
if (response.status === 401) {
|
|
120
|
+
throw new Error(`${response.status}: Unauthorized request.`);
|
|
121
|
+
}
|
|
122
|
+
else if (response.status === 403) {
|
|
123
|
+
throw new Error(`${response.status}: Forbidden request.`);
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`${response.status}: Bad request.`);
|
|
126
|
+
}
|
|
127
|
+
const buffer = await parseStream(response, onProgress ? (loaded) => {
|
|
128
|
+
if (this.contentLength > 0) {
|
|
129
|
+
onProgress(Math.min(Math.max(loaded / this.contentLength, 0), 1));
|
|
130
|
+
}
|
|
131
|
+
} : undefined);
|
|
132
|
+
if (onProgress) {
|
|
133
|
+
onProgress(1);
|
|
134
|
+
}
|
|
135
|
+
const data = Array.isArray(buffer) ? buffer[0] : buffer;
|
|
136
|
+
this.data = data;
|
|
137
|
+
return data;
|
|
138
|
+
}
|
|
139
|
+
// Fetch a server-generated preview image (image/webp) for this file, or
|
|
140
|
+
// undefined when the file type has no meaningful preview. Cached per file.
|
|
141
|
+
async preview(revalidate = false) {
|
|
142
|
+
if (this.previewData !== undefined && !revalidate) {
|
|
143
|
+
return this.previewData ?? undefined;
|
|
144
|
+
}
|
|
145
|
+
const auth = this.authorization;
|
|
146
|
+
const response = 'repository' in auth
|
|
147
|
+
? await fetch(`${Fauna.Termite.getURL()}/termite/repositories/${auth.repository}/files${auth.path.split('/').filter(Boolean).map((s) => '/' + encodeURIComponent(s)).join('')}?preview=1`, {
|
|
148
|
+
method: "GET",
|
|
149
|
+
headers: {
|
|
150
|
+
"Authorization": 'email' in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
|
|
151
|
+
...(auth.group ? { "Group": auth.group } : {}),
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
: await fetch(`${Fauna.getURL()}/file/preview`, {
|
|
155
|
+
method: "GET",
|
|
156
|
+
headers: {
|
|
157
|
+
"Authorization": 'email' in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
|
|
158
|
+
...('path' in auth ? {
|
|
159
|
+
"Path": this.contentType === 'application/x-directory' ? auth.path + '/' : auth.path,
|
|
160
|
+
...(auth.group ? { "Group": auth.group } : {})
|
|
161
|
+
} : {
|
|
162
|
+
"Access-Code": auth.accessCode
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
if (response.status === 204) {
|
|
167
|
+
this.previewData = null;
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
if (response.status === 401) {
|
|
172
|
+
throw new Error(`${response.status}: Unauthorized request.`);
|
|
173
|
+
}
|
|
174
|
+
else if (response.status === 403) {
|
|
175
|
+
throw new Error(`${response.status}: Forbidden request.`);
|
|
176
|
+
}
|
|
177
|
+
// Soft-fail (incl. 429): cache miss so this File instance does not hammer.
|
|
178
|
+
this.previewData = null;
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const buffer = await parseStream(response);
|
|
182
|
+
const data = Array.isArray(buffer) ? buffer[0] : buffer;
|
|
183
|
+
this.previewData = data;
|
|
184
|
+
return data;
|
|
185
|
+
}
|
|
186
|
+
async upload(onProgress) {
|
|
187
|
+
if ('accessCode' in this.authorization) {
|
|
188
|
+
throw new Error('401: Unauthorized request.');
|
|
189
|
+
}
|
|
190
|
+
const directory = this.contentType === 'application/x-directory';
|
|
191
|
+
if (!this.data && !directory) {
|
|
192
|
+
throw new Error('400: No data to upload.');
|
|
193
|
+
}
|
|
194
|
+
const auth = this.authorization;
|
|
195
|
+
const url = 'repository' in auth
|
|
196
|
+
? `${Fauna.Termite.getURL()}/termite/repositories/${auth.repository}/files${auth.path.split('/').filter(Boolean).map((s) => '/' + encodeURIComponent(s)).join('')}`
|
|
197
|
+
: `${Fauna.getURL()}/file/upload`;
|
|
198
|
+
const headers = {
|
|
199
|
+
Authorization: 'email' in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
|
|
200
|
+
'Content-Type': this.contentType || 'application/octet-stream',
|
|
201
|
+
};
|
|
202
|
+
if (!('repository' in auth))
|
|
203
|
+
headers.Path = directory ? auth.path + '/' : auth.path;
|
|
204
|
+
if (auth.group)
|
|
205
|
+
headers.Group = auth.group;
|
|
206
|
+
const body = directory ? 'Folder' : this.data.buffer;
|
|
207
|
+
// XMLHttpRequest reports upload progress; runtimes without it (Node) use fetch.
|
|
208
|
+
const status = typeof XMLHttpRequest === 'undefined'
|
|
209
|
+
? await fetch(url, { method: 'POST', headers, body }).then((r) => r.status, () => { throw new Error('Failed to upload file.'); })
|
|
210
|
+
: await sendWithProgress(url, headers, body, onProgress);
|
|
211
|
+
onProgress?.(1);
|
|
212
|
+
if (status === 401)
|
|
213
|
+
throw new Error(`${status}: Unauthorized request.`);
|
|
214
|
+
if (status === 403)
|
|
215
|
+
throw new Error(`${status}: Forbidden request.`);
|
|
216
|
+
if (status < 200 || status >= 300)
|
|
217
|
+
throw new Error(`${status}: Bad request.`);
|
|
218
|
+
this._online = true;
|
|
219
|
+
}
|
|
220
|
+
async copy(path) {
|
|
221
|
+
if ('accessCode' in this.authorization) {
|
|
222
|
+
throw new Error('401: Unauthorized request.');
|
|
223
|
+
}
|
|
224
|
+
if ('repository' in this.authorization) {
|
|
225
|
+
throw new Error('403: Not available for repository files.');
|
|
226
|
+
}
|
|
227
|
+
const response = await fetch(`${Fauna.getURL()}/file/copy`, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
headers: {
|
|
230
|
+
"Content-Type": "application/json",
|
|
231
|
+
"Authorization": 'email' in this.authorization.authorization ? `Token ${this.authorization.authorization.token}` : `ApiKey ${this.authorization.authorization.id}`,
|
|
232
|
+
"Path": this.contentType === 'application/x-directory' ? this.authorization.path + '/' : this.authorization.path,
|
|
233
|
+
...(this.authorization.group ? { "Group": this.authorization.group } : {})
|
|
234
|
+
},
|
|
235
|
+
body: JSON.stringify({ copyPath: path })
|
|
236
|
+
});
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
throw new Error(await response.text());
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async text() {
|
|
242
|
+
return new TextDecoder().decode(await this.download());
|
|
243
|
+
}
|
|
244
|
+
async json() {
|
|
245
|
+
return JSON.parse(await this.text());
|
|
246
|
+
}
|
|
247
|
+
async remove() {
|
|
248
|
+
if ('accessCode' in this.authorization) {
|
|
249
|
+
throw new Error('401: Unauthorized request.');
|
|
250
|
+
}
|
|
251
|
+
if ('repository' in this.authorization) {
|
|
252
|
+
throw new Error('403: Not available for repository files.');
|
|
253
|
+
}
|
|
254
|
+
await remove(this.authorization.authorization, this.contentType === 'application/x-directory' ? this.authorization.path + '/' : this.authorization.path, this.authorization.group);
|
|
255
|
+
this.data = undefined;
|
|
256
|
+
this._online = false;
|
|
257
|
+
}
|
|
258
|
+
async generateAccessCode(expiration) {
|
|
259
|
+
if ('accessCode' in this.authorization) {
|
|
260
|
+
throw new Error('401: Unauthorized request.');
|
|
261
|
+
}
|
|
262
|
+
if ('repository' in this.authorization) {
|
|
263
|
+
throw new Error('403: Not available for repository files.');
|
|
264
|
+
}
|
|
265
|
+
const response = await fetch(`${Fauna.getURL()}/file/access-code`, {
|
|
266
|
+
method: "POST",
|
|
267
|
+
headers: {
|
|
268
|
+
"Content-Type": "application/json",
|
|
269
|
+
"Authorization": 'email' in this.authorization.authorization ? `Token ${this.authorization.authorization.token}` : `ApiKey ${this.authorization.authorization.id}`,
|
|
270
|
+
"Path": this.contentType === 'application/x-directory' ? this.authorization.path + '/' : this.authorization.path,
|
|
271
|
+
...(this.authorization.group ? { "Group": this.authorization.group } : {}),
|
|
272
|
+
},
|
|
273
|
+
body: JSON.stringify({ expiration: expiration })
|
|
274
|
+
});
|
|
275
|
+
if (!response.ok) {
|
|
276
|
+
throw new Error(await response.text());
|
|
277
|
+
}
|
|
278
|
+
return (await response.text());
|
|
279
|
+
}
|
|
280
|
+
async owner() {
|
|
281
|
+
const auth = this.authorization;
|
|
282
|
+
if ('repository' in auth) {
|
|
283
|
+
throw new Error('403: Not available for repository files.');
|
|
284
|
+
}
|
|
285
|
+
const response = await fetch(`${Fauna.getURL()}/file/owner`, {
|
|
286
|
+
method: "GET",
|
|
287
|
+
headers: {
|
|
288
|
+
"Authorization": 'email' in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
|
|
289
|
+
...('path' in auth
|
|
290
|
+
? { "Path": auth.path, ...(auth.group ? { "Group": auth.group } : {}) }
|
|
291
|
+
: { "Access-Code": auth.accessCode }),
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
if (!response.ok) {
|
|
295
|
+
throw new Error(await response.text());
|
|
296
|
+
}
|
|
297
|
+
return await response.json();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
export async function list(authorization, path, group) {
|
|
301
|
+
const response = await fetch(`${Fauna.getURL()}/file/list`, {
|
|
302
|
+
method: "GET",
|
|
303
|
+
headers: {
|
|
304
|
+
"Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
|
|
305
|
+
"Path": path,
|
|
306
|
+
...(group ? { "Group": group } : {})
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
if (!response.ok) {
|
|
310
|
+
throw new Error(await response.text());
|
|
311
|
+
}
|
|
312
|
+
return await response.json();
|
|
313
|
+
}
|
|
314
|
+
export async function wrap(authorization, file, options = {}) {
|
|
315
|
+
const now = new Date();
|
|
316
|
+
// Browsers often leave File.type empty for HEIC; infer from the extension.
|
|
317
|
+
const contentType = file.type || mimeFromFileName(file.name) || "application/octet-stream";
|
|
318
|
+
return new FaunaFile(authorization, file.name, false, contentType, file.size, options.accessDate || now, options.createDate || now, new Uint8Array(await file.arrayBuffer()));
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Build an in-memory FaunaFile from raw bytes (not yet uploaded). `path` is
|
|
322
|
+
* the Drive destination (e.g. `tmp/${uuid}-${name}`); the display name is the
|
|
323
|
+
* last path segment. `authorization` is the caller's credentials/api key; the
|
|
324
|
+
* file is `online: false` until an explicit `upload()`.
|
|
325
|
+
*/
|
|
326
|
+
export function fromBytes(authorization, path, contentType, data, options = {}) {
|
|
327
|
+
const now = new Date();
|
|
328
|
+
const name = path.split('/').pop() || path;
|
|
329
|
+
return new FaunaFile({ authorization, path }, name, false, contentType, data.length, options.accessDate || now, options.createDate || now, data);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Build a streaming FaunaFile addressed by a per-file access code. Bytes are
|
|
333
|
+
* pulled on demand via `download()` (the `Access-Code` path). Used to hydrate
|
|
334
|
+
* chat message FILE parts returned by the server (each carries its own code),
|
|
335
|
+
* so members stream file bytes uniformly without a host-drive path.
|
|
336
|
+
*/
|
|
337
|
+
export function fromAccessCode(authorization, accessCode, meta) {
|
|
338
|
+
return FaunaFile.fromJSON(meta, { authorization, accessCode });
|
|
339
|
+
}
|
|
340
|
+
export async function folder(authorization, options = {}) {
|
|
341
|
+
if ('accessCode' in authorization) {
|
|
342
|
+
throw new Error('401: Unauthorized request.');
|
|
343
|
+
}
|
|
344
|
+
const normalized = authorization.path.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
345
|
+
const parts = normalized.split('/');
|
|
346
|
+
const name = parts[parts.length - 1] || '';
|
|
347
|
+
const now = new Date();
|
|
348
|
+
return new FaunaFile(authorization, name, false, 'application/x-directory', 0, options.accessDate || now, options.createDate || now);
|
|
349
|
+
}
|
|
350
|
+
export async function pull(authorization) {
|
|
351
|
+
const response = 'repository' in authorization
|
|
352
|
+
? await fetch(`${Fauna.Termite.getURL()}/termite/repositories/${authorization.repository}/files${authorization.path.split('/').filter(Boolean).map((s) => '/' + encodeURIComponent(s)).join('')}`, {
|
|
353
|
+
method: "GET",
|
|
354
|
+
headers: {
|
|
355
|
+
"Authorization": 'email' in authorization.authorization ? `Token ${authorization.authorization.token}` : `ApiKey ${authorization.authorization.id}`,
|
|
356
|
+
...(authorization.group ? { "Group": authorization.group } : {}),
|
|
357
|
+
}
|
|
358
|
+
})
|
|
359
|
+
: await fetch(`${Fauna.getURL()}/file/pull`, {
|
|
360
|
+
method: "GET",
|
|
361
|
+
headers: {
|
|
362
|
+
"Authorization": 'email' in authorization.authorization ? `Token ${authorization.authorization.token}` : `ApiKey ${authorization.authorization.id}`,
|
|
363
|
+
...('path' in authorization
|
|
364
|
+
? { "Path": authorization.path, ...(authorization.group ? { "Group": authorization.group } : {}) }
|
|
365
|
+
: { "Access-Code": authorization.accessCode }),
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
if (!response.ok) {
|
|
369
|
+
throw new Error(await response.text());
|
|
370
|
+
}
|
|
371
|
+
return FaunaFile.fromJSON(await response.json(), authorization);
|
|
372
|
+
}
|
|
373
|
+
export async function remove(authorization, path, group) {
|
|
374
|
+
const response = await fetch(`${Fauna.getURL()}/file`, {
|
|
375
|
+
method: "DELETE",
|
|
376
|
+
headers: {
|
|
377
|
+
"Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
|
|
378
|
+
"Path": path,
|
|
379
|
+
...(group ? { "Group": group } : {})
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
if (!response.ok) {
|
|
383
|
+
throw new Error(await response.text());
|
|
384
|
+
}
|
|
385
|
+
return response.ok;
|
|
386
|
+
}
|
|
387
|
+
/** Split a Drive style response into its parts. With `Encoding-Size` above 1 the
|
|
388
|
+
* body is a `--BOUNDARY` separated multipart and this returns every part. */
|
|
389
|
+
export async function parseStream(response, onLoaded) {
|
|
390
|
+
const encodingSize = response.headers.get('Encoding-Size');
|
|
391
|
+
if (encodingSize && parseInt(encodingSize) > 1) {
|
|
392
|
+
const reader = response.body.getReader();
|
|
393
|
+
let buffer = new Uint8Array(0);
|
|
394
|
+
let loaded = 0;
|
|
395
|
+
const boundaryBytes = new TextEncoder().encode('--BOUNDARY');
|
|
396
|
+
const parts = [];
|
|
397
|
+
while (true) {
|
|
398
|
+
const { done, value } = await reader.read();
|
|
399
|
+
if (done)
|
|
400
|
+
break;
|
|
401
|
+
if (value) {
|
|
402
|
+
const tmp = new Uint8Array(buffer.length + value.length);
|
|
403
|
+
tmp.set(buffer, 0);
|
|
404
|
+
tmp.set(value, buffer.length);
|
|
405
|
+
buffer = tmp;
|
|
406
|
+
loaded += value.length;
|
|
407
|
+
if (onLoaded) {
|
|
408
|
+
onLoaded(loaded);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function indexOfBoundary(buf, startPos = 0) {
|
|
413
|
+
for (let i = startPos; i <= buf.length - boundaryBytes.length; i++) {
|
|
414
|
+
let match = true;
|
|
415
|
+
for (let j = 0; j < boundaryBytes.length; j++) {
|
|
416
|
+
if (buf[i + j] !== boundaryBytes[j]) {
|
|
417
|
+
match = false;
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (match) {
|
|
422
|
+
return i;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return -1;
|
|
426
|
+
}
|
|
427
|
+
let currentPos = 0;
|
|
428
|
+
let boundaryCount = 0;
|
|
429
|
+
while (true) {
|
|
430
|
+
const idx = indexOfBoundary(buffer, currentPos);
|
|
431
|
+
if (idx === -1) {
|
|
432
|
+
if (currentPos < buffer.length) {
|
|
433
|
+
const part = buffer.slice(currentPos);
|
|
434
|
+
if (part.length > 0) {
|
|
435
|
+
parts.push(part);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
boundaryCount++;
|
|
442
|
+
const part = buffer.slice(currentPos, idx);
|
|
443
|
+
if (part.length > 0) {
|
|
444
|
+
parts.push(part);
|
|
445
|
+
}
|
|
446
|
+
currentPos = idx + boundaryBytes.length;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return parts;
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
const reader = response.body.getReader();
|
|
453
|
+
let buffer = new Uint8Array(0);
|
|
454
|
+
let loaded = 0;
|
|
455
|
+
while (true) {
|
|
456
|
+
const { done, value } = await reader.read();
|
|
457
|
+
if (done)
|
|
458
|
+
break;
|
|
459
|
+
if (value) {
|
|
460
|
+
const tmp = new Uint8Array(buffer.length + value.length);
|
|
461
|
+
tmp.set(buffer, 0);
|
|
462
|
+
tmp.set(value, buffer.length);
|
|
463
|
+
buffer = tmp;
|
|
464
|
+
loaded += value.length;
|
|
465
|
+
if (onLoaded) {
|
|
466
|
+
onLoaded(loaded);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return buffer;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Credentials, ApiKey } from "../../authentification.js";
|
|
2
|
+
import { Presence } from "../../shared/server.js";
|
|
3
|
+
import { ChatRoom, RoomHooks } from "../../parrot/room.js";
|
|
4
|
+
import { WebRoom, type WebRoomHooks, DomReplayer, type WebSnapshot, type WebMutation } from "../../marmot/web.js";
|
|
5
|
+
/** Public join URL for a web-room access code (chat joins via ensure, not the URL). */
|
|
6
|
+
export declare function shareUrl(code: string, origin?: string): string;
|
|
7
|
+
export type SessionHooks = {
|
|
8
|
+
web?: WebRoomHooks;
|
|
9
|
+
chat?: RoomHooks;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A paired live session: one `WebRoom` (live page DOM) + one `ChatRoom`.
|
|
13
|
+
* Share links carry only the web access code; chat uses ensure + Parrot code.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ExtensionWebSession {
|
|
16
|
+
readonly web: WebRoom;
|
|
17
|
+
readonly chat: ChatRoom;
|
|
18
|
+
readonly webSelf: Presence;
|
|
19
|
+
readonly chatSelf: Presence;
|
|
20
|
+
/** Bare web access code used in the share URL. */
|
|
21
|
+
readonly code: string;
|
|
22
|
+
private recorder;
|
|
23
|
+
replayer: DomReplayer | null;
|
|
24
|
+
private detachTools;
|
|
25
|
+
constructor(parts: {
|
|
26
|
+
web: WebRoom;
|
|
27
|
+
chat: ChatRoom;
|
|
28
|
+
webSelf: Presence;
|
|
29
|
+
chatSelf: Presence;
|
|
30
|
+
code: string;
|
|
31
|
+
});
|
|
32
|
+
shareCode(): string;
|
|
33
|
+
/** Page tools routed through the web room (host executes). */
|
|
34
|
+
pageTools(): import("../../parrot/generative.js").Tool[];
|
|
35
|
+
/**
|
|
36
|
+
* Begin hosting: upload HTML + assets, bind ids, stream mutations.
|
|
37
|
+
* Prefer `startWebShare` from the extension for progress UX.
|
|
38
|
+
*/
|
|
39
|
+
startHosting(root?: Node, onProgress?: (percent: number) => void): Promise<void>;
|
|
40
|
+
stopHosting(): void;
|
|
41
|
+
startViewing(mount: Element, onProgress?: (percent: number) => void): Promise<void>;
|
|
42
|
+
renderSnapshot(snapshot: WebSnapshot): void;
|
|
43
|
+
renderMutation(mutation: WebMutation): void;
|
|
44
|
+
private renderMutationAsync;
|
|
45
|
+
close(): void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Cached chat half of a share. The content script only mints/opens the room
|
|
49
|
+
* (`openRoom`); the chat iframe owns the live `ChatRoom` socket so the host
|
|
50
|
+
* does not double-join presence.
|
|
51
|
+
*/
|
|
52
|
+
export type CachedChatRoom = {
|
|
53
|
+
reference: string;
|
|
54
|
+
roomId: string;
|
|
55
|
+
code: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Open (or return) a shared Parrot chat room for this tab. Lives until the host
|
|
59
|
+
* leaves the page — panel close must not destroy it. Does not connect a socket
|
|
60
|
+
* here; call `connectRoom` from the chat UI with `code`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function ensureChatRoom(authorization: Credentials | ApiKey, cached?: CachedChatRoom | null): Promise<CachedChatRoom>;
|
|
63
|
+
export type WebShareSession = {
|
|
64
|
+
web: WebRoom;
|
|
65
|
+
webSelf: Presence;
|
|
66
|
+
chatId: string;
|
|
67
|
+
webCode: string;
|
|
68
|
+
reference: string;
|
|
69
|
+
shareCode(): string;
|
|
70
|
+
close(): void;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Bind (host) or open the Parrot chat paired with a web room. Always returns a
|
|
74
|
+
* fresh Parrot access code for `connectRoom({ code })`.
|
|
75
|
+
*/
|
|
76
|
+
export declare function ensureChatFromWebAccess(authorization: Credentials | ApiKey, scope: {
|
|
77
|
+
accessCode: string;
|
|
78
|
+
} | {
|
|
79
|
+
reference: string;
|
|
80
|
+
}, opts?: {
|
|
81
|
+
chatId?: string;
|
|
82
|
+
}): Promise<{
|
|
83
|
+
chatId: string;
|
|
84
|
+
code: string;
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Start the web room only (chat room must already exist). Uploads HTML + assets
|
|
88
|
+
* with progress, publishes bootstrap meta, starts mutation streaming + tools.
|
|
89
|
+
* Persists `chatId` under the web room so guests can ensure a Parrot code later.
|
|
90
|
+
*/
|
|
91
|
+
export declare function startWebShare(authorization: Credentials | ApiKey, chat: {
|
|
92
|
+
roomId: string;
|
|
93
|
+
}, options?: {
|
|
94
|
+
hooks?: WebRoomHooks;
|
|
95
|
+
root?: Node;
|
|
96
|
+
onProgress?: (percent: number) => void;
|
|
97
|
+
}): Promise<WebShareSession>;
|
|
98
|
+
export declare function openSession(authorization: Credentials | ApiKey, hooks?: SessionHooks): Promise<ExtensionWebSession>;
|
|
99
|
+
export declare function joinRoom(authorization: Credentials | ApiKey, webCode: string, hooks?: SessionHooks): Promise<ExtensionWebSession>;
|
|
100
|
+
export declare function invite(authorization: Credentials | ApiKey, email: string, joinUrl: string, scope: {
|
|
101
|
+
accessCode: string;
|
|
102
|
+
} | {
|
|
103
|
+
reference: string;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
status: "added" | "invited";
|
|
106
|
+
}>;
|