@frockbot/cloudflare 0.0.0 → 0.7.291
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/build-artifact.ts +130 -0
- package/build-flutter-web.ts +508 -0
- package/deployment-config/README.md +414 -0
- package/deployment-config/cli.ts +228 -0
- package/deployment-config/generate.ts +689 -0
- package/deployment-config/jsonc.ts +18 -0
- package/deployment-config/profile-schema.generated.ts +391 -0
- package/deployment-config/profile.schema.json +358 -0
- package/deployment-config/profile.ts +124 -0
- package/migrations/0001_better_auth.sql +15 -0
- package/migrations/0002_drop_account_issuer.sql +8 -0
- package/package.json +61 -5
- package/release-version.ts +20 -0
- package/src/account-admission.ts +179 -0
- package/src/account-deletion.ts +274 -0
- package/src/admin-entrypoint.ts +194 -0
- package/src/admin-identities.ts +26 -0
- package/src/audit.ts +103 -0
- package/src/auth-package.access.ts +24 -0
- package/src/auth-package.ts +36 -0
- package/src/avatar-state-cleanup.ts +107 -0
- package/src/billing-computer.ts +267 -0
- package/src/billing-readiness.ts +21 -0
- package/src/billing.ts +461 -0
- package/src/bot-capabilities.ts +480 -0
- package/src/bot-recovery.ts +1 -0
- package/src/bot-state-channel.ts +702 -0
- package/src/bot-state.ts +3995 -0
- package/src/bot-template-cleanup.ts +98 -0
- package/src/bot-title-cleanup.ts +104 -0
- package/src/brand-icon.png +0 -0
- package/src/brand-logo.ts +2 -0
- package/src/brand.ts +36 -0
- package/src/client-compatibility.ts +51 -0
- package/src/compaction-announcement-cleanup.ts +113 -0
- package/src/computer-egress.ts +110 -0
- package/src/computer-host.ts +92 -0
- package/src/computer-screenshot-cleanup.ts +78 -0
- package/src/contracts.ts +832 -0
- package/src/debug.ts +272 -0
- package/src/default-packages-marker-cleanup.ts +39 -0
- package/src/deployment-policy-admin-host.ts +121 -0
- package/src/deployment-policy.ts +426 -0
- package/src/directory-profile-cleanup.ts +101 -0
- package/src/durable-rpc.ts +753 -0
- package/src/durable-session.ts +21 -0
- package/src/entry-boundary.ts +103 -0
- package/src/frock-ai.ts +338 -0
- package/src/gateway.ts +1392 -0
- package/src/group-chat.ts +736 -0
- package/src/hidden-bot-notifications-cleanup.ts +32 -0
- package/src/index.ts +2798 -0
- package/src/insights.ts +15 -0
- package/src/machine-messages-cleanup.ts +121 -0
- package/src/machine-socket.ts +164 -0
- package/src/memory-records.ts +181 -0
- package/src/memory.ts +145 -0
- package/src/model-rates.ts +252 -0
- package/src/native-auth.ts +1006 -0
- package/src/native-sessions.ts +121 -0
- package/src/notification-state-cleanup.ts +18 -0
- package/src/ollama-web-search-cleanup.ts +69 -0
- package/src/package-page-shapes-cleanup.ts +190 -0
- package/src/plugin-egress.ts +31 -0
- package/src/plugin-page-route.ts +72 -0
- package/src/plugin-panels-cleanup.ts +101 -0
- package/src/prepared-input-cleanup.ts +105 -0
- package/src/production-secrets.ts +484 -0
- package/src/project-cleanup.ts +123 -0
- package/src/project-events-cleanup.ts +152 -0
- package/src/publication-state-cleanup.ts +92 -0
- package/src/push.ts +498 -0
- package/src/request-body.ts +165 -0
- package/src/routine-state-cleanup.ts +57 -0
- package/src/search.ts +88 -0
- package/src/sidebar-label-cleanup.ts +165 -0
- package/src/skill-index-cleanup.ts +53 -0
- package/src/supersede-cleanup.ts +162 -0
- package/src/test-chat-cleanup.ts +93 -0
- package/src/uploads.ts +486 -0
- package/src/user-application.ts +1068 -0
- package/src/user-configuration.ts +4491 -0
- package/src/voice-assistant.ts +4999 -0
- package/src/voice-dictation.ts +743 -0
- package/src/working-context-cleanup.ts +96 -0
- package/src/workspace.ts +201 -0
- package/wrangler.jsonc +385 -0
- package/README.md +0 -3
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://frockbot.com/schemas/deployment-profile-v1.json",
|
|
4
|
+
"title": "FrockBot deployment profile",
|
|
5
|
+
"description": "Who a deployment is: the Cloudflare account, the Worker names, the hostnames, the auth Package and the resources that carry identity. `frockbot-deployment-config` (`bun run deployment:config` in the FrockBot repository) reads one of these and writes the deployable wrangler configs from the tracked ones, which hold bindings and migrations and no identity at all.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "name", "accountId", "prefix", "authPackage"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": {
|
|
11
|
+
"const": 1
|
|
12
|
+
},
|
|
13
|
+
"name": {
|
|
14
|
+
"description": "The profile's own name. Must match the file name, and names the directory under `.deployment/`.",
|
|
15
|
+
"type": "string",
|
|
16
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
17
|
+
},
|
|
18
|
+
"accountId": {
|
|
19
|
+
"description": "The Cloudflare account every Worker in this deployment belongs to.",
|
|
20
|
+
"type": "string",
|
|
21
|
+
"pattern": "^[0-9a-f]{32}$"
|
|
22
|
+
},
|
|
23
|
+
"region": {
|
|
24
|
+
"description": "Where a fresh deployment's R2 buckets and Vectorize index are created. The installer passes it; no wrangler config carries it, so changing it never moves an existing resource.",
|
|
25
|
+
"type": "string",
|
|
26
|
+
"enum": ["wnam", "enam", "weur", "eeur", "apac", "oc"]
|
|
27
|
+
},
|
|
28
|
+
"prefix": {
|
|
29
|
+
"description": "What every unnamed Worker and resource below is named from.",
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
32
|
+
},
|
|
33
|
+
"workers": {
|
|
34
|
+
"description": "One entry per deployable. An entry that is absent is not generated and not deployed, which is how a profile leaves out the hosted-only marketing site and admin portal.",
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"properties": {
|
|
38
|
+
"app": {
|
|
39
|
+
"$ref": "#/$defs/worker"
|
|
40
|
+
},
|
|
41
|
+
"computerHost": {
|
|
42
|
+
"$ref": "#/$defs/worker"
|
|
43
|
+
},
|
|
44
|
+
"appletBuild": {
|
|
45
|
+
"$ref": "#/$defs/worker"
|
|
46
|
+
},
|
|
47
|
+
"marketing": {
|
|
48
|
+
"$ref": "#/$defs/worker"
|
|
49
|
+
},
|
|
50
|
+
"adminPortal": {
|
|
51
|
+
"$ref": "#/$defs/worker"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"images": {
|
|
56
|
+
"description": "Where the two container Workers get their image. Absent is `dockerfile`: wrangler builds it on the deploying machine, which needs Docker. `registry` pulls the image `release.yml` published for one tag, which is what an installer with no Docker deploys.",
|
|
57
|
+
"type": "object",
|
|
58
|
+
"additionalProperties": false,
|
|
59
|
+
"required": ["source"],
|
|
60
|
+
"properties": {
|
|
61
|
+
"source": {
|
|
62
|
+
"enum": ["dockerfile", "registry"]
|
|
63
|
+
},
|
|
64
|
+
"registry": {
|
|
65
|
+
"description": "The registry and namespace the images were published under, without the image name. It must be one Cloudflare Containers pull from: the managed registry, Docker Hub, Amazon ECR or Google Artifact Registry (see the README).",
|
|
66
|
+
"type": "string",
|
|
67
|
+
"pattern": "^[a-z0-9][a-z0-9.-]*(:[0-9]+)?(/[a-z0-9][a-z0-9._-]*)*$"
|
|
68
|
+
},
|
|
69
|
+
"tag": {
|
|
70
|
+
"description": "The image tag, which is the release version the deployment is running.",
|
|
71
|
+
"type": "string",
|
|
72
|
+
"pattern": "^[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"allOf": [
|
|
76
|
+
{
|
|
77
|
+
"if": {
|
|
78
|
+
"properties": {
|
|
79
|
+
"source": {
|
|
80
|
+
"const": "registry"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"required": ["source"]
|
|
84
|
+
},
|
|
85
|
+
"then": {
|
|
86
|
+
"properties": {
|
|
87
|
+
"registry": true,
|
|
88
|
+
"tag": true
|
|
89
|
+
},
|
|
90
|
+
"required": ["registry", "tag"]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"authPackage": {
|
|
96
|
+
"description": "Which sign-in Package this deployment builds: one of the two `@frockbot/cloudflare` ships, or a path, relative to this profile file, to a chooser module a white-label wrote \u2014 a module exporting `AUTH_PACKAGE_V1: AuthPackageBuildV1` and the `AuthPackageEnvironmentV1` type, as `apps/cloudflare/src/auth-package.ts` does (ADR 0038 \u00a73). Written as a wrangler `alias` for `#auth-package` unless it is `better-auth`, which the tracked source already resolves.",
|
|
97
|
+
"anyOf": [
|
|
98
|
+
{
|
|
99
|
+
"enum": ["better-auth", "access"]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "string",
|
|
103
|
+
"pattern": "^\\.{1,2}/\\S+\\.(ts|mts|js|mjs)$"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"authEnvironment": {
|
|
108
|
+
"description": "What a white-label's own auth Package reads off `env`, which this repository cannot know: `secrets` are required by the production-secrets check and carried by the deploy's secrets file, and `vars` are written into the app Worker's `vars`. Together they must name exactly the settings the chooser's `AUTH_PACKAGE_V1.required` lists. Only for an auth Package named by path.",
|
|
109
|
+
"type": "object",
|
|
110
|
+
"additionalProperties": false,
|
|
111
|
+
"properties": {
|
|
112
|
+
"secrets": {
|
|
113
|
+
"type": "array",
|
|
114
|
+
"uniqueItems": true,
|
|
115
|
+
"items": {
|
|
116
|
+
"type": "object",
|
|
117
|
+
"additionalProperties": false,
|
|
118
|
+
"required": ["name", "why"],
|
|
119
|
+
"properties": {
|
|
120
|
+
"name": {
|
|
121
|
+
"$ref": "#/$defs/envName"
|
|
122
|
+
},
|
|
123
|
+
"why": {
|
|
124
|
+
"type": "string",
|
|
125
|
+
"minLength": 1
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"vars": {
|
|
131
|
+
"type": "object",
|
|
132
|
+
"propertyNames": {
|
|
133
|
+
"$ref": "#/$defs/envName"
|
|
134
|
+
},
|
|
135
|
+
"additionalProperties": {
|
|
136
|
+
"type": "string"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"brand": {
|
|
142
|
+
"description": "The brand module this deployment builds, relative to this profile file: a TypeScript module exporting `BRAND_V1: BrandV1` (`core/contracts/brand.ts`). Written as a wrangler `alias` for `#brand`. Absent, the Worker resolves `#brand` to FrockBot's own, `apps/cloudflare/src/brand.ts`.",
|
|
143
|
+
"type": "string",
|
|
144
|
+
"pattern": "^\\S+\\.ts$"
|
|
145
|
+
},
|
|
146
|
+
"webClient": {
|
|
147
|
+
"description": "The directory the app Worker's static assets are uploaded from, relative to this profile file: the web client `build-flutter-web.ts` staged for this deployment's own application. Absent, the package's own `dist/web`, which is where FrockBot's build stages FrockBot's client.",
|
|
148
|
+
"type": "string",
|
|
149
|
+
"minLength": 1
|
|
150
|
+
},
|
|
151
|
+
"access": {
|
|
152
|
+
"description": "The Cloudflare Access application the `access` Package verifies against. Written as the `ACCESS_TEAM_DOMAIN` and `ACCESS_AUD` vars.",
|
|
153
|
+
"type": "object",
|
|
154
|
+
"additionalProperties": false,
|
|
155
|
+
"required": ["teamDomain", "aud"],
|
|
156
|
+
"properties": {
|
|
157
|
+
"teamDomain": {
|
|
158
|
+
"$ref": "#/$defs/hostname"
|
|
159
|
+
},
|
|
160
|
+
"aud": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"adminEmails": {
|
|
167
|
+
"description": "The deployment's admins: they bypass admission, and a debug Turn may act as one of them. The debug surface itself is gated on `DEBUG_TOKEN`. The installer sets it as the Worker secret `FROCKBOT_ADMIN_EMAILS`; no generated config carries it, which is why the hosted profile leaves it to the repository secret it already has.",
|
|
168
|
+
"type": "array",
|
|
169
|
+
"minItems": 1,
|
|
170
|
+
"items": {
|
|
171
|
+
"$ref": "#/$defs/email"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"d1DatabaseId": {
|
|
175
|
+
"description": "The `AUTH_DB` database. Required by the `better-auth` Package unless the deploy supplies it with `--d1-database-id`, which is how a disposable stage names a database it creates in the same job.",
|
|
176
|
+
"type": "string",
|
|
177
|
+
"pattern": "^[0-9a-fA-F-]{36}$"
|
|
178
|
+
},
|
|
179
|
+
"aiGateway": {
|
|
180
|
+
"description": "The AI Gateway that serves the platform model. Absent, the Worker takes the `AI` binding and Auto resolves to a concrete Workers AI model.",
|
|
181
|
+
"type": "object",
|
|
182
|
+
"additionalProperties": false,
|
|
183
|
+
"required": ["accountId"],
|
|
184
|
+
"properties": {
|
|
185
|
+
"accountId": {
|
|
186
|
+
"description": "The account owning the Gateway. Present with the `FROCK_AI_GATEWAY_TOKEN` secret, requests take the compat HTTP transport \u2014 the only one that accepts a dynamic route.",
|
|
187
|
+
"type": "string",
|
|
188
|
+
"pattern": "^[0-9a-f]{32}$"
|
|
189
|
+
},
|
|
190
|
+
"id": {
|
|
191
|
+
"type": "string",
|
|
192
|
+
"pattern": "^[A-Za-z0-9-]+$"
|
|
193
|
+
},
|
|
194
|
+
"autoRoute": {
|
|
195
|
+
"type": "string",
|
|
196
|
+
"pattern": "^[A-Za-z0-9-]+$"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"nativeAuth": {
|
|
201
|
+
"description": "The native returns this deployment serves: `android`, the released Mac and iPhone apps (`macos`, `ios`), and the FrockBot Dev builds (`macos-dev`, `ios-dev`), each named only where such a build signs in. Nothing is implied by another entry. Absent, the deployment offers no native sign-in at all.",
|
|
202
|
+
"type": "array",
|
|
203
|
+
"minItems": 1,
|
|
204
|
+
"uniqueItems": true,
|
|
205
|
+
"items": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"enum": ["android", "macos", "macos-dev", "ios", "ios-dev"]
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"nativeApps": {
|
|
211
|
+
"description": "The signed native apps this deployment's App Links and Universal Links name, in `/.well-known/assetlinks.json` and `/.well-known/apple-app-site-association`. Written as the `NATIVE_APPS` var. Absent, the deployment serves neither file.",
|
|
212
|
+
"type": "object",
|
|
213
|
+
"additionalProperties": false,
|
|
214
|
+
"properties": {
|
|
215
|
+
"android": {
|
|
216
|
+
"description": "Each Android app by package name, with the SHA-256 fingerprints of the certificates that sign it.",
|
|
217
|
+
"type": "array",
|
|
218
|
+
"minItems": 1,
|
|
219
|
+
"items": {
|
|
220
|
+
"type": "object",
|
|
221
|
+
"additionalProperties": false,
|
|
222
|
+
"required": ["packageName", "sha256CertFingerprints"],
|
|
223
|
+
"properties": {
|
|
224
|
+
"packageName": {
|
|
225
|
+
"type": "string",
|
|
226
|
+
"pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z][A-Za-z0-9_]*)+$"
|
|
227
|
+
},
|
|
228
|
+
"sha256CertFingerprints": {
|
|
229
|
+
"type": "array",
|
|
230
|
+
"minItems": 1,
|
|
231
|
+
"uniqueItems": true,
|
|
232
|
+
"items": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"pattern": "^[0-9A-F]{2}(:[0-9A-F]{2}){31}$"
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"apple": {
|
|
241
|
+
"description": "The Apple app ids (`<team id>.<bundle id>`) the association names for the released Mac and iPhone returns.",
|
|
242
|
+
"type": "array",
|
|
243
|
+
"minItems": 1,
|
|
244
|
+
"uniqueItems": true,
|
|
245
|
+
"items": {
|
|
246
|
+
"type": "string",
|
|
247
|
+
"pattern": "^[A-Z0-9]{10}\\.[A-Za-z0-9.-]+$"
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"email": {
|
|
253
|
+
"description": "Email to and from Bots, both directions on one domain. Each Bot's address is `<bot-slug>.<username>@<domain>`. The domain becomes the app Worker's `EMAIL_DOMAIN` var, which the `email()` handler receives mail for, and the app Worker gains a `send_email` binding named `SEND_EMAIL`, through which each Bot sends from its own address on that domain and no other. Absent, no Bot has an address, every message is refused and nothing is sent. The domain's Email Routing catch-all and its onboarding for Email Sending are set up in Cloudflare by hand: see `apps/cloudflare/deployment-config/README.md`.",
|
|
254
|
+
"type": "object",
|
|
255
|
+
"additionalProperties": false,
|
|
256
|
+
"required": ["domain"],
|
|
257
|
+
"properties": {
|
|
258
|
+
"domain": {
|
|
259
|
+
"$ref": "#/$defs/hostname"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
"resources": {
|
|
264
|
+
"description": "Names that carry identity. Each is derived from `prefix` when absent.",
|
|
265
|
+
"type": "object",
|
|
266
|
+
"additionalProperties": false,
|
|
267
|
+
"properties": {
|
|
268
|
+
"applicationArtifactsBucket": {
|
|
269
|
+
"$ref": "#/$defs/resourceName"
|
|
270
|
+
},
|
|
271
|
+
"memoryFilesBucket": {
|
|
272
|
+
"$ref": "#/$defs/resourceName"
|
|
273
|
+
},
|
|
274
|
+
"memoryIndex": {
|
|
275
|
+
"$ref": "#/$defs/resourceName"
|
|
276
|
+
},
|
|
277
|
+
"authDatabaseName": {
|
|
278
|
+
"$ref": "#/$defs/resourceName"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
"allOf": [
|
|
284
|
+
{
|
|
285
|
+
"if": {
|
|
286
|
+
"properties": {
|
|
287
|
+
"authPackage": {
|
|
288
|
+
"const": "access"
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
"required": ["authPackage"]
|
|
292
|
+
},
|
|
293
|
+
"then": {
|
|
294
|
+
"properties": {
|
|
295
|
+
"access": true
|
|
296
|
+
},
|
|
297
|
+
"required": ["access"]
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"if": {
|
|
302
|
+
"properties": {
|
|
303
|
+
"authPackage": {
|
|
304
|
+
"enum": ["better-auth", "access"]
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
"required": ["authPackage"]
|
|
308
|
+
},
|
|
309
|
+
"then": {
|
|
310
|
+
"properties": {
|
|
311
|
+
"authEnvironment": false
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
"else": {
|
|
315
|
+
"properties": {
|
|
316
|
+
"authEnvironment": true
|
|
317
|
+
},
|
|
318
|
+
"required": ["authEnvironment"]
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
"$defs": {
|
|
323
|
+
"worker": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"additionalProperties": false,
|
|
326
|
+
"properties": {
|
|
327
|
+
"name": {
|
|
328
|
+
"$ref": "#/$defs/resourceName"
|
|
329
|
+
},
|
|
330
|
+
"hostnames": {
|
|
331
|
+
"description": "Custom domains this Worker answers on. Absent, the Worker takes its `workers.dev` hostname, which is what a deployment with no zone has.",
|
|
332
|
+
"type": "array",
|
|
333
|
+
"minItems": 1,
|
|
334
|
+
"items": {
|
|
335
|
+
"$ref": "#/$defs/hostname"
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
"hostname": {
|
|
341
|
+
"type": "string",
|
|
342
|
+
"pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$"
|
|
343
|
+
},
|
|
344
|
+
"email": {
|
|
345
|
+
"type": "string",
|
|
346
|
+
"pattern": "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"
|
|
347
|
+
},
|
|
348
|
+
"resourceName": {
|
|
349
|
+
"type": "string",
|
|
350
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$",
|
|
351
|
+
"maxLength": 63
|
|
352
|
+
},
|
|
353
|
+
"envName": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"pattern": "^[A-Z][A-Z0-9_]*$"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import Ajv from "ajv";
|
|
4
|
+
import {
|
|
5
|
+
DEPLOYMENT_PROFILE_SCHEMA_V1,
|
|
6
|
+
type DeploymentProfileV1 as GeneratedDeploymentProfileV1,
|
|
7
|
+
} from "./profile-schema.generated.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `@frockbot/cloudflare` itself: where the app Worker's tracked wrangler config
|
|
11
|
+
* is, in this repository and in a consumer's `node_modules` alike.
|
|
12
|
+
*/
|
|
13
|
+
export const PACKAGE_ROOT_V1 = join(import.meta.dirname, "..");
|
|
14
|
+
|
|
15
|
+
/** The profile contract, shipped beside the generator that enforces it. */
|
|
16
|
+
export const PROFILE_SCHEMA_FILE_V1 = join(
|
|
17
|
+
import.meta.dirname,
|
|
18
|
+
"profile.schema.json",
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export { DEPLOYMENT_PROFILE_SCHEMA_V1 };
|
|
22
|
+
|
|
23
|
+
type ProfileWithoutAuthV1 = Omit<
|
|
24
|
+
GeneratedDeploymentProfileV1,
|
|
25
|
+
"authPackage" | "access" | "authEnvironment"
|
|
26
|
+
>;
|
|
27
|
+
type AccessApplicationV1 = NonNullable<GeneratedDeploymentProfileV1["access"]>;
|
|
28
|
+
type AuthEnvironmentShapeV1 = NonNullable<
|
|
29
|
+
GeneratedDeploymentProfileV1["authEnvironment"]
|
|
30
|
+
>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A deployment profile, as the schema admits one.
|
|
34
|
+
*
|
|
35
|
+
* `FromSchema` of the schema, with the auth Package's three cases spelled out:
|
|
36
|
+
* `authPackage` may be a path, which `FromSchema` can only read as `string`,
|
|
37
|
+
* and a `string` cannot exclude `"access"` — so the generated type alone would
|
|
38
|
+
* let an Access profile name no Access application. The schema's `allOf` says
|
|
39
|
+
* the same thing to ajv, which is what refuses a profile file.
|
|
40
|
+
*/
|
|
41
|
+
export type DeploymentProfileV1 = ProfileWithoutAuthV1 &
|
|
42
|
+
(
|
|
43
|
+
| {
|
|
44
|
+
authPackage: "better-auth";
|
|
45
|
+
access?: AccessApplicationV1;
|
|
46
|
+
authEnvironment?: never;
|
|
47
|
+
}
|
|
48
|
+
| {
|
|
49
|
+
authPackage: "access";
|
|
50
|
+
access: AccessApplicationV1;
|
|
51
|
+
authEnvironment?: never;
|
|
52
|
+
}
|
|
53
|
+
| {
|
|
54
|
+
authPackage: `./${string}` | `../${string}`;
|
|
55
|
+
access?: AccessApplicationV1;
|
|
56
|
+
authEnvironment: AuthEnvironmentShapeV1;
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
export type DeploymentWorkerV1 = NonNullable<
|
|
61
|
+
NonNullable<DeploymentProfileV1["workers"]>["app"]
|
|
62
|
+
>;
|
|
63
|
+
|
|
64
|
+
export type DeploymentImagesV1 = NonNullable<DeploymentProfileV1["images"]>;
|
|
65
|
+
export type DeploymentRegionV1 = NonNullable<DeploymentProfileV1["region"]>;
|
|
66
|
+
|
|
67
|
+
export const DEPLOYMENT_REGIONS_V1 =
|
|
68
|
+
DEPLOYMENT_PROFILE_SCHEMA_V1.properties.region.enum;
|
|
69
|
+
|
|
70
|
+
export function deploymentRegionV1(value: string): DeploymentRegionV1 {
|
|
71
|
+
if ((DEPLOYMENT_REGIONS_V1 as readonly string[]).includes(value)) {
|
|
72
|
+
return value as DeploymentRegionV1;
|
|
73
|
+
}
|
|
74
|
+
throw new Error(
|
|
75
|
+
`"${value}" is not a deployment region (${DEPLOYMENT_REGIONS_V1.join(", ")})`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The schema is the contract, so it is the thing that refuses a bad profile —
|
|
81
|
+
* not a hand-written check that drifts from it.
|
|
82
|
+
*/
|
|
83
|
+
export function validateProfileV1(value: unknown, what: string): void {
|
|
84
|
+
const schema: unknown = JSON.parse(
|
|
85
|
+
readFileSync(PROFILE_SCHEMA_FILE_V1, "utf8"),
|
|
86
|
+
);
|
|
87
|
+
// Ajv ships a CommonJS default export; under this project's ESM resolution
|
|
88
|
+
// the constructor is one property in.
|
|
89
|
+
const AjvConstructor = ((Ajv as unknown as { default?: typeof Ajv })
|
|
90
|
+
.default ?? Ajv) as typeof Ajv;
|
|
91
|
+
const ajv = new AjvConstructor({ allErrors: true, strict: true });
|
|
92
|
+
const validate = ajv.compile(schema as object);
|
|
93
|
+
if (validate(value)) return;
|
|
94
|
+
const detail = (validate.errors ?? [])
|
|
95
|
+
.map((error) => `${error.instancePath || "/"} ${error.message ?? ""}`)
|
|
96
|
+
.join("; ");
|
|
97
|
+
throw new Error(`${what} is not a deployment profile: ${detail}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** `<profileDirectory>/<name>.json`, validated against the schema. */
|
|
101
|
+
export function loadProfileV1(
|
|
102
|
+
name: string,
|
|
103
|
+
profileDirectory: string,
|
|
104
|
+
): DeploymentProfileV1 {
|
|
105
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(name)) {
|
|
106
|
+
throw new Error(`"${name}" is not a profile name`);
|
|
107
|
+
}
|
|
108
|
+
const file = join(profileDirectory, `${name}.json`);
|
|
109
|
+
let source: string;
|
|
110
|
+
try {
|
|
111
|
+
source = readFileSync(file, "utf8");
|
|
112
|
+
} catch {
|
|
113
|
+
throw new Error(`No deployment profile at ${file}`);
|
|
114
|
+
}
|
|
115
|
+
const profile: unknown = JSON.parse(source);
|
|
116
|
+
validateProfileV1(profile, file);
|
|
117
|
+
const loaded = profile as DeploymentProfileV1;
|
|
118
|
+
if (loaded.name !== name) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`${file} names the profile "${loaded.name}"; a profile's name is its file name`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return loaded;
|
|
124
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
create table "user" ("id" text not null primary key, "name" text not null, "email" text not null unique, "emailVerified" integer not null, "image" text, "createdAt" date not null, "updatedAt" date not null);
|
|
2
|
+
|
|
3
|
+
create table "session" ("id" text not null primary key, "expiresAt" date not null, "token" text not null unique, "createdAt" date not null, "updatedAt" date not null, "ipAddress" text, "userAgent" text, "userId" text not null references "user" ("id") on delete cascade);
|
|
4
|
+
|
|
5
|
+
create table "account" ("id" text not null primary key, "issuer" text not null, "accountId" text not null, "providerId" text not null, "userId" text not null references "user" ("id") on delete cascade, "accessToken" text, "refreshToken" text, "idToken" text, "accessTokenExpiresAt" date, "refreshTokenExpiresAt" date, "scope" text, "password" text, "createdAt" date not null, "updatedAt" date not null);
|
|
6
|
+
|
|
7
|
+
create table "verification" ("id" text not null primary key, "identifier" text not null, "value" text not null, "expiresAt" date not null, "createdAt" date not null, "updatedAt" date not null);
|
|
8
|
+
|
|
9
|
+
create index "session_userId_idx" on "session" ("userId");
|
|
10
|
+
|
|
11
|
+
create index "account_userId_idx" on "account" ("userId");
|
|
12
|
+
|
|
13
|
+
create index "verification_identifier_idx" on "verification" ("identifier");
|
|
14
|
+
|
|
15
|
+
create unique index "account_issuer_accountId_uidx" on "account" ("issuer", "accountId");
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- `account.issuer` belonged to Better Auth 1.7.0 through 1.7.2. From 1.7.3 the
|
|
2
|
+
-- library neither writes it nor looks accounts up by it — it keys on
|
|
3
|
+
-- (providerId, accountId) — and it refuses to serve `/api/auth/*` at all while
|
|
4
|
+
-- a column it never writes is `not null`, so the column and its unique index
|
|
5
|
+
-- have to go rather than be kept nullable.
|
|
6
|
+
drop index if exists "account_issuer_accountId_uidx";
|
|
7
|
+
|
|
8
|
+
alter table "account" drop column "issuer";
|
package/package.json
CHANGED
|
@@ -1,14 +1,70 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/cloudflare",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"license": "
|
|
3
|
+
"version": "0.7.291",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"imports": {
|
|
8
|
+
"#auth-package": "./src/auth-package.ts",
|
|
9
|
+
"#brand": "./src/brand.ts"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"frockbot-deployment-config": "./deployment-config/cli.ts"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"client:build": "bun run build-flutter-web.ts",
|
|
16
|
+
"artifact:build": "bun run client:build && bun run build-artifact.ts",
|
|
17
|
+
"build": "bun run artifact:build && bun ../../scripts/deployment-config.ts hosted && wrangler deploy --dry-run -c ../../.deployment/hosted/app/wrangler.jsonc --outdir dist/gateway",
|
|
18
|
+
"dev": "bun run dev.ts",
|
|
19
|
+
"test": "bun test src && bun run test:workerd",
|
|
20
|
+
"test:workerd": "vitest run --config vitest.config.ts",
|
|
21
|
+
"test:integration": "bun run artifact:build && vitest run --config vitest.integration.config.ts",
|
|
22
|
+
"test:e2e": "playwright test -c e2e/playwright.config.ts",
|
|
23
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.access.json && tsc --noEmit -p test/tsconfig.json && tsc --noEmit -p e2e/tsconfig.json"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@frockbot/app": "0.7.291",
|
|
27
|
+
"@frockbot/applets": "0.7.291",
|
|
28
|
+
"@frockbot/computer": "0.7.291",
|
|
29
|
+
"@frockbot/core": "0.7.291",
|
|
30
|
+
"@frockbot/frock-compose": "0.7.291",
|
|
31
|
+
"@frockbot/providers": "0.7.291",
|
|
32
|
+
"@rive-app/flutter-native-wasm": "44.0.0",
|
|
33
|
+
"agents": "0.24.0",
|
|
34
|
+
"ai": "^7.0.107",
|
|
35
|
+
"ajv": "8.20.0",
|
|
36
|
+
"json-schema-to-ts": "^3.1.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@cloudflare/vitest-plugin": "^1.1.10",
|
|
40
|
+
"@cloudflare/workers-types": "5.20260920.1",
|
|
41
|
+
"@playwright/test": "1.63.0",
|
|
42
|
+
"@types/bun": "1.4.2",
|
|
43
|
+
"typescript": "npm:typescript-native-bridge@6.0.3-bridge.16.tsgo.7.0.2",
|
|
44
|
+
"vitest": "^4.1.0",
|
|
45
|
+
"wrangler": "4.129.0"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"src",
|
|
49
|
+
"deployment-config",
|
|
50
|
+
"migrations",
|
|
51
|
+
"wrangler.jsonc",
|
|
52
|
+
"build-artifact.ts",
|
|
53
|
+
"build-flutter-web.ts",
|
|
54
|
+
"release-version.ts",
|
|
55
|
+
"!**/*.test.ts",
|
|
56
|
+
"!**/*.type-test.ts",
|
|
57
|
+
"!**/tsconfig*.json"
|
|
58
|
+
],
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public"
|
|
61
|
+
},
|
|
6
62
|
"repository": {
|
|
7
63
|
"type": "git",
|
|
8
64
|
"url": "git+https://github.com/timoconnellaus/frockbot.git",
|
|
9
65
|
"directory": "apps/cloudflare"
|
|
10
66
|
},
|
|
11
|
-
"
|
|
12
|
-
"
|
|
67
|
+
"frockbot": {
|
|
68
|
+
"npm": true
|
|
13
69
|
}
|
|
14
70
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The pattern `ClientHello.nativeVersion` accepts, so a release can always say its name. */
|
|
2
|
+
const RELEASE =
|
|
3
|
+
/^(0|[1-9]\d{0,5})\.(0|[1-9]\d{0,5})\.(0|[1-9]\d{0,5})(-[0-9A-Za-z.-]{1,20})?$/u;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The version tag `release.yml` builds, without its `v`, from
|
|
7
|
+
* `FROCKBOT_RELEASE`; null for any other build. Shared by the web client build
|
|
8
|
+
* here and `scripts/native-metadata.ts`, so the two cannot disagree about what
|
|
9
|
+
* a release is called.
|
|
10
|
+
*/
|
|
11
|
+
export function releaseVersion(value: string | undefined) {
|
|
12
|
+
if (value === undefined || value === "") return null;
|
|
13
|
+
const match = RELEASE.exec(value);
|
|
14
|
+
if (!match || value.length > 32) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`FROCKBOT_RELEASE must be a version tag without its \`v\`, such as 0.7.163 or 0.8.0-rc.1, not ${JSON.stringify(value)}.`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return { release: value, versionName: `${match[1]}.${match[2]}.${match[3]}` };
|
|
20
|
+
}
|