@frockbot/cloudflare 0.0.0 → 0.7.292

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.
Files changed (88) hide show
  1. package/build-artifact.ts +130 -0
  2. package/build-flutter-web.ts +508 -0
  3. package/deployment-config/README.md +414 -0
  4. package/deployment-config/cli.ts +228 -0
  5. package/deployment-config/generate.ts +689 -0
  6. package/deployment-config/jsonc.ts +18 -0
  7. package/deployment-config/profile-schema.generated.ts +391 -0
  8. package/deployment-config/profile.schema.json +358 -0
  9. package/deployment-config/profile.ts +124 -0
  10. package/migrations/0001_better_auth.sql +15 -0
  11. package/migrations/0002_drop_account_issuer.sql +8 -0
  12. package/package.json +61 -5
  13. package/release-version.ts +20 -0
  14. package/src/account-admission.ts +179 -0
  15. package/src/account-deletion.ts +274 -0
  16. package/src/admin-entrypoint.ts +194 -0
  17. package/src/admin-identities.ts +26 -0
  18. package/src/audit.ts +103 -0
  19. package/src/auth-package.access.ts +24 -0
  20. package/src/auth-package.ts +36 -0
  21. package/src/avatar-state-cleanup.ts +107 -0
  22. package/src/billing-computer.ts +267 -0
  23. package/src/billing-readiness.ts +21 -0
  24. package/src/billing.ts +461 -0
  25. package/src/bot-capabilities.ts +480 -0
  26. package/src/bot-recovery.ts +1 -0
  27. package/src/bot-state-channel.ts +702 -0
  28. package/src/bot-state.ts +3995 -0
  29. package/src/bot-template-cleanup.ts +98 -0
  30. package/src/bot-title-cleanup.ts +104 -0
  31. package/src/brand-icon.png +0 -0
  32. package/src/brand-logo.ts +2 -0
  33. package/src/brand.ts +36 -0
  34. package/src/client-compatibility.ts +51 -0
  35. package/src/compaction-announcement-cleanup.ts +113 -0
  36. package/src/computer-egress.ts +110 -0
  37. package/src/computer-host.ts +92 -0
  38. package/src/computer-screenshot-cleanup.ts +78 -0
  39. package/src/contracts.ts +832 -0
  40. package/src/debug.ts +272 -0
  41. package/src/default-packages-marker-cleanup.ts +39 -0
  42. package/src/deployment-policy-admin-host.ts +121 -0
  43. package/src/deployment-policy.ts +426 -0
  44. package/src/directory-profile-cleanup.ts +101 -0
  45. package/src/durable-rpc.ts +753 -0
  46. package/src/durable-session.ts +21 -0
  47. package/src/entry-boundary.ts +103 -0
  48. package/src/frock-ai.ts +338 -0
  49. package/src/gateway.ts +1392 -0
  50. package/src/group-chat.ts +736 -0
  51. package/src/hidden-bot-notifications-cleanup.ts +32 -0
  52. package/src/index.ts +2798 -0
  53. package/src/insights.ts +15 -0
  54. package/src/machine-messages-cleanup.ts +121 -0
  55. package/src/machine-socket.ts +164 -0
  56. package/src/memory-records.ts +181 -0
  57. package/src/memory.ts +145 -0
  58. package/src/model-rates.ts +252 -0
  59. package/src/native-auth.ts +1006 -0
  60. package/src/native-sessions.ts +121 -0
  61. package/src/notification-state-cleanup.ts +18 -0
  62. package/src/ollama-web-search-cleanup.ts +69 -0
  63. package/src/package-page-shapes-cleanup.ts +190 -0
  64. package/src/plugin-egress.ts +31 -0
  65. package/src/plugin-page-route.ts +72 -0
  66. package/src/plugin-panels-cleanup.ts +101 -0
  67. package/src/prepared-input-cleanup.ts +105 -0
  68. package/src/production-secrets.ts +484 -0
  69. package/src/project-cleanup.ts +123 -0
  70. package/src/project-events-cleanup.ts +152 -0
  71. package/src/publication-state-cleanup.ts +92 -0
  72. package/src/push.ts +498 -0
  73. package/src/request-body.ts +165 -0
  74. package/src/routine-state-cleanup.ts +57 -0
  75. package/src/search.ts +88 -0
  76. package/src/sidebar-label-cleanup.ts +165 -0
  77. package/src/skill-index-cleanup.ts +53 -0
  78. package/src/supersede-cleanup.ts +162 -0
  79. package/src/test-chat-cleanup.ts +93 -0
  80. package/src/uploads.ts +486 -0
  81. package/src/user-application.ts +1068 -0
  82. package/src/user-configuration.ts +4491 -0
  83. package/src/voice-assistant.ts +4999 -0
  84. package/src/voice-dictation.ts +743 -0
  85. package/src/working-context-cleanup.ts +96 -0
  86. package/src/workspace.ts +201 -0
  87. package/wrangler.jsonc +385 -0
  88. package/README.md +0 -3
