the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add topics to sandboxes and persist Notyf

+1362 -27
+4 -1
apps/api/src/schema/sandboxes.ts
··· 9 9 import users from "./users"; 10 10 11 11 const sandboxes = pgTable("sandboxes", { 12 - id: text("id").primaryKey().default(sql`sandbox_id()`), 12 + id: text("id") 13 + .primaryKey() 14 + .default(sql`sandbox_id()`), 13 15 base: text("base"), 14 16 name: text("name").unique().notNull(), 15 17 displayName: text("display_name"), ··· 18 20 repo: text("repo"), 19 21 provider: text("provider").default("cloudflare").notNull(), 20 22 description: text("description"), 23 + topics: text("topics").array(), 21 24 logo: text("logo"), 22 25 publicKey: text("public_key").notNull(), 23 26 readme: text("readme"),
+1
apps/api/src/xrpc/io/pocketenv/sandbox/getSandbox.ts
··· 79 79 provider: data.sandboxes.provider, 80 80 displayName: data.sandboxes.displayName, 81 81 description: data.sandboxes.description, 82 + topics: data.sandboxes.topics, 82 83 baseSandbox: data.sandboxes.base, 83 84 status: data.sandboxes.status, 84 85 repo: data.sandboxes.repo,
+1
apps/cf-sandbox/drizzle/0021_romantic_morlocks.sql
··· 1 + ALTER TABLE "sandboxes" ADD COLUMN "topics" text[];
+1293
apps/cf-sandbox/drizzle/meta/0021_snapshot.json
··· 1 + { 2 + "id": "f478e38d-5ee2-4bb8-bb1f-5fc2b01fce75", 3 + "prevId": "513c9a33-b832-454a-bb41-46e3f792dd24", 4 + "version": "7", 5 + "dialect": "postgresql", 6 + "tables": { 7 + "public.authorized_keys": { 8 + "name": "authorized_keys", 9 + "schema": "", 10 + "columns": { 11 + "id": { 12 + "name": "id", 13 + "type": "text", 14 + "primaryKey": true, 15 + "notNull": true, 16 + "default": "xata_id()" 17 + }, 18 + "sandbox_id": { 19 + "name": "sandbox_id", 20 + "type": "text", 21 + "primaryKey": false, 22 + "notNull": false 23 + }, 24 + "public_key": { 25 + "name": "public_key", 26 + "type": "text", 27 + "primaryKey": false, 28 + "notNull": true 29 + }, 30 + "created_at": { 31 + "name": "created_at", 32 + "type": "timestamp", 33 + "primaryKey": false, 34 + "notNull": true, 35 + "default": "now()" 36 + } 37 + }, 38 + "indexes": {}, 39 + "foreignKeys": { 40 + "authorized_keys_sandbox_id_sandboxes_id_fk": { 41 + "name": "authorized_keys_sandbox_id_sandboxes_id_fk", 42 + "tableFrom": "authorized_keys", 43 + "tableTo": "sandboxes", 44 + "columnsFrom": [ 45 + "sandbox_id" 46 + ], 47 + "columnsTo": [ 48 + "id" 49 + ], 50 + "onDelete": "no action", 51 + "onUpdate": "no action" 52 + } 53 + }, 54 + "compositePrimaryKeys": {}, 55 + "uniqueConstraints": {}, 56 + "policies": {}, 57 + "checkConstraints": {}, 58 + "isRLSEnabled": false 59 + }, 60 + "public.files": { 61 + "name": "files", 62 + "schema": "", 63 + "columns": { 64 + "id": { 65 + "name": "id", 66 + "type": "text", 67 + "primaryKey": true, 68 + "notNull": true, 69 + "default": "variable_id()" 70 + }, 71 + "content": { 72 + "name": "content", 73 + "type": "text", 74 + "primaryKey": false, 75 + "notNull": true 76 + }, 77 + "created_at": { 78 + "name": "created_at", 79 + "type": "timestamp", 80 + "primaryKey": false, 81 + "notNull": true, 82 + "default": "now()" 83 + }, 84 + "updated_at": { 85 + "name": "updated_at", 86 + "type": "timestamp", 87 + "primaryKey": false, 88 + "notNull": true, 89 + "default": "now()" 90 + } 91 + }, 92 + "indexes": {}, 93 + "foreignKeys": {}, 94 + "compositePrimaryKeys": {}, 95 + "uniqueConstraints": {}, 96 + "policies": {}, 97 + "checkConstraints": {}, 98 + "isRLSEnabled": false 99 + }, 100 + "public.sandbox_files": { 101 + "name": "sandbox_files", 102 + "schema": "", 103 + "columns": { 104 + "id": { 105 + "name": "id", 106 + "type": "text", 107 + "primaryKey": true, 108 + "notNull": true, 109 + "default": "xata_id()" 110 + }, 111 + "sandbox_id": { 112 + "name": "sandbox_id", 113 + "type": "text", 114 + "primaryKey": false, 115 + "notNull": true 116 + }, 117 + "file_id": { 118 + "name": "file_id", 119 + "type": "text", 120 + "primaryKey": false, 121 + "notNull": true 122 + }, 123 + "path": { 124 + "name": "path", 125 + "type": "text", 126 + "primaryKey": false, 127 + "notNull": true 128 + }, 129 + "created_at": { 130 + "name": "created_at", 131 + "type": "timestamp", 132 + "primaryKey": false, 133 + "notNull": true, 134 + "default": "now()" 135 + }, 136 + "updated_at": { 137 + "name": "updated_at", 138 + "type": "timestamp", 139 + "primaryKey": false, 140 + "notNull": true, 141 + "default": "now()" 142 + } 143 + }, 144 + "indexes": { 145 + "unique_sandbox_file": { 146 + "name": "unique_sandbox_file", 147 + "columns": [ 148 + { 149 + "expression": "sandbox_id", 150 + "isExpression": false, 151 + "asc": true, 152 + "nulls": "last" 153 + }, 154 + { 155 + "expression": "file_id", 156 + "isExpression": false, 157 + "asc": true, 158 + "nulls": "last" 159 + } 160 + ], 161 + "isUnique": true, 162 + "concurrently": false, 163 + "method": "btree", 164 + "with": {} 165 + }, 166 + "unique_sandbox_file_path": { 167 + "name": "unique_sandbox_file_path", 168 + "columns": [ 169 + { 170 + "expression": "sandbox_id", 171 + "isExpression": false, 172 + "asc": true, 173 + "nulls": "last" 174 + }, 175 + { 176 + "expression": "path", 177 + "isExpression": false, 178 + "asc": true, 179 + "nulls": "last" 180 + } 181 + ], 182 + "isUnique": true, 183 + "concurrently": false, 184 + "method": "btree", 185 + "with": {} 186 + } 187 + }, 188 + "foreignKeys": { 189 + "sandbox_files_sandbox_id_sandboxes_id_fk": { 190 + "name": "sandbox_files_sandbox_id_sandboxes_id_fk", 191 + "tableFrom": "sandbox_files", 192 + "tableTo": "sandboxes", 193 + "columnsFrom": [ 194 + "sandbox_id" 195 + ], 196 + "columnsTo": [ 197 + "id" 198 + ], 199 + "onDelete": "no action", 200 + "onUpdate": "no action" 201 + }, 202 + "sandbox_files_file_id_files_id_fk": { 203 + "name": "sandbox_files_file_id_files_id_fk", 204 + "tableFrom": "sandbox_files", 205 + "tableTo": "files", 206 + "columnsFrom": [ 207 + "file_id" 208 + ], 209 + "columnsTo": [ 210 + "id" 211 + ], 212 + "onDelete": "no action", 213 + "onUpdate": "no action" 214 + } 215 + }, 216 + "compositePrimaryKeys": {}, 217 + "uniqueConstraints": {}, 218 + "policies": {}, 219 + "checkConstraints": {}, 220 + "isRLSEnabled": false 221 + }, 222 + "public.sandbox_secrets": { 223 + "name": "sandbox_secrets", 224 + "schema": "", 225 + "columns": { 226 + "id": { 227 + "name": "id", 228 + "type": "text", 229 + "primaryKey": true, 230 + "notNull": true, 231 + "default": "xata_id()" 232 + }, 233 + "sandbox_id": { 234 + "name": "sandbox_id", 235 + "type": "text", 236 + "primaryKey": false, 237 + "notNull": true 238 + }, 239 + "secret_id": { 240 + "name": "secret_id", 241 + "type": "text", 242 + "primaryKey": false, 243 + "notNull": true 244 + }, 245 + "name": { 246 + "name": "name", 247 + "type": "text", 248 + "primaryKey": false, 249 + "notNull": false 250 + }, 251 + "created_at": { 252 + "name": "created_at", 253 + "type": "timestamp", 254 + "primaryKey": false, 255 + "notNull": true, 256 + "default": "now()" 257 + }, 258 + "updated_at": { 259 + "name": "updated_at", 260 + "type": "timestamp", 261 + "primaryKey": false, 262 + "notNull": true, 263 + "default": "now()" 264 + } 265 + }, 266 + "indexes": { 267 + "unique_sandbox_secret": { 268 + "name": "unique_sandbox_secret", 269 + "columns": [ 270 + { 271 + "expression": "sandbox_id", 272 + "isExpression": false, 273 + "asc": true, 274 + "nulls": "last" 275 + }, 276 + { 277 + "expression": "secret_id", 278 + "isExpression": false, 279 + "asc": true, 280 + "nulls": "last" 281 + } 282 + ], 283 + "isUnique": true, 284 + "concurrently": false, 285 + "method": "btree", 286 + "with": {} 287 + }, 288 + "unique_sandbox_secret_by_name": { 289 + "name": "unique_sandbox_secret_by_name", 290 + "columns": [ 291 + { 292 + "expression": "sandbox_id", 293 + "isExpression": false, 294 + "asc": true, 295 + "nulls": "last" 296 + }, 297 + { 298 + "expression": "name", 299 + "isExpression": false, 300 + "asc": true, 301 + "nulls": "last" 302 + } 303 + ], 304 + "isUnique": true, 305 + "concurrently": false, 306 + "method": "btree", 307 + "with": {} 308 + } 309 + }, 310 + "foreignKeys": { 311 + "sandbox_secrets_sandbox_id_sandboxes_id_fk": { 312 + "name": "sandbox_secrets_sandbox_id_sandboxes_id_fk", 313 + "tableFrom": "sandbox_secrets", 314 + "tableTo": "sandboxes", 315 + "columnsFrom": [ 316 + "sandbox_id" 317 + ], 318 + "columnsTo": [ 319 + "id" 320 + ], 321 + "onDelete": "no action", 322 + "onUpdate": "no action" 323 + }, 324 + "sandbox_secrets_secret_id_secrets_id_fk": { 325 + "name": "sandbox_secrets_secret_id_secrets_id_fk", 326 + "tableFrom": "sandbox_secrets", 327 + "tableTo": "secrets", 328 + "columnsFrom": [ 329 + "secret_id" 330 + ], 331 + "columnsTo": [ 332 + "id" 333 + ], 334 + "onDelete": "no action", 335 + "onUpdate": "no action" 336 + } 337 + }, 338 + "compositePrimaryKeys": {}, 339 + "uniqueConstraints": {}, 340 + "policies": {}, 341 + "checkConstraints": {}, 342 + "isRLSEnabled": false 343 + }, 344 + "public.sandbox_variables": { 345 + "name": "sandbox_variables", 346 + "schema": "", 347 + "columns": { 348 + "id": { 349 + "name": "id", 350 + "type": "text", 351 + "primaryKey": true, 352 + "notNull": true, 353 + "default": "xata_id()" 354 + }, 355 + "sandbox_id": { 356 + "name": "sandbox_id", 357 + "type": "text", 358 + "primaryKey": false, 359 + "notNull": true 360 + }, 361 + "variable_id": { 362 + "name": "variable_id", 363 + "type": "text", 364 + "primaryKey": false, 365 + "notNull": true 366 + }, 367 + "name": { 368 + "name": "name", 369 + "type": "text", 370 + "primaryKey": false, 371 + "notNull": true 372 + }, 373 + "created_at": { 374 + "name": "created_at", 375 + "type": "timestamp", 376 + "primaryKey": false, 377 + "notNull": true, 378 + "default": "now()" 379 + }, 380 + "updated_at": { 381 + "name": "updated_at", 382 + "type": "timestamp", 383 + "primaryKey": false, 384 + "notNull": true, 385 + "default": "now()" 386 + } 387 + }, 388 + "indexes": { 389 + "unique_sandbox_variables": { 390 + "name": "unique_sandbox_variables", 391 + "columns": [ 392 + { 393 + "expression": "sandbox_id", 394 + "isExpression": false, 395 + "asc": true, 396 + "nulls": "last" 397 + }, 398 + { 399 + "expression": "variable_id", 400 + "isExpression": false, 401 + "asc": true, 402 + "nulls": "last" 403 + } 404 + ], 405 + "isUnique": true, 406 + "concurrently": false, 407 + "method": "btree", 408 + "with": {} 409 + }, 410 + "unique_sandbox_variables_by_name": { 411 + "name": "unique_sandbox_variables_by_name", 412 + "columns": [ 413 + { 414 + "expression": "sandbox_id", 415 + "isExpression": false, 416 + "asc": true, 417 + "nulls": "last" 418 + }, 419 + { 420 + "expression": "name", 421 + "isExpression": false, 422 + "asc": true, 423 + "nulls": "last" 424 + } 425 + ], 426 + "isUnique": true, 427 + "concurrently": false, 428 + "method": "btree", 429 + "with": {} 430 + } 431 + }, 432 + "foreignKeys": { 433 + "sandbox_variables_sandbox_id_sandboxes_id_fk": { 434 + "name": "sandbox_variables_sandbox_id_sandboxes_id_fk", 435 + "tableFrom": "sandbox_variables", 436 + "tableTo": "sandboxes", 437 + "columnsFrom": [ 438 + "sandbox_id" 439 + ], 440 + "columnsTo": [ 441 + "id" 442 + ], 443 + "onDelete": "no action", 444 + "onUpdate": "no action" 445 + }, 446 + "sandbox_variables_variable_id_variables_id_fk": { 447 + "name": "sandbox_variables_variable_id_variables_id_fk", 448 + "tableFrom": "sandbox_variables", 449 + "tableTo": "variables", 450 + "columnsFrom": [ 451 + "variable_id" 452 + ], 453 + "columnsTo": [ 454 + "id" 455 + ], 456 + "onDelete": "no action", 457 + "onUpdate": "no action" 458 + } 459 + }, 460 + "compositePrimaryKeys": {}, 461 + "uniqueConstraints": {}, 462 + "policies": {}, 463 + "checkConstraints": {}, 464 + "isRLSEnabled": false 465 + }, 466 + "public.sandbox_volumes": { 467 + "name": "sandbox_volumes", 468 + "schema": "", 469 + "columns": { 470 + "id": { 471 + "name": "id", 472 + "type": "text", 473 + "primaryKey": true, 474 + "notNull": true, 475 + "default": "xata_id()" 476 + }, 477 + "sandbox_id": { 478 + "name": "sandbox_id", 479 + "type": "text", 480 + "primaryKey": false, 481 + "notNull": true 482 + }, 483 + "volume_id": { 484 + "name": "volume_id", 485 + "type": "text", 486 + "primaryKey": false, 487 + "notNull": true 488 + }, 489 + "name": { 490 + "name": "name", 491 + "type": "text", 492 + "primaryKey": false, 493 + "notNull": false 494 + }, 495 + "path": { 496 + "name": "path", 497 + "type": "text", 498 + "primaryKey": false, 499 + "notNull": true 500 + }, 501 + "created_at": { 502 + "name": "created_at", 503 + "type": "timestamp", 504 + "primaryKey": false, 505 + "notNull": true, 506 + "default": "now()" 507 + }, 508 + "updated_at": { 509 + "name": "updated_at", 510 + "type": "timestamp", 511 + "primaryKey": false, 512 + "notNull": true, 513 + "default": "now()" 514 + } 515 + }, 516 + "indexes": { 517 + "unique_sandbox_volume": { 518 + "name": "unique_sandbox_volume", 519 + "columns": [ 520 + { 521 + "expression": "sandbox_id", 522 + "isExpression": false, 523 + "asc": true, 524 + "nulls": "last" 525 + }, 526 + { 527 + "expression": "volume_id", 528 + "isExpression": false, 529 + "asc": true, 530 + "nulls": "last" 531 + } 532 + ], 533 + "isUnique": true, 534 + "concurrently": false, 535 + "method": "btree", 536 + "with": {} 537 + }, 538 + "unique_sandbox_volume_path": { 539 + "name": "unique_sandbox_volume_path", 540 + "columns": [ 541 + { 542 + "expression": "sandbox_id", 543 + "isExpression": false, 544 + "asc": true, 545 + "nulls": "last" 546 + }, 547 + { 548 + "expression": "path", 549 + "isExpression": false, 550 + "asc": true, 551 + "nulls": "last" 552 + } 553 + ], 554 + "isUnique": true, 555 + "concurrently": false, 556 + "method": "btree", 557 + "with": {} 558 + } 559 + }, 560 + "foreignKeys": { 561 + "sandbox_volumes_sandbox_id_sandboxes_id_fk": { 562 + "name": "sandbox_volumes_sandbox_id_sandboxes_id_fk", 563 + "tableFrom": "sandbox_volumes", 564 + "tableTo": "sandboxes", 565 + "columnsFrom": [ 566 + "sandbox_id" 567 + ], 568 + "columnsTo": [ 569 + "id" 570 + ], 571 + "onDelete": "no action", 572 + "onUpdate": "no action" 573 + }, 574 + "sandbox_volumes_volume_id_volumes_id_fk": { 575 + "name": "sandbox_volumes_volume_id_volumes_id_fk", 576 + "tableFrom": "sandbox_volumes", 577 + "tableTo": "volumes", 578 + "columnsFrom": [ 579 + "volume_id" 580 + ], 581 + "columnsTo": [ 582 + "id" 583 + ], 584 + "onDelete": "no action", 585 + "onUpdate": "no action" 586 + } 587 + }, 588 + "compositePrimaryKeys": {}, 589 + "uniqueConstraints": {}, 590 + "policies": {}, 591 + "checkConstraints": {}, 592 + "isRLSEnabled": false 593 + }, 594 + "public.sandboxes": { 595 + "name": "sandboxes", 596 + "schema": "", 597 + "columns": { 598 + "id": { 599 + "name": "id", 600 + "type": "text", 601 + "primaryKey": true, 602 + "notNull": true, 603 + "default": "sandbox_id()" 604 + }, 605 + "base": { 606 + "name": "base", 607 + "type": "text", 608 + "primaryKey": false, 609 + "notNull": false 610 + }, 611 + "name": { 612 + "name": "name", 613 + "type": "text", 614 + "primaryKey": false, 615 + "notNull": true 616 + }, 617 + "display_name": { 618 + "name": "display_name", 619 + "type": "text", 620 + "primaryKey": false, 621 + "notNull": false 622 + }, 623 + "uri": { 624 + "name": "uri", 625 + "type": "text", 626 + "primaryKey": false, 627 + "notNull": false 628 + }, 629 + "cid": { 630 + "name": "cid", 631 + "type": "text", 632 + "primaryKey": false, 633 + "notNull": false 634 + }, 635 + "repo": { 636 + "name": "repo", 637 + "type": "text", 638 + "primaryKey": false, 639 + "notNull": false 640 + }, 641 + "provider": { 642 + "name": "provider", 643 + "type": "text", 644 + "primaryKey": false, 645 + "notNull": true, 646 + "default": "'cloudflare'" 647 + }, 648 + "description": { 649 + "name": "description", 650 + "type": "text", 651 + "primaryKey": false, 652 + "notNull": false 653 + }, 654 + "topics": { 655 + "name": "topics", 656 + "type": "text[]", 657 + "primaryKey": false, 658 + "notNull": false 659 + }, 660 + "logo": { 661 + "name": "logo", 662 + "type": "text", 663 + "primaryKey": false, 664 + "notNull": false 665 + }, 666 + "readme": { 667 + "name": "readme", 668 + "type": "text", 669 + "primaryKey": false, 670 + "notNull": false 671 + }, 672 + "public_key": { 673 + "name": "public_key", 674 + "type": "text", 675 + "primaryKey": false, 676 + "notNull": true 677 + }, 678 + "user_id": { 679 + "name": "user_id", 680 + "type": "text", 681 + "primaryKey": false, 682 + "notNull": false 683 + }, 684 + "instance_type": { 685 + "name": "instance_type", 686 + "type": "text", 687 + "primaryKey": false, 688 + "notNull": false 689 + }, 690 + "vcpus": { 691 + "name": "vcpus", 692 + "type": "integer", 693 + "primaryKey": false, 694 + "notNull": false 695 + }, 696 + "memory": { 697 + "name": "memory", 698 + "type": "integer", 699 + "primaryKey": false, 700 + "notNull": false 701 + }, 702 + "disk": { 703 + "name": "disk", 704 + "type": "integer", 705 + "primaryKey": false, 706 + "notNull": false 707 + }, 708 + "status": { 709 + "name": "status", 710 + "type": "text", 711 + "primaryKey": false, 712 + "notNull": true 713 + }, 714 + "keep_alive": { 715 + "name": "keep_alive", 716 + "type": "boolean", 717 + "primaryKey": false, 718 + "notNull": true, 719 + "default": false 720 + }, 721 + "sleep_after": { 722 + "name": "sleep_after", 723 + "type": "text", 724 + "primaryKey": false, 725 + "notNull": false 726 + }, 727 + "sandbox_id": { 728 + "name": "sandbox_id", 729 + "type": "text", 730 + "primaryKey": false, 731 + "notNull": false 732 + }, 733 + "installs": { 734 + "name": "installs", 735 + "type": "integer", 736 + "primaryKey": false, 737 + "notNull": true, 738 + "default": 0 739 + }, 740 + "started_at": { 741 + "name": "started_at", 742 + "type": "timestamp", 743 + "primaryKey": false, 744 + "notNull": false 745 + }, 746 + "created_at": { 747 + "name": "created_at", 748 + "type": "timestamp", 749 + "primaryKey": false, 750 + "notNull": true, 751 + "default": "now()" 752 + }, 753 + "updated_at": { 754 + "name": "updated_at", 755 + "type": "timestamp", 756 + "primaryKey": false, 757 + "notNull": true, 758 + "default": "now()" 759 + } 760 + }, 761 + "indexes": {}, 762 + "foreignKeys": { 763 + "sandboxes_user_id_users_id_fk": { 764 + "name": "sandboxes_user_id_users_id_fk", 765 + "tableFrom": "sandboxes", 766 + "tableTo": "users", 767 + "columnsFrom": [ 768 + "user_id" 769 + ], 770 + "columnsTo": [ 771 + "id" 772 + ], 773 + "onDelete": "no action", 774 + "onUpdate": "no action" 775 + } 776 + }, 777 + "compositePrimaryKeys": {}, 778 + "uniqueConstraints": { 779 + "sandboxes_name_unique": { 780 + "name": "sandboxes_name_unique", 781 + "nullsNotDistinct": false, 782 + "columns": [ 783 + "name" 784 + ] 785 + }, 786 + "sandboxes_uri_unique": { 787 + "name": "sandboxes_uri_unique", 788 + "nullsNotDistinct": false, 789 + "columns": [ 790 + "uri" 791 + ] 792 + }, 793 + "sandboxes_cid_unique": { 794 + "name": "sandboxes_cid_unique", 795 + "nullsNotDistinct": false, 796 + "columns": [ 797 + "cid" 798 + ] 799 + } 800 + }, 801 + "policies": {}, 802 + "checkConstraints": {}, 803 + "isRLSEnabled": false 804 + }, 805 + "public.secrets": { 806 + "name": "secrets", 807 + "schema": "", 808 + "columns": { 809 + "id": { 810 + "name": "id", 811 + "type": "text", 812 + "primaryKey": true, 813 + "notNull": true, 814 + "default": "secret_id()" 815 + }, 816 + "name": { 817 + "name": "name", 818 + "type": "text", 819 + "primaryKey": false, 820 + "notNull": true 821 + }, 822 + "value": { 823 + "name": "value", 824 + "type": "text", 825 + "primaryKey": false, 826 + "notNull": true 827 + }, 828 + "redacted": { 829 + "name": "redacted", 830 + "type": "text", 831 + "primaryKey": false, 832 + "notNull": false 833 + }, 834 + "created_at": { 835 + "name": "created_at", 836 + "type": "timestamp", 837 + "primaryKey": false, 838 + "notNull": true, 839 + "default": "now()" 840 + } 841 + }, 842 + "indexes": {}, 843 + "foreignKeys": {}, 844 + "compositePrimaryKeys": {}, 845 + "uniqueConstraints": {}, 846 + "policies": {}, 847 + "checkConstraints": {}, 848 + "isRLSEnabled": false 849 + }, 850 + "public.snapshots": { 851 + "name": "snapshots", 852 + "schema": "", 853 + "columns": { 854 + "id": { 855 + "name": "id", 856 + "type": "text", 857 + "primaryKey": true, 858 + "notNull": true, 859 + "default": "snapshot_id()" 860 + }, 861 + "slug": { 862 + "name": "slug", 863 + "type": "text", 864 + "primaryKey": false, 865 + "notNull": true 866 + }, 867 + "created_at": { 868 + "name": "created_at", 869 + "type": "timestamp", 870 + "primaryKey": false, 871 + "notNull": true, 872 + "default": "now()" 873 + } 874 + }, 875 + "indexes": {}, 876 + "foreignKeys": {}, 877 + "compositePrimaryKeys": {}, 878 + "uniqueConstraints": { 879 + "snapshots_slug_unique": { 880 + "name": "snapshots_slug_unique", 881 + "nullsNotDistinct": false, 882 + "columns": [ 883 + "slug" 884 + ] 885 + } 886 + }, 887 + "policies": {}, 888 + "checkConstraints": {}, 889 + "isRLSEnabled": false 890 + }, 891 + "public.users": { 892 + "name": "users", 893 + "schema": "", 894 + "columns": { 895 + "id": { 896 + "name": "id", 897 + "type": "text", 898 + "primaryKey": true, 899 + "notNull": true, 900 + "default": "xata_id()" 901 + }, 902 + "did": { 903 + "name": "did", 904 + "type": "text", 905 + "primaryKey": false, 906 + "notNull": true 907 + }, 908 + "display_name": { 909 + "name": "display_name", 910 + "type": "text", 911 + "primaryKey": false, 912 + "notNull": false 913 + }, 914 + "handle": { 915 + "name": "handle", 916 + "type": "text", 917 + "primaryKey": false, 918 + "notNull": true 919 + }, 920 + "avatar": { 921 + "name": "avatar", 922 + "type": "text", 923 + "primaryKey": false, 924 + "notNull": false 925 + }, 926 + "created_at": { 927 + "name": "created_at", 928 + "type": "timestamp", 929 + "primaryKey": false, 930 + "notNull": true, 931 + "default": "now()" 932 + }, 933 + "updated_at": { 934 + "name": "updated_at", 935 + "type": "timestamp", 936 + "primaryKey": false, 937 + "notNull": true, 938 + "default": "now()" 939 + } 940 + }, 941 + "indexes": {}, 942 + "foreignKeys": {}, 943 + "compositePrimaryKeys": {}, 944 + "uniqueConstraints": { 945 + "users_did_unique": { 946 + "name": "users_did_unique", 947 + "nullsNotDistinct": false, 948 + "columns": [ 949 + "did" 950 + ] 951 + }, 952 + "users_handle_unique": { 953 + "name": "users_handle_unique", 954 + "nullsNotDistinct": false, 955 + "columns": [ 956 + "handle" 957 + ] 958 + } 959 + }, 960 + "policies": {}, 961 + "checkConstraints": {}, 962 + "isRLSEnabled": false 963 + }, 964 + "public.variables": { 965 + "name": "variables", 966 + "schema": "", 967 + "columns": { 968 + "id": { 969 + "name": "id", 970 + "type": "text", 971 + "primaryKey": true, 972 + "notNull": true, 973 + "default": "variable_id()" 974 + }, 975 + "name": { 976 + "name": "name", 977 + "type": "text", 978 + "primaryKey": false, 979 + "notNull": true 980 + }, 981 + "value": { 982 + "name": "value", 983 + "type": "text", 984 + "primaryKey": false, 985 + "notNull": true 986 + }, 987 + "created_at": { 988 + "name": "created_at", 989 + "type": "timestamp", 990 + "primaryKey": false, 991 + "notNull": true, 992 + "default": "now()" 993 + }, 994 + "updated_at": { 995 + "name": "updated_at", 996 + "type": "timestamp", 997 + "primaryKey": false, 998 + "notNull": true, 999 + "default": "now()" 1000 + } 1001 + }, 1002 + "indexes": {}, 1003 + "foreignKeys": {}, 1004 + "compositePrimaryKeys": {}, 1005 + "uniqueConstraints": {}, 1006 + "policies": {}, 1007 + "checkConstraints": {}, 1008 + "isRLSEnabled": false 1009 + }, 1010 + "public.volumes": { 1011 + "name": "volumes", 1012 + "schema": "", 1013 + "columns": { 1014 + "id": { 1015 + "name": "id", 1016 + "type": "text", 1017 + "primaryKey": true, 1018 + "notNull": true, 1019 + "default": "volume_id()" 1020 + }, 1021 + "slug": { 1022 + "name": "slug", 1023 + "type": "text", 1024 + "primaryKey": false, 1025 + "notNull": true 1026 + }, 1027 + "size": { 1028 + "name": "size", 1029 + "type": "integer", 1030 + "primaryKey": false, 1031 + "notNull": true 1032 + }, 1033 + "size_unit": { 1034 + "name": "size_unit", 1035 + "type": "text", 1036 + "primaryKey": false, 1037 + "notNull": true 1038 + }, 1039 + "created_at": { 1040 + "name": "created_at", 1041 + "type": "timestamp", 1042 + "primaryKey": false, 1043 + "notNull": true, 1044 + "default": "now()" 1045 + }, 1046 + "updated_at": { 1047 + "name": "updated_at", 1048 + "type": "timestamp", 1049 + "primaryKey": false, 1050 + "notNull": true, 1051 + "default": "now()" 1052 + } 1053 + }, 1054 + "indexes": {}, 1055 + "foreignKeys": {}, 1056 + "compositePrimaryKeys": {}, 1057 + "uniqueConstraints": { 1058 + "volumes_slug_unique": { 1059 + "name": "volumes_slug_unique", 1060 + "nullsNotDistinct": false, 1061 + "columns": [ 1062 + "slug" 1063 + ] 1064 + } 1065 + }, 1066 + "policies": {}, 1067 + "checkConstraints": {}, 1068 + "isRLSEnabled": false 1069 + }, 1070 + "public.integrations": { 1071 + "name": "integrations", 1072 + "schema": "", 1073 + "columns": { 1074 + "id": { 1075 + "name": "id", 1076 + "type": "text", 1077 + "primaryKey": true, 1078 + "notNull": true, 1079 + "default": "xata_id()" 1080 + }, 1081 + "sandbox_id": { 1082 + "name": "sandbox_id", 1083 + "type": "text", 1084 + "primaryKey": false, 1085 + "notNull": true 1086 + }, 1087 + "name": { 1088 + "name": "name", 1089 + "type": "text", 1090 + "primaryKey": false, 1091 + "notNull": true 1092 + }, 1093 + "description": { 1094 + "name": "description", 1095 + "type": "text", 1096 + "primaryKey": false, 1097 + "notNull": false 1098 + }, 1099 + "webhook_url": { 1100 + "name": "webhook_url", 1101 + "type": "text", 1102 + "primaryKey": false, 1103 + "notNull": true 1104 + }, 1105 + "created_at": { 1106 + "name": "created_at", 1107 + "type": "timestamp", 1108 + "primaryKey": false, 1109 + "notNull": true, 1110 + "default": "now()" 1111 + } 1112 + }, 1113 + "indexes": { 1114 + "unique_sandbox_integration": { 1115 + "name": "unique_sandbox_integration", 1116 + "columns": [ 1117 + { 1118 + "expression": "sandbox_id", 1119 + "isExpression": false, 1120 + "asc": true, 1121 + "nulls": "last" 1122 + }, 1123 + { 1124 + "expression": "name", 1125 + "isExpression": false, 1126 + "asc": true, 1127 + "nulls": "last" 1128 + } 1129 + ], 1130 + "isUnique": true, 1131 + "concurrently": false, 1132 + "method": "btree", 1133 + "with": {} 1134 + } 1135 + }, 1136 + "foreignKeys": { 1137 + "integrations_sandbox_id_sandboxes_id_fk": { 1138 + "name": "integrations_sandbox_id_sandboxes_id_fk", 1139 + "tableFrom": "integrations", 1140 + "tableTo": "sandboxes", 1141 + "columnsFrom": [ 1142 + "sandbox_id" 1143 + ], 1144 + "columnsTo": [ 1145 + "id" 1146 + ], 1147 + "onDelete": "no action", 1148 + "onUpdate": "no action" 1149 + } 1150 + }, 1151 + "compositePrimaryKeys": {}, 1152 + "uniqueConstraints": {}, 1153 + "policies": {}, 1154 + "checkConstraints": {}, 1155 + "isRLSEnabled": false 1156 + }, 1157 + "public.ssh_keys": { 1158 + "name": "ssh_keys", 1159 + "schema": "", 1160 + "columns": { 1161 + "id": { 1162 + "name": "id", 1163 + "type": "text", 1164 + "primaryKey": true, 1165 + "notNull": true, 1166 + "default": "xata_id()" 1167 + }, 1168 + "sandbox_id": { 1169 + "name": "sandbox_id", 1170 + "type": "text", 1171 + "primaryKey": false, 1172 + "notNull": false 1173 + }, 1174 + "public_key": { 1175 + "name": "public_key", 1176 + "type": "text", 1177 + "primaryKey": false, 1178 + "notNull": true 1179 + }, 1180 + "private_key": { 1181 + "name": "private_key", 1182 + "type": "text", 1183 + "primaryKey": false, 1184 + "notNull": true 1185 + }, 1186 + "redacted": { 1187 + "name": "redacted", 1188 + "type": "text", 1189 + "primaryKey": false, 1190 + "notNull": true 1191 + }, 1192 + "created_at": { 1193 + "name": "created_at", 1194 + "type": "timestamp", 1195 + "primaryKey": false, 1196 + "notNull": true, 1197 + "default": "now()" 1198 + } 1199 + }, 1200 + "indexes": {}, 1201 + "foreignKeys": { 1202 + "ssh_keys_sandbox_id_sandboxes_id_fk": { 1203 + "name": "ssh_keys_sandbox_id_sandboxes_id_fk", 1204 + "tableFrom": "ssh_keys", 1205 + "tableTo": "sandboxes", 1206 + "columnsFrom": [ 1207 + "sandbox_id" 1208 + ], 1209 + "columnsTo": [ 1210 + "id" 1211 + ], 1212 + "onDelete": "no action", 1213 + "onUpdate": "no action" 1214 + } 1215 + }, 1216 + "compositePrimaryKeys": {}, 1217 + "uniqueConstraints": {}, 1218 + "policies": {}, 1219 + "checkConstraints": {}, 1220 + "isRLSEnabled": false 1221 + }, 1222 + "public.tailscale_tokens": { 1223 + "name": "tailscale_tokens", 1224 + "schema": "", 1225 + "columns": { 1226 + "id": { 1227 + "name": "id", 1228 + "type": "text", 1229 + "primaryKey": true, 1230 + "notNull": true, 1231 + "default": "xata_id()" 1232 + }, 1233 + "sandbox_id": { 1234 + "name": "sandbox_id", 1235 + "type": "text", 1236 + "primaryKey": false, 1237 + "notNull": false 1238 + }, 1239 + "tokens": { 1240 + "name": "tokens", 1241 + "type": "text", 1242 + "primaryKey": false, 1243 + "notNull": true 1244 + }, 1245 + "redacted": { 1246 + "name": "redacted", 1247 + "type": "text", 1248 + "primaryKey": false, 1249 + "notNull": true 1250 + }, 1251 + "created_at": { 1252 + "name": "created_at", 1253 + "type": "timestamp", 1254 + "primaryKey": false, 1255 + "notNull": true, 1256 + "default": "now()" 1257 + } 1258 + }, 1259 + "indexes": {}, 1260 + "foreignKeys": { 1261 + "tailscale_tokens_sandbox_id_sandboxes_id_fk": { 1262 + "name": "tailscale_tokens_sandbox_id_sandboxes_id_fk", 1263 + "tableFrom": "tailscale_tokens", 1264 + "tableTo": "sandboxes", 1265 + "columnsFrom": [ 1266 + "sandbox_id" 1267 + ], 1268 + "columnsTo": [ 1269 + "id" 1270 + ], 1271 + "onDelete": "no action", 1272 + "onUpdate": "no action" 1273 + } 1274 + }, 1275 + "compositePrimaryKeys": {}, 1276 + "uniqueConstraints": {}, 1277 + "policies": {}, 1278 + "checkConstraints": {}, 1279 + "isRLSEnabled": false 1280 + } 1281 + }, 1282 + "enums": {}, 1283 + "schemas": {}, 1284 + "sequences": {}, 1285 + "roles": {}, 1286 + "policies": {}, 1287 + "views": {}, 1288 + "_meta": { 1289 + "columns": {}, 1290 + "schemas": {}, 1291 + "tables": {} 1292 + } 1293 + }
+7
apps/cf-sandbox/drizzle/meta/_journal.json
··· 148 148 "when": 1773002299756, 149 149 "tag": "0020_striped_kree", 150 150 "breakpoints": true 151 + }, 152 + { 153 + "idx": 21, 154 + "version": "7", 155 + "when": 1773207199352, 156 + "tag": "0021_romantic_morlocks", 157 + "breakpoints": true 151 158 } 152 159 ] 153 160 }
+1
apps/cf-sandbox/src/schema/sandboxes.ts
··· 20 20 repo: text("repo"), 21 21 provider: text("provider").default("cloudflare").notNull(), 22 22 description: text("description"), 23 + topics: text("topics").array(), 23 24 logo: text("logo"), 24 25 readme: text("readme"), 25 26 publicKey: text("public_key").notNull(),
+1
apps/sandbox/src/schema/sandboxes.ts
··· 19 19 repo: text("repo"), 20 20 provider: text("provider").default("cloudflare").notNull(), 21 21 description: text("description"), 22 + topics: text("topics").array(), 22 23 logo: text("logo"), 23 24 readme: text("readme"), 24 25 publicKey: text("public_key").notNull(),
+30 -23
apps/web/src/hooks/useNotyf.ts
··· 1 + import { useRef } from "react"; 1 2 import { Notyf } from "notyf"; 2 3 3 4 export function useNotyf() { 4 - const notyf = new Notyf({ 5 - duration: 3000, 6 - position: { 7 - x: "right", 8 - y: "bottom", 9 - }, 10 - types: [ 11 - { 12 - type: "primary", 13 - background: "var(--color-primary)", 14 - icon: { 15 - className: "icon-[tabler--circle-check] text-white!", 16 - tagName: "i", 5 + const notyfRef = useRef<Notyf | null>(null); 6 + 7 + if (!notyfRef.current) { 8 + notyfRef.current = new Notyf({ 9 + duration: 3000, 10 + position: { 11 + x: "right", 12 + y: "bottom", 13 + }, 14 + types: [ 15 + { 16 + type: "primary", 17 + background: "var(--color-primary)", 18 + icon: { 19 + className: "icon-[tabler--circle-check] text-white!", 20 + tagName: "i", 21 + }, 17 22 }, 18 - }, 19 - { 20 - type: "error", 21 - background: "var(--color-error)", 22 - icon: { 23 - className: "icon-[tabler--circle-x] text-white!", 24 - tagName: "i", 23 + { 24 + type: "error", 25 + background: "var(--color-error)", 26 + icon: { 27 + className: "icon-[tabler--circle-x] text-white!", 28 + tagName: "i", 29 + }, 25 30 }, 26 - }, 27 - ], 28 - }); 31 + ], 32 + }); 33 + } 34 + 35 + const notyf = notyfRef.current; 29 36 30 37 const open = ( 31 38 type: string,
+23 -3
apps/web/src/pages/settings/Settings.tsx
··· 1 1 import { zodResolver } from "@hookform/resolvers/zod"; 2 2 import { useRouterState } from "@tanstack/react-router"; 3 + import { useEffect, useRef } from "react"; 3 4 import { useForm } from "react-hook-form"; 4 5 import { z } from "zod"; 5 6 import { useSandboxQuery } from "../../hooks/useSandbox"; ··· 17 18 18 19 function Settings() { 19 20 const notyf = useNotyf(); 21 + 20 22 const routerState = useRouterState(); 21 23 const pathname = routerState.location.pathname; 22 24 const { data } = useSandboxQuery( 23 25 `at:/${pathname.replace("/settings", "").replace("sandbox", "io.pocketenv.sandbox")}`, 24 26 ); 27 + 28 + const hasReset = useRef(false); 25 29 26 30 const { 27 31 register, 28 32 handleSubmit, 33 + reset, 29 34 formState: { errors }, 30 35 } = useForm<SettingsFormValues>({ 31 36 resolver: zodResolver(settingsSchema), 37 + shouldFocusError: false, 32 38 }); 33 39 40 + useEffect(() => { 41 + if (data?.sandbox && !hasReset.current) { 42 + hasReset.current = true; 43 + reset({ 44 + name: data.sandbox.name, 45 + description: data.sandbox.description || "", 46 + topics: data.sandbox.topics?.join(" "), 47 + }); 48 + } 49 + }, [data, reset]); 50 + 34 51 const onSubmit = (values: SettingsFormValues) => { 35 52 console.log(values); 36 53 notyf.open("primary", "Settings saved successfully!"); ··· 47 64 className="form-control w-[95%] m-auto" 48 65 onSubmit={handleSubmit(onSubmit)} 49 66 > 50 - <label className="label"> 67 + <label className="label" htmlFor="name"> 51 68 <span className="label-text font-bold mb-1 text-[14px]">Name</span> 52 69 </label> 53 70 <div 54 71 className={`input input-bordered w-md input-lg text-[15px] font-semibold bg-transparent ${errors.name ? "input-error" : ""}`} 55 72 > 56 73 <input 74 + id="name" 57 75 type="text" 58 76 className="grow" 59 77 autoComplete="off" ··· 67 85 <p className="text-error text-sm mt-2">{errors.name.message}</p> 68 86 )} 69 87 <div className="mt-8"> 70 - <label className="label"> 88 + <label className="label" htmlFor="description"> 71 89 <span className="label-text font-bold mb-1 text-[14px]"> 72 90 Description 73 91 </span> 74 92 </label> 75 93 <textarea 94 + id="description" 76 95 className="textarea max-w-full h-[150px] text-[14px] font-semibold" 77 96 aria-label="Textarea" 78 97 {...register("description")} 79 98 ></textarea> 80 99 </div> 81 100 <div className="mt-8"> 82 - <label className="label"> 101 + <label className="label" htmlFor="topics"> 83 102 <span className="label-text font-bold mb-1 text-[14px]"> 84 103 Topics 85 104 </span> ··· 88 107 List of topics separated by spaces. 89 108 </span> 90 109 <textarea 110 + id="topics" 91 111 className="textarea max-w-full h-25 text-[14px] font-semibold mt-2" 92 112 aria-label="Textarea" 93 113 {...register("topics")}
+1
apps/web/src/types/sandbox.ts
··· 9 9 displayName: string; 10 10 uri: string; 11 11 description?: string; 12 + topics?: string[]; 12 13 logo?: string; 13 14 readme?: string; 14 15 vcpus?: number;