@@ -0,0 +1,480 @@
1
+ // The loopback CAPABILITIES service binding a Plugin worker sees.
2
+ //
3
+ // Minted once per User with the User as its only prop. Which Turn, Bot and
4
+ // Plugin a call is for arrives on the call as its scope; the Bot Durable Object
5
+ // it is routed to resolves that Turn's authority when it is called and refuses
6
+ // a scope that is not the Turn it is running. So nothing here can go stale in
7
+ // a cached worker, and nothing here can hand out authority the Bot does not
8
+ // hold: the stub is an address, not a snapshot.
9
+ import { WorkerEntrypoint } from "cloudflare:workers";
10
+ import type {
11
+ IsolateCapabilityListOutcomeV1,
12
+ IsolateConnectionOutcomeV1,
13
+ IsolateDeviceCallOutcomeV1,
14
+ IsolateJevOutcomeV1,
15
+ IsolateMemoryOutcomeV1,
16
+ IsolateModelOutcomeV1,
17
+ IsolateEmailOutcomeV1,
18
+ IsolateScheduleOutcomeV1,
19
+ IsolateScopeV1,
20
+ IsolateSettingsOutcomeV1,
21
+ IsolateStorageListOutcomeV1,
22
+ IsolateStorageOutcomeV1,
23
+ IsolateWorkspaceOutcomeV1,
24
+ PluginModelTransportOutcomeV1,
25
+ } from "@frockbot/core/contracts";
26
+ import {
27
+ decodeIsolateCapabilityListV1,
28
+ decodeIsolateDeviceCallRequestV1,
29
+ decodeIsolateJevRequestV1,
30
+ decodeIsolateMemoryReadRequestV1,
31
+ decodeIsolateMemoryWriteRequestV1,
32
+ decodeIsolateModelInvocationV1,
33
+ decodeIsolateEmailRequestV1,
34
+ decodeIsolateScheduleRequestV1,
35
+ decodeIsolateScopeV1,
36
+ decodeIsolateStorageDeleteRequestV1,
37
+ decodeIsolateStorageGetRequestV1,
38
+ decodeIsolateStorageListRequestV1,
39
+ decodeIsolateStoragePutRequestV1,
40
+ decodeIsolateWorkspaceDeleteRequestV1,
41
+ decodeIsolateWorkspaceListRequestV1,
42
+ decodeIsolateWorkspacePathV1,
43
+ decodeIsolateWorkspaceWriteRequestV1,
44
+ decodeNormalizedModelRequestV1,
45
+ } from "@frockbot/core/contracts";
46
+ import type { BotCapabilitiesPropsV1 } from "@frockbot/app/isolates/capabilities";
47
+ import type { BotState } from "./bot-state.js";
48
+
49
+ function unavailable(reason: string): {
50
+ status: "unavailable";
51
+ reason: string;
52
+ } {
53
+ return { status: "unavailable", reason };
54
+ }
55
+
56
+ export type { BotCapabilitiesPropsV1 };
57
+
58
+ export interface BotCapabilitiesEnv {
59
+ BOT_STATES: DurableObjectNamespace<BotState>;
60
+ }
61
+
62
+ interface BotIsolateRpc {
63
+ isolateAuthority(input: unknown): Promise<unknown>;
64
+ isolateInvokeModel(input: unknown): Promise<unknown>;
65
+ isolateMemoryRead(input: unknown): Promise<IsolateMemoryOutcomeV1>;
66
+ isolateJevDecide(input: unknown): Promise<IsolateJevOutcomeV1>;
67
+ isolateMemoryWrite(input: unknown): Promise<IsolateMemoryOutcomeV1>;
68
+ isolateMemoryForget(input: unknown): Promise<IsolateMemoryOutcomeV1>;
69
+ isolateWorkspaceRead(input: unknown): Promise<IsolateWorkspaceOutcomeV1>;
70
+ isolateWorkspaceList(input: unknown): Promise<IsolateWorkspaceOutcomeV1>;
71
+ isolateWorkspaceStat(input: unknown): Promise<IsolateWorkspaceOutcomeV1>;
72
+ isolateWorkspaceWrite(input: unknown): Promise<IsolateWorkspaceOutcomeV1>;
73
+ isolateWorkspaceDelete(input: unknown): Promise<IsolateWorkspaceOutcomeV1>;
74
+ isolateConnection(input: unknown): Promise<IsolateConnectionOutcomeV1>;
75
+ isolateModelTransport(input: unknown): Promise<PluginModelTransportOutcomeV1>;
76
+ isolateSchedule(input: unknown): Promise<IsolateScheduleOutcomeV1>;
77
+ isolateEmail(input: unknown): Promise<IsolateEmailOutcomeV1>;
78
+ isolateDeviceCall(input: unknown): Promise<IsolateDeviceCallOutcomeV1>;
79
+ isolateStorageGet(input: unknown): Promise<IsolateStorageOutcomeV1>;
80
+ isolateStoragePut(input: unknown): Promise<IsolateStorageOutcomeV1>;
81
+ isolateStorageDelete(input: unknown): Promise<IsolateStorageOutcomeV1>;
82
+ isolateStorageList(input: unknown): Promise<IsolateStorageListOutcomeV1>;
83
+ isolateSettings(input: unknown): Promise<IsolateSettingsOutcomeV1>;
84
+ }
85
+
86
+ export class BotCapabilities extends WorkerEntrypoint<
87
+ BotCapabilitiesEnv,
88
+ BotCapabilitiesPropsV1
89
+ > {
90
+ /** The Bot the scope names, which is always one of this User's. */
91
+ private rpc(scope: IsolateScopeV1): BotIsolateRpc {
92
+ const id = this.env.BOT_STATES.idFromName(
93
+ `${this.ctx.props.userId}:${scope.botId}`,
94
+ );
95
+ return this.env.BOT_STATES.get(id) as unknown as BotIsolateRpc;
96
+ }
97
+
98
+ /**
99
+ * The envelope every Bot RPC takes. The scope is decoded here — Plugin code
100
+ * wrote it, through the wrapper — and the User comes from the props, which
101
+ * Plugin code cannot forge.
102
+ */
103
+ private scoped(
104
+ rawScope: unknown,
105
+ request: unknown,
106
+ ): { rpc: BotIsolateRpc; envelope: Record<string, unknown> } {
107
+ const scope = decodeIsolateScopeV1(rawScope);
108
+ return {
109
+ rpc: this.rpc(scope),
110
+ envelope: {
111
+ schemaVersion: 1,
112
+ userId: this.ctx.props.userId,
113
+ botId: scope.botId,
114
+ runId: scope.runId,
115
+ sessionId: scope.sessionId,
116
+ turnId: scope.turnId,
117
+ packageId: scope.pluginId,
118
+ generationId: scope.generationId,
119
+ request,
120
+ },
121
+ };
122
+ }
123
+
124
+ async list(scope: unknown): Promise<IsolateCapabilityListOutcomeV1> {
125
+ try {
126
+ const { rpc, envelope } = this.scoped(scope, null);
127
+ return decodeIsolateCapabilityListV1(
128
+ await rpc.isolateAuthority(envelope),
129
+ );
130
+ } catch {
131
+ return unavailable("capabilities are unavailable");
132
+ }
133
+ }
134
+
135
+ async invokeModel(
136
+ scope: unknown,
137
+ request: unknown,
138
+ ): Promise<IsolateModelOutcomeV1> {
139
+ try {
140
+ const { rpc, envelope } = this.scoped(
141
+ scope,
142
+ decodeNormalizedModelRequestV1(request),
143
+ );
144
+ return decodeIsolateModelInvocationV1(
145
+ await rpc.isolateInvokeModel(envelope),
146
+ );
147
+ } catch {
148
+ return unavailable("the model request could not be served");
149
+ }
150
+ }
151
+
152
+ async jevDecide(
153
+ scope: unknown,
154
+ request: unknown,
155
+ ): Promise<IsolateJevOutcomeV1> {
156
+ try {
157
+ const { rpc, envelope } = this.scoped(
158
+ scope,
159
+ decodeIsolateJevRequestV1(request),
160
+ );
161
+ return await rpc.isolateJevDecide(envelope);
162
+ } catch (error) {
163
+ // A malformed request is the Plugin's to fix; say what was wrong.
164
+ return unavailable(
165
+ error instanceof Error &&
166
+ error.message.startsWith("isolate Jev request")
167
+ ? error.message
168
+ : "Jev is unavailable",
169
+ );
170
+ }
171
+ }
172
+
173
+ async memoryRead(
174
+ scope: unknown,
175
+ request: unknown,
176
+ ): Promise<IsolateMemoryOutcomeV1> {
177
+ try {
178
+ const { rpc, envelope } = this.scoped(
179
+ scope,
180
+ decodeIsolateMemoryReadRequestV1(request),
181
+ );
182
+ return await rpc.isolateMemoryRead(envelope);
183
+ } catch {
184
+ return unavailable("Memory is unavailable");
185
+ }
186
+ }
187
+
188
+ async memoryWrite(
189
+ scope: unknown,
190
+ request: unknown,
191
+ ): Promise<IsolateMemoryOutcomeV1> {
192
+ try {
193
+ const { rpc, envelope } = this.scoped(
194
+ scope,
195
+ decodeIsolateMemoryWriteRequestV1(request),
196
+ );
197
+ return await rpc.isolateMemoryWrite(envelope);
198
+ } catch {
199
+ return unavailable("Memory is unavailable");
200
+ }
201
+ }
202
+
203
+ async memoryForget(
204
+ scope: unknown,
205
+ request: unknown,
206
+ ): Promise<IsolateMemoryOutcomeV1> {
207
+ try {
208
+ const { rpc, envelope } = this.scoped(
209
+ scope,
210
+ decodeIsolateMemoryWriteRequestV1(request),
211
+ );
212
+ return await rpc.isolateMemoryForget(envelope);
213
+ } catch {
214
+ return unavailable("Memory is unavailable");
215
+ }
216
+ }
217
+
218
+ async workspaceRead(
219
+ scope: unknown,
220
+ request: unknown,
221
+ ): Promise<IsolateWorkspaceOutcomeV1> {
222
+ try {
223
+ const { rpc, envelope } = this.scoped(
224
+ scope,
225
+ decodeIsolateWorkspacePathV1(request),
226
+ );
227
+ return await rpc.isolateWorkspaceRead(envelope);
228
+ } catch {
229
+ return unavailable("Workspace is unavailable");
230
+ }
231
+ }
232
+
233
+ async workspaceList(
234
+ scope: unknown,
235
+ request: unknown,
236
+ ): Promise<IsolateWorkspaceOutcomeV1> {
237
+ try {
238
+ const { rpc, envelope } = this.scoped(
239
+ scope,
240
+ decodeIsolateWorkspaceListRequestV1(request),
241
+ );
242
+ return await rpc.isolateWorkspaceList(envelope);
243
+ } catch {
244
+ return unavailable("Workspace is unavailable");
245
+ }
246
+ }
247
+
248
+ async workspaceStat(
249
+ scope: unknown,
250
+ request: unknown,
251
+ ): Promise<IsolateWorkspaceOutcomeV1> {
252
+ try {
253
+ const { rpc, envelope } = this.scoped(
254
+ scope,
255
+ decodeIsolateWorkspacePathV1(request),
256
+ );
257
+ return await rpc.isolateWorkspaceStat(envelope);
258
+ } catch {
259
+ return unavailable("Workspace is unavailable");
260
+ }
261
+ }
262
+
263
+ async workspaceWrite(
264
+ scope: unknown,
265
+ request: unknown,
266
+ ): Promise<IsolateWorkspaceOutcomeV1> {
267
+ try {
268
+ const { rpc, envelope } = this.scoped(
269
+ scope,
270
+ decodeIsolateWorkspaceWriteRequestV1(request),
271
+ );
272
+ return await rpc.isolateWorkspaceWrite(envelope);
273
+ } catch {
274
+ return unavailable("Workspace is unavailable");
275
+ }
276
+ }
277
+
278
+ async workspaceDelete(
279
+ scope: unknown,
280
+ request: unknown,
281
+ ): Promise<IsolateWorkspaceOutcomeV1> {
282
+ try {
283
+ const { rpc, envelope } = this.scoped(
284
+ scope,
285
+ decodeIsolateWorkspaceDeleteRequestV1(request),
286
+ );
287
+ return await rpc.isolateWorkspaceDelete(envelope);
288
+ } catch {
289
+ return unavailable("Workspace is unavailable");
290
+ }
291
+ }
292
+
293
+ /**
294
+ * One credentialed upstream call for a model provider Plugin (ADR 0032).
295
+ * The ticket is the host's own, minted for the dispatch this call belongs
296
+ * to; everything else is checked on the Bot object, which is the only
297
+ * place that holds the Connection and the credential.
298
+ */
299
+ async modelTransport(
300
+ scope: unknown,
301
+ request: unknown,
302
+ ): Promise<PluginModelTransportOutcomeV1> {
303
+ try {
304
+ const { rpc, envelope } = this.scoped(scope, request);
305
+ return await rpc.isolateModelTransport(envelope);
306
+ } catch {
307
+ return {
308
+ status: "unavailable",
309
+ reason: "the model transport is unavailable",
310
+ };
311
+ }
312
+ }
313
+
314
+ async connection(
315
+ scope: unknown,
316
+ connectionId: unknown,
317
+ ): Promise<IsolateConnectionOutcomeV1> {
318
+ if (
319
+ typeof connectionId !== "string" ||
320
+ connectionId.length === 0 ||
321
+ connectionId.length > 256
322
+ ) {
323
+ return unavailable("the Connection is unavailable");
324
+ }
325
+ try {
326
+ const { rpc, envelope } = this.scoped(scope, connectionId);
327
+ return await rpc.isolateConnection(envelope);
328
+ } catch {
329
+ return unavailable("the Connection is unavailable");
330
+ }
331
+ }
332
+
333
+ async sendEmail(
334
+ scope: unknown,
335
+ request: unknown,
336
+ ): Promise<IsolateEmailOutcomeV1> {
337
+ // Decoded outside the call, because a request the kernel refuses and a
338
+ // deployment that cannot send mail are different facts: a draft naming
339
+ // something that is not an address is the draft's problem, and answering
340
+ // it with "unavailable" would tell the person this deployment sends no
341
+ // mail when it sends mail fine.
342
+ let decoded;
343
+ try {
344
+ decoded = decodeIsolateEmailRequestV1(request);
345
+ } catch (error) {
346
+ return unavailable(
347
+ `this email was refused: ${error instanceof Error ? error.message : String(error)}`,
348
+ );
349
+ }
350
+ let scoped;
351
+ try {
352
+ scoped = this.scoped(scope, decoded);
353
+ } catch {
354
+ return unavailable("sending email is unavailable");
355
+ }
356
+ try {
357
+ return await scoped.rpc.isolateEmail(scoped.envelope);
358
+ } catch {
359
+ // The Durable Object may have claimed the decision and handed the
360
+ // message over before this call lost its answer. Saying `unavailable`
361
+ // would tell the Plugin to try again; one decision sends one message.
362
+ return {
363
+ status: "unknown",
364
+ reason:
365
+ "the message may have been sent: the answer from the sender was lost",
366
+ };
367
+ }
368
+ }
369
+
370
+ async deviceCall(
371
+ scope: unknown,
372
+ request: unknown,
373
+ ): Promise<IsolateDeviceCallOutcomeV1> {
374
+ let scoped;
375
+ try {
376
+ scoped = this.scoped(scope, decodeIsolateDeviceCallRequestV1(request));
377
+ } catch (error) {
378
+ return {
379
+ ok: false,
380
+ outcome: "failed",
381
+ error: `this device call was refused: ${error instanceof Error ? error.message : String(error)}`,
382
+ };
383
+ }
384
+ try {
385
+ return await scoped.rpc.isolateDeviceCall(scoped.envelope);
386
+ } catch {
387
+ // The Bot's object may have sent the call before this answer was lost.
388
+ return {
389
+ ok: false,
390
+ outcome: "unknown",
391
+ error:
392
+ "the answer from the computer was lost; the call may have taken effect",
393
+ };
394
+ }
395
+ }
396
+
397
+ async schedule(
398
+ scope: unknown,
399
+ request: unknown,
400
+ ): Promise<IsolateScheduleOutcomeV1> {
401
+ try {
402
+ const { rpc, envelope } = this.scoped(
403
+ scope,
404
+ decodeIsolateScheduleRequestV1(request),
405
+ );
406
+ return await rpc.isolateSchedule(envelope);
407
+ } catch {
408
+ return unavailable("durable scheduling is unavailable");
409
+ }
410
+ }
411
+
412
+ async storageGet(
413
+ scope: unknown,
414
+ request: unknown,
415
+ ): Promise<IsolateStorageOutcomeV1> {
416
+ try {
417
+ const { rpc, envelope } = this.scoped(
418
+ scope,
419
+ decodeIsolateStorageGetRequestV1(request),
420
+ );
421
+ return await rpc.isolateStorageGet(envelope);
422
+ } catch {
423
+ return unavailable("storage is unavailable");
424
+ }
425
+ }
426
+
427
+ async storagePut(
428
+ scope: unknown,
429
+ request: unknown,
430
+ ): Promise<IsolateStorageOutcomeV1> {
431
+ try {
432
+ const { rpc, envelope } = this.scoped(
433
+ scope,
434
+ decodeIsolateStoragePutRequestV1(request),
435
+ );
436
+ return await rpc.isolateStoragePut(envelope);
437
+ } catch {
438
+ return unavailable("storage is unavailable");
439
+ }
440
+ }
441
+
442
+ async storageDelete(
443
+ scope: unknown,
444
+ request: unknown,
445
+ ): Promise<IsolateStorageOutcomeV1> {
446
+ try {
447
+ const { rpc, envelope } = this.scoped(
448
+ scope,
449
+ decodeIsolateStorageDeleteRequestV1(request),
450
+ );
451
+ return await rpc.isolateStorageDelete(envelope);
452
+ } catch {
453
+ return unavailable("storage is unavailable");
454
+ }
455
+ }
456
+
457
+ async storageList(
458
+ scope: unknown,
459
+ request: unknown,
460
+ ): Promise<IsolateStorageListOutcomeV1> {
461
+ try {
462
+ const { rpc, envelope } = this.scoped(
463
+ scope,
464
+ decodeIsolateStorageListRequestV1(request ?? {}),
465
+ );
466
+ return await rpc.isolateStorageList(envelope);
467
+ } catch {
468
+ return unavailable("storage is unavailable");
469
+ }
470
+ }
471
+
472
+ async settings(scope: unknown): Promise<IsolateSettingsOutcomeV1> {
473
+ try {
474
+ const { rpc, envelope } = this.scoped(scope, null);
475
+ return await rpc.isolateSettings(envelope);
476
+ } catch {
477
+ return unavailable("settings are unavailable");
478
+ }
479
+ }
480
+ }
@@ -0,0 +1 @@
1
+ export * from "@frockbot/app/shell/backend-recovery";