Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fd676528d | ||
|
|
0a2801444b | ||
|
|
c9adbc7c21 | ||
|
|
ba8de38435 | ||
|
|
8166612467 | ||
|
|
4d20e1c3c6 | ||
|
|
4bb7ea9127 | ||
|
|
969af4d541 | ||
|
|
271b679058 | ||
|
|
83b16cb18e | ||
|
|
431ffc94f5 | ||
|
|
47b4cc6d53 | ||
|
|
ce9b758d0a | ||
|
|
f8a1a0b26f | ||
|
|
6ecaf83f76 | ||
|
|
30b1ae5d4b | ||
|
|
9cd465f9c0 | ||
|
|
1747979568 | ||
|
|
062023fa06 | ||
|
|
954a796b8a | ||
|
|
34ff87d504 | ||
|
|
16357e8041 | ||
|
|
dabb1aa719 | ||
|
|
7af3380455 | ||
|
|
dcaa90808e | ||
|
|
01705fd467 | ||
|
|
006f3bdeb6 | ||
|
|
1d43b4e6d7 | ||
|
|
8cef7940fe | ||
|
|
b2dd9fdfdf | ||
|
|
b82a52cb85 | ||
|
|
7294d86778 | ||
|
|
3bb3f4f2c9 | ||
|
|
d31f97343c | ||
|
|
536d10e5ab | ||
|
|
9885c716f3 | ||
|
|
39461fbbce | ||
|
|
1a2b3701f2 | ||
|
|
0a395d8783 | ||
|
|
79bb22a573 | ||
|
|
4271df96d2 | ||
|
|
aa07be09e1 | ||
|
|
5d6bdca6d0 | ||
|
|
58bbe9e689 | ||
|
|
b5a035ceab | ||
|
|
b3c6d0b08a | ||
|
|
090d27df11 | ||
|
|
b374a6cac9 | ||
|
|
73cd8a334c | ||
|
|
b46c3f2a26 | ||
|
|
45fabec091 | ||
|
|
a96365fd81 | ||
|
|
5f7e1e099b | ||
|
|
d462e380f4 | ||
|
|
c5a558f3da | ||
|
|
7f51b181d4 | ||
|
|
7adbc3ad44 | ||
|
|
89922a8598 | ||
|
|
3a1d1a6284 | ||
|
|
4463d319c9 | ||
|
|
c6eea0343d | ||
|
|
e317e7e481 | ||
|
|
287855336d | ||
|
|
d55f4f3322 | ||
|
|
b708d0ecec | ||
|
|
afb831c93c | ||
|
|
14397651b5 | ||
|
|
e5804f64f9 | ||
|
|
ce7b73170f | ||
|
|
9554abb56e | ||
|
|
d0f5c825bd | ||
|
|
9f603e39a6 | ||
|
|
da51c9dfac | ||
|
|
9e04ff013c | ||
|
|
6bfccace0c | ||
|
|
b25d4f9dfb | ||
|
|
d1962ca5a7 | ||
|
|
25f31f3096 | ||
|
|
11a6f0886e | ||
|
|
3ba7e243d0 | ||
|
|
a2ab019317 | ||
|
|
21957406ff | ||
|
|
61c4747fbe | ||
|
|
957c43aa09 | ||
|
|
96c57418f3 | ||
|
|
b8c51e307f | ||
|
|
6791233ca0 | ||
|
|
cd6072ec58 | ||
|
|
017e42bbcd | ||
|
|
2d20582802 | ||
|
|
2bcc00dbf0 | ||
|
|
e45e94634f | ||
|
|
de1278414f | ||
|
|
3c2803fd9a | ||
|
|
90c2b26733 | ||
|
|
1ea3a8eb9b | ||
|
|
8729edc5e0 | ||
|
|
d8bcf1f5f3 | ||
|
|
67f3c934fe | ||
|
|
065f656fb0 | ||
|
|
f636d937c4 | ||
|
|
492bf51a0d | ||
|
|
81ab127f63 | ||
|
|
6ba7c54bab | ||
|
|
146bae82cb | ||
|
|
ab345cf0da | ||
|
|
a1836527ce | ||
|
|
49e4cfb286 | ||
|
|
e52bfab79d | ||
|
|
cc6d5c8ddd | ||
|
|
afe8508949 | ||
|
|
7c098c8849 | ||
|
|
11d6005b77 | ||
|
|
2cc072b3dc | ||
|
|
86247b8ea9 | ||
|
|
0a5a02043c | ||
|
|
6e553f7e20 |
@@ -20,8 +20,8 @@ jobs:
|
||||
const title = issue.title;
|
||||
const description = issue.body || '';
|
||||
|
||||
// Check for "opencode web" or desktop keywords
|
||||
const webPattern = /(opencode web|\bdesktop\b)/i;
|
||||
// Check for "opencode web" keyword
|
||||
const webPattern = /(opencode web)/i;
|
||||
const isWebRelated = webPattern.test(title) || webPattern.test(description);
|
||||
|
||||
// Check for version patterns like v1.0.x or 1.0.x
|
||||
|
||||
@@ -12,6 +12,10 @@ on:
|
||||
- major
|
||||
- minor
|
||||
- patch
|
||||
version:
|
||||
description: "Override version (optional)"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
@@ -62,6 +66,7 @@ jobs:
|
||||
./script/publish.ts
|
||||
env:
|
||||
OPENCODE_BUMP: ${{ inputs.bump }}
|
||||
OPENCODE_VERSION: ${{ inputs.version }}
|
||||
OPENCODE_CHANNEL: latest
|
||||
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||
|
||||
@@ -21,27 +21,27 @@
|
||||
|
||||
json
|
||||
{
|
||||
"recipient_name": "multi_tool_use.parallel",
|
||||
"parameters": {
|
||||
"tool_uses": [
|
||||
{
|
||||
"recipient_name": "functions.read",
|
||||
"parameters": {
|
||||
"filePath": "path/to/file.tsx"
|
||||
}
|
||||
},
|
||||
{
|
||||
"recipient_name": "functions.read",
|
||||
"parameters": {
|
||||
"filePath": "path/to/file.ts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"recipient_name": "functions.read",
|
||||
"parameters": {
|
||||
"filePath": "path/to/file.md"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"recipient_name": "multi_tool_use.parallel",
|
||||
"parameters": {
|
||||
"tool_uses": [
|
||||
{
|
||||
"recipient_name": "functions.read",
|
||||
"parameters": {
|
||||
"filePath": "path/to/file.tsx"
|
||||
}
|
||||
},
|
||||
{
|
||||
"recipient_name": "functions.read",
|
||||
"parameters": {
|
||||
"filePath": "path/to/file.ts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"recipient_name": "functions.read",
|
||||
"parameters": {
|
||||
"filePath": "path/to/file.md"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,3 +131,6 @@
|
||||
| 2025-11-03 | 653,130 (+9,063) | 597,139 (+7,135) | 1,250,269 (+16,198) |
|
||||
| 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) |
|
||||
| 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) |
|
||||
| 2025-11-06 | 686,252 (+11,178) | 630,885 (+11,195) | 1,317,137 (+22,373) |
|
||||
| 2025-11-07 | 696,646 (+10,394) | 642,146 (+11,261) | 1,338,792 (+21,655) |
|
||||
| 2025-11-08 | 706,035 (+9,389) | 653,489 (+11,343) | 1,359,524 (+20,732) |
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"@tsconfig/bun": "catalog:",
|
||||
"husky": "9.1.7",
|
||||
"prettier": "3.6.2",
|
||||
"sst": "3.17.19",
|
||||
"sst": "3.17.23",
|
||||
"turbo": "2.5.6",
|
||||
},
|
||||
},
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"packages/console/core": {
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
@@ -66,7 +66,7 @@
|
||||
},
|
||||
"packages/console/function": {
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "2.0.0",
|
||||
"@ai-sdk/openai": "2.0.2",
|
||||
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"packages/console/mail": {
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
@@ -106,12 +106,15 @@
|
||||
"@cloudflare/workers-types": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "catalog:",
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
"@types/node": "catalog:",
|
||||
"cloudflare": "5.2.0",
|
||||
},
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -151,7 +154,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
@@ -167,7 +170,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -185,8 +188,8 @@
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opentui/core": "0.1.35",
|
||||
"@opentui/solid": "0.1.35",
|
||||
"@opentui/core": "0.0.0-20251108-0c7899b1",
|
||||
"@opentui/solid": "0.0.0-20251108-0c7899b1",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@pierre/precision-diffs": "catalog:",
|
||||
"@solid-primitives/event-bus": "1.1.2",
|
||||
@@ -245,7 +248,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"zod": "catalog:",
|
||||
@@ -265,7 +268,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.81.0",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -276,7 +279,7 @@
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -289,7 +292,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -319,7 +322,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
@@ -365,7 +368,7 @@
|
||||
"@hono/zod-validator": "0.4.2",
|
||||
"@kobalte/core": "0.13.11",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@pierre/precision-diffs": "0.4.2",
|
||||
"@pierre/precision-diffs": "0.4.4",
|
||||
"@solidjs/meta": "0.29.4",
|
||||
"@tailwindcss/vite": "4.1.11",
|
||||
"@tsconfig/bun": "1.0.9",
|
||||
@@ -962,21 +965,21 @@
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
"@opentui/core": ["@opentui/core@0.1.35", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.35", "@opentui/core-darwin-x64": "0.1.35", "@opentui/core-linux-arm64": "0.1.35", "@opentui/core-linux-x64": "0.1.35", "@opentui/core-win32-arm64": "0.1.35", "@opentui/core-win32-x64": "0.1.35", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-t7xUaie+ri7ROXcWWLrQ0XY0Mo2kH6gqyagZrNRgUjH1zudqPBYJddiw7Kc9LMuPtV8usPzlzjXIny+EzuawkA=="],
|
||||
"@opentui/core": ["@opentui/core@0.0.0-20251108-0c7899b1", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.0.0-20251108-0c7899b1", "@opentui/core-darwin-x64": "0.0.0-20251108-0c7899b1", "@opentui/core-linux-arm64": "0.0.0-20251108-0c7899b1", "@opentui/core-linux-x64": "0.0.0-20251108-0c7899b1", "@opentui/core-win32-arm64": "0.0.0-20251108-0c7899b1", "@opentui/core-win32-x64": "0.0.0-20251108-0c7899b1", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-uJ7wbVw2v5NnL6g3v72SjPLUwMl2wqOejUEo8t4NeBA8nsboSxggqkrqOYf6OOmCADoAqyFDY7akZMsz6HMZtg=="],
|
||||
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.35", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mSu6sS4a8DBejMqr06xtRdLtS+8m4oRzFVNtiKuY1T9PL74SnRmUl3VFxseY19ZMSVVAz/7hHPFX+ttmoT2pEw=="],
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.0.0-20251108-0c7899b1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DS9CmFmZZjwe6PIhz6zhZAsDx11DtyMFDxn8V3On2b8G892aBG6rHYtBBnsM28/1GGEJBTeDQ/jUXPVd6FNJ/g=="],
|
||||
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.35", "", { "os": "darwin", "cpu": "x64" }, "sha512-HqIbf25OSJgsxfe+G6ZvpsGolj1V8yTIXrAUcRSqCmw/Xdp82JqTnI6zx1cxQSllVmF4SxT+WwTRG216DE5MMw=="],
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.0.0-20251108-0c7899b1", "", { "os": "darwin", "cpu": "x64" }, "sha512-K4XwdmT6FTShn7EG8AKliPzO5H59R0XUlZi9+kfRVW59IIJtna5wxbu69SkA28dFoWj5i4yDumwoBI+tI7T6vg=="],
|
||||
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.35", "", { "os": "linux", "cpu": "arm64" }, "sha512-zNZpKg2fxZTsMJAjW3M9Il+1if61oe+d3m98hPm1i/UDtM+Fj8pkU0XBnsIJHfP5GVNnVHuLksXDpqmHquNmOg=="],
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.0.0-20251108-0c7899b1", "", { "os": "linux", "cpu": "arm64" }, "sha512-3JUmxZeSvxV5yU7NEXSecy5Z1/LcVUMy1oWyusZgp96X0CTYAXMrolZt9IJDGO5raeO7JId1UaJmWW0r4DR8TA=="],
|
||||
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.35", "", { "os": "linux", "cpu": "x64" }, "sha512-KKLw9Po+KC0u0JWG9p1bCWKro3dzSg56QQ8Y9CR/wT2ywTatNrtiYeymoeft3BogWSz65PxQr7Dw8kwdUOD3yQ=="],
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.0.0-20251108-0c7899b1", "", { "os": "linux", "cpu": "x64" }, "sha512-i/AQWGyanpPRpk9NK7Ze1tn+d5bqzM9wZFKNB3rd9d2Vbt/ROgBJItG6igz8vzKPKgnlHK4Gw9b5iG5sbjpd+Q=="],
|
||||
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.35", "", { "os": "win32", "cpu": "arm64" }, "sha512-5ycmzf0D8SkaR4xlTZqneegFt4w4RK2Q9yZC3ZiAclNMtffVnWOkK/3zIpCwTdi2I1wHPVG0doX6pi0EUM7f2A=="],
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.0.0-20251108-0c7899b1", "", { "os": "win32", "cpu": "arm64" }, "sha512-C7JLWuNN3w2txiVx3demwNwogVi4DQB5ZNHy2b09++kd2m449/RwGPyLcKpuoTzU4s/usYOeY4TxKIAd8cKedQ=="],
|
||||
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.35", "", { "os": "win32", "cpu": "x64" }, "sha512-m/l9NkzT/asdpPPN0525z5JcYiHc++feIisqmHS1+IfqirTDuReyKk7HxU3MydxrFcsp1LBMCxFipWiYV2V9hw=="],
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.0.0-20251108-0c7899b1", "", { "os": "win32", "cpu": "x64" }, "sha512-mpOryp37YaHlTsN70LhiSn9hJJBktbyhlH/eB3N2K7H1ANYQVrekgBJ3rDxlH1GDVtRz6vLS3IDlyK75qNX4pg=="],
|
||||
|
||||
"@opentui/solid": ["@opentui/solid@0.1.35", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.35", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-VIhPmnZstthNpDWZzouOE6YzEnLHI3HbuT9wL6wf0K7Fp0kJEGUA7dlYscSpX9ZBY15B7COnIkSagC/C7hUQkw=="],
|
||||
"@opentui/solid": ["@opentui/solid@0.0.0-20251108-0c7899b1", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.0.0-20251108-0c7899b1", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-tcsYnFGH/KBlQNG0IyZE2bisnm5NwN/w7theuWga3L1zoXqZqA5dQHutAVg4zkq5l/YKULeDI4jBlvz0lzH88A=="],
|
||||
|
||||
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
|
||||
|
||||
@@ -1034,7 +1037,7 @@
|
||||
|
||||
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
|
||||
|
||||
"@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.2", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/transformers": "3.14.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.14.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-C6LbruH24BCp4awI47D5iMtVaZZD6GkzqBoDw+Sfu7DB3hC9y/rZr1C2BD7AUzAKwByTfFnh16Zp11ipfPqLKw=="],
|
||||
"@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.4", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/transformers": "3.14.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.14.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-9bhWs+hsz1i0/SMIrzce+fFrSec8aLIFrJYTGHATlynmQovngIWz1Gc+XwGigvY4+zSMksrGPzO5HiaNlvRqtQ=="],
|
||||
|
||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||
|
||||
@@ -1432,6 +1435,8 @@
|
||||
|
||||
"@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="],
|
||||
|
||||
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
|
||||
|
||||
"@types/promise.allsettled": ["@types/promise.allsettled@1.0.6", "", {}, "sha512-wA0UT0HeT2fGHzIFV9kWpYz5mdoyLxKrTgMdZQM++5h6pYAFH73HXcQhefg24nD1yivUFEn5KU+EF4b+CXJ4Wg=="],
|
||||
|
||||
"@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="],
|
||||
@@ -1518,6 +1523,8 @@
|
||||
|
||||
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
|
||||
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
||||
|
||||
"ai": ["ai@5.0.8", "", { "dependencies": { "@ai-sdk/gateway": "1.0.4", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.1", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-qbnhj046UvG30V1S5WhjBn+RBGEAmi8PSZWqMhRsE3EPxvO5BcePXTZFA23e9MYyWS9zr4Vm8Mv3wQXwLmtIBw=="],
|
||||
|
||||
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
@@ -1742,6 +1749,8 @@
|
||||
|
||||
"clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="],
|
||||
|
||||
"cloudflare": ["cloudflare@5.2.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-dVzqDpPFYR9ApEC9e+JJshFJZXcw4HzM8W+3DHzO5oy9+8rLC53G7x6fEf9A7/gSuSCxuvndzui5qJKftfIM9A=="],
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
|
||||
"cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="],
|
||||
@@ -2068,7 +2077,11 @@
|
||||
|
||||
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||
|
||||
"form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="],
|
||||
"form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
|
||||
|
||||
"form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="],
|
||||
|
||||
"formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="],
|
||||
|
||||
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||
|
||||
@@ -2258,6 +2271,8 @@
|
||||
|
||||
"human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
|
||||
|
||||
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
|
||||
|
||||
"husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="],
|
||||
|
||||
"i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="],
|
||||
@@ -2716,6 +2731,8 @@
|
||||
|
||||
"node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="],
|
||||
|
||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||
|
||||
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||
|
||||
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
|
||||
@@ -3178,23 +3195,23 @@
|
||||
|
||||
"sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="],
|
||||
|
||||
"sst": ["sst@3.17.19", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.19", "sst-darwin-x64": "3.17.19", "sst-linux-arm64": "3.17.19", "sst-linux-x64": "3.17.19", "sst-linux-x86": "3.17.19", "sst-win32-arm64": "3.17.19", "sst-win32-x64": "3.17.19", "sst-win32-x86": "3.17.19" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-j0FlQhFZW+QWCczzqfPr6fZAF0Um7lP1tbGdd7zkbjFlxdk9BUBI4CYXUnopC6KaTMtjvpfg3XRF7v0bDc9g+A=="],
|
||||
"sst": ["sst@3.17.23", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.23", "sst-darwin-x64": "3.17.23", "sst-linux-arm64": "3.17.23", "sst-linux-x64": "3.17.23", "sst-linux-x86": "3.17.23", "sst-win32-arm64": "3.17.23", "sst-win32-x64": "3.17.23", "sst-win32-x86": "3.17.23" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-TwKgUgDnZdc1Swe+bvCNeyO4dQnYz5cTodMpYj3jlXZdK9/KNz0PVxT1f0u5E76i1pmilXrUBL/f7iiMPw4RDg=="],
|
||||
|
||||
"sst-darwin-arm64": ["sst-darwin-arm64@3.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6FeEgPqXkRT3o5qV0xktJ1eUiscJiPLBcGaxOxIEClpkVggZM83hO7Nizx/cAaAMhr1XQhbOZcKYueDHPdUY+Q=="],
|
||||
"sst-darwin-arm64": ["sst-darwin-arm64@3.17.23", "", { "os": "darwin", "cpu": "arm64" }, "sha512-R6kvmF+rUideOoU7KBs2SdvrIupoE+b+Dor/eq9Uo4Dojj7KvYDZI/EDm8sSCbbcx/opiWeyNqKtlnLEdCxE6g=="],
|
||||
|
||||
"sst-darwin-x64": ["sst-darwin-x64@3.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-/z78dxfLHG8FtOhpjMnYSpKSdQjfdyKbq+cL3eud2+g2BQr7IyQ8BWNGimk2oadh38V3r6dO1/5aVJh3x3l1rg=="],
|
||||
"sst-darwin-x64": ["sst-darwin-x64@3.17.23", "", { "os": "darwin", "cpu": "x64" }, "sha512-WW4P1S35iYCifQXxD+sE3wuzcN+LHLpuKMaNoaBqEcWGZnH3IPaDJ7rpLF0arkDAo/z3jZmWWzOCkr0JuqJ8vQ=="],
|
||||
|
||||
"sst-linux-arm64": ["sst-linux-arm64@3.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-vbcMjiuLVxZ7352ajGlMqsS4J5AkAYvjLmsEALySUBVQhJUO9U7pk2P+Orfn702ZcO+6+NkGG9AL/g3K9EM1Tg=="],
|
||||
"sst-linux-arm64": ["sst-linux-arm64@3.17.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-TjtNqgIh7RlAWgPLFCAt0mXvIB+J7WjmRvIRrAdX0mXsndOiBJ/DMOgXSLVsIWHCfPj8MIEot/hWpnJgXgIeag=="],
|
||||
|
||||
"sst-linux-x64": ["sst-linux-x64@3.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-gkNNmuHyvKjcb7RwMyoUH4wtgd7/bH7vUlMbcVsDzwt38y7+iTxyPMbcihucw42wDQRaDJtkDneSqj08U+MTFQ=="],
|
||||
"sst-linux-x64": ["sst-linux-x64@3.17.23", "", { "os": "linux", "cpu": "x64" }, "sha512-qdqJiEbYfCjZlI3F/TA6eoIU7JXVkEEI/UMILNf2JWhky0KQdCW2Xyz+wb6c0msVJCWdUM/uj+1DaiP2eXvghw=="],
|
||||
|
||||
"sst-linux-x86": ["sst-linux-x86@3.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-Bsvunkh4onZRVv4Rxq7bT/63qQOg2KJoQKhAQtFkJdbri/cOA2QWkzqH8+pC5Sv9rSvbcIJAEIhMXILC0pqCJw=="],
|
||||
"sst-linux-x86": ["sst-linux-x86@3.17.23", "", { "os": "linux", "cpu": "none" }, "sha512-aGmUujIvoNlmAABEGsOgfY1rxD9koC6hN8bnTLbDI+oI/u/zjHYh50jsbL0p3TlaHpwF/lxP3xFSuT6IKp+KgA=="],
|
||||
|
||||
"sst-win32-arm64": ["sst-win32-arm64@3.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-dKxR4v24AODJLHiT9yNena0JUgyz3cHyCi6HZyxyG3dXyWncMe1ZXMXIgs1ZEUcU4XeYM2HVy+Nnz4KB1US1Kg=="],
|
||||
"sst-win32-arm64": ["sst-win32-arm64@3.17.23", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZxdkGqYDrrZGz98rijDCN+m5yuCcwD6Bc9/6hubLsvdpNlVorUqzpg801Ec97xSK0nIC9g6pNiRyxAcsQQstUg=="],
|
||||
|
||||
"sst-win32-x64": ["sst-win32-x64@3.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-zgxSkGWZ1dewAr4R3slN/d3X9yumQDvAUOlJiX/6QE9Z67t/XNlow4+5i3L2oz4WHAFi59Un12YxbfM+RsBDmA=="],
|
||||
"sst-win32-x64": ["sst-win32-x64@3.17.23", "", { "os": "win32", "cpu": "x64" }, "sha512-yc9cor4MS49Ccy2tQCF1tf6M81yLeSGzGL+gjhUxpVKo2pN3bxl3w70eyU/mTXSEeyAmG9zEfbt6FNu4sy5cUA=="],
|
||||
|
||||
"sst-win32-x86": ["sst-win32-x86@3.17.19", "", { "os": "win32", "cpu": "none" }, "sha512-z8S0kyb0ibz9Q3cNYDpcKYX47jys7j/mdebC8HUhtED1qKEAfqQ1vsR+zvWyN64Z9Ijj7aPi1KwNV6Et3d7F8g=="],
|
||||
"sst-win32-x86": ["sst-win32-x86@3.17.23", "", { "os": "win32", "cpu": "none" }, "sha512-DIp3s54IpNAfdYjSRt6McvkbEPQDMxUu6RUeRAd2C+FcTJgTloon/ghAPQBaDgu2VoVgymjcJARO/XyfKcCLOQ=="],
|
||||
|
||||
"stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="],
|
||||
|
||||
@@ -3480,6 +3497,8 @@
|
||||
|
||||
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
|
||||
|
||||
"web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="],
|
||||
|
||||
"web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||
@@ -3754,6 +3773,8 @@
|
||||
|
||||
"@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="],
|
||||
|
||||
"@slack/web-api/form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="],
|
||||
|
||||
"@slack/web-api/p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="],
|
||||
|
||||
"@solidjs/start/shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="],
|
||||
@@ -3814,8 +3835,6 @@
|
||||
|
||||
"astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"axios/form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
|
||||
|
||||
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
|
||||
|
||||
"babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="],
|
||||
@@ -4350,6 +4369,8 @@
|
||||
|
||||
"@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
|
||||
|
||||
"@slack/web-api/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
|
||||
|
||||
"@slack/web-api/p-queue/p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="],
|
||||
@@ -4402,8 +4423,6 @@
|
||||
|
||||
"astro/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
|
||||
|
||||
"axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="],
|
||||
|
||||
"babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="],
|
||||
@@ -4700,6 +4719,8 @@
|
||||
|
||||
"@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
||||
|
||||
"@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="],
|
||||
|
||||
"@vercel/nft/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
@@ -4708,8 +4729,6 @@
|
||||
|
||||
"archiver-utils/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"axios/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||
|
||||
+14
-43
@@ -171,9 +171,7 @@ try {
|
||||
const summary = await summarize(response)
|
||||
await pushToLocalBranch(summary)
|
||||
}
|
||||
const hasShared = prData.comments.nodes.some((c) =>
|
||||
c.body.includes(`${useShareUrl()}/s/${shareId}`),
|
||||
)
|
||||
const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${useShareUrl()}/s/${shareId}`))
|
||||
await updateComment(`${response}${footer({ image: !hasShared })}`)
|
||||
}
|
||||
// Fork PR
|
||||
@@ -185,9 +183,7 @@ try {
|
||||
const summary = await summarize(response)
|
||||
await pushToForkBranch(summary, prData)
|
||||
}
|
||||
const hasShared = prData.comments.nodes.some((c) =>
|
||||
c.body.includes(`${useShareUrl()}/s/${shareId}`),
|
||||
)
|
||||
const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${useShareUrl()}/s/${shareId}`))
|
||||
await updateComment(`${response}${footer({ image: !hasShared })}`)
|
||||
}
|
||||
}
|
||||
@@ -368,9 +364,7 @@ async function getAccessToken() {
|
||||
|
||||
if (!response.ok) {
|
||||
const responseJson = (await response.json()) as { error?: string }
|
||||
throw new Error(
|
||||
`App token exchange failed: ${response.status} ${response.statusText} - ${responseJson.error}`,
|
||||
)
|
||||
throw new Error(`App token exchange failed: ${response.status} ${response.statusText} - ${responseJson.error}`)
|
||||
}
|
||||
|
||||
const responseJson = (await response.json()) as { token: string }
|
||||
@@ -411,12 +405,8 @@ async function getUserPrompt() {
|
||||
// ie. <img alt="Image" src="https://github.com/user-attachments/assets/xxxx" />
|
||||
// ie. [api.json](https://github.com/user-attachments/files/21433810/api.json)
|
||||
// ie. 
|
||||
const mdMatches = prompt.matchAll(
|
||||
/!?\[.*?\]\((https:\/\/github\.com\/user-attachments\/[^)]+)\)/gi,
|
||||
)
|
||||
const tagMatches = prompt.matchAll(
|
||||
/<img .*?src="(https:\/\/github\.com\/user-attachments\/[^"]+)" \/>/gi,
|
||||
)
|
||||
const mdMatches = prompt.matchAll(/!?\[.*?\]\((https:\/\/github\.com\/user-attachments\/[^)]+)\)/gi)
|
||||
const tagMatches = prompt.matchAll(/<img .*?src="(https:\/\/github\.com\/user-attachments\/[^"]+)" \/>/gi)
|
||||
const matches = [...mdMatches, ...tagMatches].sort((a, b) => a.index - b.index)
|
||||
console.log("Images", JSON.stringify(matches, null, 2))
|
||||
|
||||
@@ -443,8 +433,7 @@ async function getUserPrompt() {
|
||||
|
||||
// Replace img tag with file path, ie. @image.png
|
||||
const replacement = `@${filename}`
|
||||
prompt =
|
||||
prompt.slice(0, start + offset) + replacement + prompt.slice(start + offset + tag.length)
|
||||
prompt = prompt.slice(0, start + offset) + replacement + prompt.slice(start + offset + tag.length)
|
||||
offset += replacement.length - tag.length
|
||||
|
||||
const contentType = res.headers.get("content-type")
|
||||
@@ -512,12 +501,7 @@ async function subscribeSessionEvents() {
|
||||
? JSON.stringify(part.state.input)
|
||||
: "Unknown"
|
||||
console.log()
|
||||
console.log(
|
||||
color + `|`,
|
||||
"\x1b[0m\x1b[2m" + ` ${tool.padEnd(7, " ")}`,
|
||||
"",
|
||||
"\x1b[0m" + title,
|
||||
)
|
||||
console.log(color + `|`, "\x1b[0m\x1b[2m" + ` ${tool.padEnd(7, " ")}`, "", "\x1b[0m" + title)
|
||||
}
|
||||
|
||||
if (part.type === "text") {
|
||||
@@ -729,8 +713,7 @@ async function assertPermissions() {
|
||||
throw new Error(`Failed to check permissions for user ${actor}: ${error}`)
|
||||
}
|
||||
|
||||
if (!["admin", "write"].includes(permission))
|
||||
throw new Error(`User ${actor} does not have write permissions`)
|
||||
if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)
|
||||
}
|
||||
|
||||
async function updateComment(body: string) {
|
||||
@@ -774,9 +757,7 @@ function footer(opts?: { image?: boolean }) {
|
||||
|
||||
return `<a href="${useShareUrl()}/s/${shareId}"><img width="200" alt="${titleAlt}" src="https://social-cards.sst.dev/opencode-share/${title64}.png?model=${providerID}/${modelID}&version=${session.version}&id=${shareId}" /></a>\n`
|
||||
})()
|
||||
const shareUrl = shareId
|
||||
? `[opencode session](${useShareUrl()}/s/${shareId}) | `
|
||||
: ""
|
||||
const shareUrl = shareId ? `[opencode session](${useShareUrl()}/s/${shareId}) | ` : ""
|
||||
return `\n\n${image}${shareUrl}[github run](${useEnvRunUrl()})`
|
||||
}
|
||||
|
||||
@@ -959,13 +940,9 @@ function buildPromptDataForPR(pr: GitHubPullRequest) {
|
||||
})
|
||||
.map((c) => `- ${c.author.login} at ${c.createdAt}: ${c.body}`)
|
||||
|
||||
const files = (pr.files.nodes || []).map(
|
||||
(f) => `- ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`,
|
||||
)
|
||||
const files = (pr.files.nodes || []).map((f) => `- ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`)
|
||||
const reviewData = (pr.reviews.nodes || []).map((r) => {
|
||||
const comments = (r.comments.nodes || []).map(
|
||||
(c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`,
|
||||
)
|
||||
const comments = (r.comments.nodes || []).map((c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`)
|
||||
return [
|
||||
`- ${r.author.login} at ${r.submittedAt}:`,
|
||||
` - Review body: ${r.body}`,
|
||||
@@ -987,15 +964,9 @@ function buildPromptDataForPR(pr: GitHubPullRequest) {
|
||||
`Deletions: ${pr.deletions}`,
|
||||
`Total Commits: ${pr.commits.totalCount}`,
|
||||
`Changed Files: ${pr.files.nodes.length} files`,
|
||||
...(comments.length > 0
|
||||
? ["<pull_request_comments>", ...comments, "</pull_request_comments>"]
|
||||
: []),
|
||||
...(files.length > 0
|
||||
? ["<pull_request_changed_files>", ...files, "</pull_request_changed_files>"]
|
||||
: []),
|
||||
...(reviewData.length > 0
|
||||
? ["<pull_request_reviews>", ...reviewData, "</pull_request_reviews>"]
|
||||
: []),
|
||||
...(comments.length > 0 ? ["<pull_request_comments>", ...comments, "</pull_request_comments>"] : []),
|
||||
...(files.length > 0 ? ["<pull_request_changed_files>", ...files, "</pull_request_changed_files>"] : []),
|
||||
...(reviewData.length > 0 ? ["<pull_request_reviews>", ...reviewData, "</pull_request_reviews>"] : []),
|
||||
"</pull_request>",
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -6,4 +6,4 @@
|
||||
/// <reference path="../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
export {}
|
||||
|
||||
+9
-7
@@ -61,13 +61,7 @@ export const auth = new sst.cloudflare.Worker("AuthApi", {
|
||||
domain: `auth.${domain}`,
|
||||
handler: "packages/console/function/src/auth.ts",
|
||||
url: true,
|
||||
link: [
|
||||
database,
|
||||
authStorage,
|
||||
GITHUB_CLIENT_ID_CONSOLE,
|
||||
GITHUB_CLIENT_SECRET_CONSOLE,
|
||||
GOOGLE_CLIENT_ID,
|
||||
],
|
||||
link: [database, authStorage, GITHUB_CLIENT_ID_CONSOLE, GITHUB_CLIENT_SECRET_CONSOLE, GOOGLE_CLIENT_ID],
|
||||
})
|
||||
|
||||
////////////////
|
||||
@@ -112,6 +106,7 @@ const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
|
||||
const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", {
|
||||
properties: { value: stripeWebhook.secret },
|
||||
})
|
||||
const gatewayKv = new sst.cloudflare.Kv("GatewayKv")
|
||||
|
||||
////////////////
|
||||
// CONSOLE
|
||||
@@ -142,6 +137,13 @@ new sst.cloudflare.x.SolidStart("Console", {
|
||||
EMAILOCTOPUS_API_KEY,
|
||||
AWS_SES_ACCESS_KEY_ID,
|
||||
AWS_SES_SECRET_ACCESS_KEY,
|
||||
...($dev
|
||||
? [
|
||||
new sst.Secret("CLOUDFLARE_DEFAULT_ACCOUNT_ID", process.env.CLOUDFLARE_DEFAULT_ACCOUNT_ID!),
|
||||
new sst.Secret("CLOUDFLARE_API_TOKEN", process.env.CLOUDFLARE_API_TOKEN!),
|
||||
]
|
||||
: []),
|
||||
gatewayKv,
|
||||
],
|
||||
environment: {
|
||||
//VITE_DOCS_URL: web.url.apply((url) => url!),
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"keep": {
|
||||
"days": true,
|
||||
"amount": 14
|
||||
},
|
||||
"auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json",
|
||||
"files": [
|
||||
{
|
||||
"date": 1759827172859,
|
||||
"name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log",
|
||||
"hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16"
|
||||
}
|
||||
],
|
||||
"hashType": "sha256"
|
||||
}
|
||||
"keep": {
|
||||
"days": true,
|
||||
"amount": 14
|
||||
},
|
||||
"auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json",
|
||||
"files": [
|
||||
{
|
||||
"date": 1759827172859,
|
||||
"name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log",
|
||||
"hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16"
|
||||
}
|
||||
],
|
||||
"hashType": "sha256"
|
||||
}
|
||||
|
||||
+3
-3
@@ -28,7 +28,7 @@
|
||||
"@tsconfig/bun": "1.0.9",
|
||||
"@cloudflare/workers-types": "4.20251008.0",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@pierre/precision-diffs": "0.4.2",
|
||||
"@pierre/precision-diffs": "0.4.4",
|
||||
"@solidjs/meta": "0.29.4",
|
||||
"@tailwindcss/vite": "4.1.11",
|
||||
"diff": "8.0.2",
|
||||
@@ -52,7 +52,7 @@
|
||||
"@tsconfig/bun": "catalog:",
|
||||
"husky": "9.1.7",
|
||||
"prettier": "3.6.2",
|
||||
"sst": "3.17.19",
|
||||
"sst": "3.17.23",
|
||||
"turbo": "2.5.6"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -66,7 +66,7 @@
|
||||
"license": "MIT",
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 100
|
||||
"printWidth": 120
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"esbuild",
|
||||
|
||||
@@ -23,6 +23,9 @@ app.config.timestamp_*.js
|
||||
# Temp
|
||||
gitignore
|
||||
|
||||
# Generated files
|
||||
public/sitemap.xml
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"dev": "vinxi dev --host 0.0.0.0",
|
||||
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
|
||||
"build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json",
|
||||
"build": "./script/generate-sitemap.ts && vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json",
|
||||
"start": "vinxi start",
|
||||
"version": "1.0.32"
|
||||
"version": "1.0.48"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ibm/plex": "6.4.1",
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env bun
|
||||
import { readdir, writeFile } from "fs/promises"
|
||||
import { join, dirname } from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import { config } from "../src/config.js"
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const BASE_URL = config.baseUrl
|
||||
const PUBLIC_DIR = join(__dirname, "../public")
|
||||
const ROUTES_DIR = join(__dirname, "../src/routes")
|
||||
const DOCS_DIR = join(__dirname, "../../../web/src/content/docs")
|
||||
|
||||
interface SitemapEntry {
|
||||
url: string
|
||||
priority: number
|
||||
changefreq: string
|
||||
}
|
||||
|
||||
async function getMainRoutes(): Promise<SitemapEntry[]> {
|
||||
const routes: SitemapEntry[] = []
|
||||
|
||||
// Add main static routes
|
||||
const staticRoutes = [
|
||||
{ path: "/", priority: 1.0, changefreq: "daily" },
|
||||
{ path: "/enterprise", priority: 0.8, changefreq: "weekly" },
|
||||
{ path: "/brand", priority: 0.6, changefreq: "monthly" },
|
||||
{ path: "/zen", priority: 0.8, changefreq: "weekly" },
|
||||
]
|
||||
|
||||
for (const route of staticRoutes) {
|
||||
routes.push({
|
||||
url: `${BASE_URL}${route.path}`,
|
||||
priority: route.priority,
|
||||
changefreq: route.changefreq,
|
||||
})
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
async function getDocsRoutes(): Promise<SitemapEntry[]> {
|
||||
const routes: SitemapEntry[] = []
|
||||
|
||||
try {
|
||||
const files = await readdir(DOCS_DIR)
|
||||
|
||||
for (const file of files) {
|
||||
if (!file.endsWith(".mdx")) continue
|
||||
|
||||
const slug = file.replace(".mdx", "")
|
||||
const path = slug === "index" ? "/docs/" : `/docs/${slug}`
|
||||
|
||||
routes.push({
|
||||
url: `${BASE_URL}${path}`,
|
||||
priority: slug === "index" ? 0.9 : 0.7,
|
||||
changefreq: "weekly",
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error reading docs directory:", error)
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
function generateSitemapXML(entries: SitemapEntry[]): string {
|
||||
const urls = entries
|
||||
.map(
|
||||
(entry) => ` <url>
|
||||
<loc>${entry.url}</loc>
|
||||
<changefreq>${entry.changefreq}</changefreq>
|
||||
<priority>${entry.priority}</priority>
|
||||
</url>`,
|
||||
)
|
||||
.join("\n")
|
||||
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
${urls}
|
||||
</urlset>`
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("Generating sitemap...")
|
||||
|
||||
const mainRoutes = await getMainRoutes()
|
||||
const docsRoutes = await getDocsRoutes()
|
||||
|
||||
const allRoutes = [...mainRoutes, ...docsRoutes]
|
||||
|
||||
console.log(`Found ${mainRoutes.length} main routes`)
|
||||
console.log(`Found ${docsRoutes.length} docs routes`)
|
||||
console.log(`Total: ${allRoutes.length} routes`)
|
||||
|
||||
const xml = generateSitemapXML(allRoutes)
|
||||
|
||||
const outputPath = join(PUBLIC_DIR, "sitemap.xml")
|
||||
await writeFile(outputPath, xml, "utf-8")
|
||||
|
||||
console.log(`✓ Sitemap generated at ${outputPath}`)
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -12,10 +12,7 @@ export default function App() {
|
||||
root={(props) => (
|
||||
<MetaProvider>
|
||||
<Title>opencode</Title>
|
||||
<Meta
|
||||
name="description"
|
||||
content="OpenCode - The AI coding agent built for the terminal."
|
||||
/>
|
||||
<Meta name="description" content="OpenCode - The AI coding agent built for the terminal." />
|
||||
<Suspense>{props.children}</Suspense>
|
||||
</MetaProvider>
|
||||
)}
|
||||
|
||||
@@ -77,4 +77,4 @@
|
||||
background-color: var(--color-accent-alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
* Application-wide constants and configuration
|
||||
*/
|
||||
export const config = {
|
||||
// Base URL
|
||||
baseUrl: "https://opencode.ai",
|
||||
|
||||
// GitHub
|
||||
github: {
|
||||
repoUrl: "https://github.com/sst/opencode",
|
||||
|
||||
@@ -7,10 +7,7 @@ export const github = query(async () => {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
|
||||
}
|
||||
const apiBaseUrl = config.github.repoUrl.replace(
|
||||
"https://github.com/",
|
||||
"https://api.github.com/repos/",
|
||||
)
|
||||
const apiBaseUrl = config.github.repoUrl.replace("https://github.com/", "https://api.github.com/repos/")
|
||||
try {
|
||||
const [meta, releases, contributors] = await Promise.all([
|
||||
fetch(apiBaseUrl, { headers }).then((res) => res.json()),
|
||||
|
||||
@@ -264,7 +264,7 @@
|
||||
[data-component="brand-content"] {
|
||||
padding: 4rem 5rem;
|
||||
|
||||
h2 {
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-strong);
|
||||
@@ -299,7 +299,6 @@
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: var(--color-background-strong-hover);
|
||||
}
|
||||
@@ -385,23 +384,21 @@
|
||||
0 1px 2px -1px rgba(19, 16, 16, 0.12);
|
||||
|
||||
@media (max-width: 40rem) {
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(19, 16, 16, 0.16)
|
||||
box-shadow: 0 0 0 1px rgba(19, 16, 16, 0.16);
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
background: var(--color-background);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 0 0 1px rgba(19, 16, 16, 0.08), 0 6px 8px -8px rgba(19, 16, 16, 0.50);
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(19, 16, 16, 0.08),
|
||||
0 6px 8px -8px rgba(19, 16, 16, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (max-width: 60rem) {
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "./index.css"
|
||||
import { Title, Meta } from "@solidjs/meta"
|
||||
import { Title, Meta, Link } from "@solidjs/meta"
|
||||
import { Header } from "~/component/header"
|
||||
import { config } from "~/config"
|
||||
import { Footer } from "~/component/footer"
|
||||
import { Legal } from "~/component/legal"
|
||||
import previewLogoLight from "../../asset/brand/preview-opencode-logo-light.png"
|
||||
@@ -53,26 +54,21 @@ export default function Brand() {
|
||||
return (
|
||||
<main data-page="enterprise">
|
||||
<Title>OpenCode | Brand</Title>
|
||||
<Link rel="canonical" href={`${config.baseUrl}/brand`} />
|
||||
<Meta name="description" content="OpenCode brand guidelines" />
|
||||
<div data-component="container">
|
||||
<Header />
|
||||
|
||||
<div data-component="content">
|
||||
<section data-component="brand-content">
|
||||
<h2>Brand guidelines</h2>
|
||||
<h1>Brand guidelines</h1>
|
||||
<p>Resources and assets to help you work with the OpenCode brand.</p>
|
||||
<button
|
||||
data-component="download-button"
|
||||
onClick={() => downloadFile(brandAssets, "opencode-brand-assets.zip")}
|
||||
>
|
||||
Download all assets
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -88,13 +84,7 @@ export default function Brand() {
|
||||
<div data-component="actions">
|
||||
<button onClick={() => downloadFile(logoLightPng, "opencode-logo-light.png")}>
|
||||
PNG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -105,13 +95,7 @@ export default function Brand() {
|
||||
</button>
|
||||
<button onClick={() => downloadFile(logoLightSvg, "opencode-logo-light.svg")}>
|
||||
SVG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -127,13 +111,7 @@ export default function Brand() {
|
||||
<div data-component="actions">
|
||||
<button onClick={() => downloadFile(logoDarkPng, "opencode-logo-dark.png")}>
|
||||
PNG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -144,13 +122,7 @@ export default function Brand() {
|
||||
</button>
|
||||
<button onClick={() => downloadFile(logoDarkSvg, "opencode-logo-dark.svg")}>
|
||||
SVG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -164,17 +136,9 @@ export default function Brand() {
|
||||
<div>
|
||||
<img src={previewWordmarkLight} alt="OpenCode brand guidelines" />
|
||||
<div data-component="actions">
|
||||
<button
|
||||
onClick={() => downloadFile(wordmarkLightPng, "opencode-wordmark-light.png")}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkLightPng, "opencode-wordmark-light.png")}>
|
||||
PNG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -183,17 +147,9 @@ export default function Brand() {
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => downloadFile(wordmarkLightSvg, "opencode-wordmark-light.svg")}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkLightSvg, "opencode-wordmark-light.svg")}>
|
||||
SVG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -207,17 +163,9 @@ export default function Brand() {
|
||||
<div>
|
||||
<img src={previewWordmarkDark} alt="OpenCode brand guidelines" />
|
||||
<div data-component="actions">
|
||||
<button
|
||||
onClick={() => downloadFile(wordmarkDarkPng, "opencode-wordmark-dark.png")}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkDarkPng, "opencode-wordmark-dark.png")}>
|
||||
PNG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -226,17 +174,9 @@ export default function Brand() {
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => downloadFile(wordmarkDarkSvg, "opencode-wordmark-dark.svg")}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkDarkSvg, "opencode-wordmark-dark.svg")}>
|
||||
SVG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -250,19 +190,9 @@ export default function Brand() {
|
||||
<div>
|
||||
<img src={previewWordmarkSimpleLight} alt="OpenCode brand guidelines" />
|
||||
<div data-component="actions">
|
||||
<button
|
||||
onClick={() =>
|
||||
downloadFile(wordmarkSimpleLightPng, "opencode-wordmark-simple-light.png")
|
||||
}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkSimpleLightPng, "opencode-wordmark-simple-light.png")}>
|
||||
PNG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -271,19 +201,9 @@ export default function Brand() {
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
downloadFile(wordmarkSimpleLightSvg, "opencode-wordmark-simple-light.svg")
|
||||
}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkSimpleLightSvg, "opencode-wordmark-simple-light.svg")}>
|
||||
SVG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -297,19 +217,9 @@ export default function Brand() {
|
||||
<div>
|
||||
<img src={previewWordmarkSimpleDark} alt="OpenCode brand guidelines" />
|
||||
<div data-component="actions">
|
||||
<button
|
||||
onClick={() =>
|
||||
downloadFile(wordmarkSimpleDarkPng, "opencode-wordmark-simple-dark.png")
|
||||
}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkSimpleDarkPng, "opencode-wordmark-simple-dark.png")}>
|
||||
PNG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
@@ -318,19 +228,9 @@ export default function Brand() {
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
downloadFile(wordmarkSimpleDarkSvg, "opencode-wordmark-simple-dark.svg")
|
||||
}
|
||||
>
|
||||
<button onClick={() => downloadFile(wordmarkSimpleDarkSvg, "opencode-wordmark-simple-dark.svg")}>
|
||||
SVG
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||
stroke="currentColor"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { redirect } from "@solidjs/router"
|
||||
|
||||
export async function GET() {
|
||||
return redirect("https://discord.gg/h5TNnkFVNy")
|
||||
}
|
||||
@@ -287,7 +287,7 @@
|
||||
}
|
||||
|
||||
[data-component="enterprise-column-1"] {
|
||||
h2 {
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-strong);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "./index.css"
|
||||
import { Title, Meta } from "@solidjs/meta"
|
||||
import { Title, Meta, Link } from "@solidjs/meta"
|
||||
import { createSignal, Show } from "solid-js"
|
||||
import { config } from "~/config"
|
||||
import { Header } from "~/component/header"
|
||||
import { Footer } from "~/component/footer"
|
||||
import { Legal } from "~/component/legal"
|
||||
@@ -54,6 +55,7 @@ export default function Enterprise() {
|
||||
return (
|
||||
<main data-page="enterprise">
|
||||
<Title>OpenCode | Enterprise solutions for your organisation</Title>
|
||||
<Link rel="canonical" href={`${config.baseUrl}/enterprise`} />
|
||||
<Meta name="description" content="Contact OpenCode for enterprise solutions" />
|
||||
<div data-component="container">
|
||||
<Header />
|
||||
@@ -62,41 +64,28 @@ export default function Enterprise() {
|
||||
<section data-component="enterprise-content">
|
||||
<div data-component="enterprise-columns">
|
||||
<div data-component="enterprise-column-1">
|
||||
<h2>Your code is yours</h2>
|
||||
<h1>Your code is yours</h1>
|
||||
<p>
|
||||
OpenCode operates securely inside your organization with no data or context stored
|
||||
and no licensing restrictions or ownership claims. Start a trial with your team,
|
||||
then deploy it across your organization by integrating it with your SSO and
|
||||
internal AI gateway.
|
||||
OpenCode operates securely inside your organization with no data or context stored and no licensing
|
||||
restrictions or ownership claims. Start a trial with your team, then deploy it across your
|
||||
organization by integrating it with your SSO and internal AI gateway.
|
||||
</p>
|
||||
<p>Let us know and how we can help.</p>
|
||||
|
||||
<Show when={false}>
|
||||
<div data-component="testimonial">
|
||||
<div data-component="quotation">
|
||||
<svg
|
||||
width="20"
|
||||
height="17"
|
||||
viewBox="0 0 20 17"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M19.4118 0L16.5882 9.20833H20V17H12.2353V10.0938L16 0H19.4118ZM7.17647 0L4.35294 9.20833H7.76471V17H0V10.0938L3.76471 0H7.17647Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
Thanks to OpenCode, we found a way to create software to track all our assets —
|
||||
even the imaginary ones.
|
||||
Thanks to OpenCode, we found a way to create software to track all our assets — even the imaginary
|
||||
ones.
|
||||
<div data-component="testimonial-logo">
|
||||
<svg
|
||||
width="80"
|
||||
height="79"
|
||||
viewBox="0 0 80 79"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="80" height="79" viewBox="0 0 80 79" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
@@ -213,11 +202,7 @@ export default function Enterprise() {
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{showSuccess() && (
|
||||
<div data-component="success-message">
|
||||
Message sent, we'll be in touch soon.
|
||||
</div>
|
||||
)}
|
||||
{showSuccess() && <div data-component="success-message">Message sent, we'll be in touch soon.</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -230,31 +215,29 @@ export default function Enterprise() {
|
||||
<ul>
|
||||
<li>
|
||||
<Faq question="What is OpenCode Enterprise?">
|
||||
OpenCode Enterprise is for organizations that want to ensure that their code and
|
||||
data never leaves their infrastructure. It can do this by using a centralized
|
||||
config that integrates with your SSO and internal AI gateway.
|
||||
OpenCode Enterprise is for organizations that want to ensure that their code and data never leaves
|
||||
their infrastructure. It can do this by using a centralized config that integrates with your SSO and
|
||||
internal AI gateway.
|
||||
</Faq>
|
||||
</li>
|
||||
<li>
|
||||
<Faq question="How do I get started with OpenCode Enterprise?">
|
||||
Simply start with an internal trial with your team. OpenCode by default does not
|
||||
store your code or context data, making it easy to get started. Then contact us to
|
||||
discuss pricing and implementation options.
|
||||
Simply start with an internal trial with your team. OpenCode by default does not store your code or
|
||||
context data, making it easy to get started. Then contact us to discuss pricing and implementation
|
||||
options.
|
||||
</Faq>
|
||||
</li>
|
||||
<li>
|
||||
<Faq question="How does enterprise pricing work?">
|
||||
We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not
|
||||
charge for tokens used. For further details, contact us for a custom quote based
|
||||
on your organization's needs.
|
||||
We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not charge for tokens
|
||||
used. For further details, contact us for a custom quote based on your organization's needs.
|
||||
</Faq>
|
||||
</li>
|
||||
<li>
|
||||
<Faq question="Is my data secure with OpenCode Enterprise?">
|
||||
Yes. OpenCode does not store your code or context data. All processing happens
|
||||
locally or through direct API calls to your AI provider. With central config and
|
||||
SSO integration, your data remains secure within your organization's
|
||||
infrastructure.
|
||||
Yes. OpenCode does not store your code or context data. All processing happens locally or through
|
||||
direct API calls to your AI provider. With central config and SSO integration, your data remains
|
||||
secure within your organization's infrastructure.
|
||||
</Faq>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -479,7 +479,7 @@ body {
|
||||
border-bottom: 1px solid var(--color-border-weak);
|
||||
}
|
||||
|
||||
strong {
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
color: var(--color-text-strong);
|
||||
font-weight: 500;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,8 +41,7 @@ export async function POST(input: APIEvent) {
|
||||
}
|
||||
if (body.type === "checkout.session.completed") {
|
||||
const workspaceID = body.data.object.metadata?.workspaceID
|
||||
const amountInCents =
|
||||
body.data.object.metadata?.amount && parseInt(body.data.object.metadata?.amount)
|
||||
const amountInCents = body.data.object.metadata?.amount && parseInt(body.data.object.metadata?.amount)
|
||||
const customerID = body.data.object.customer as string
|
||||
const paymentID = body.data.object.payment_intent as string
|
||||
const invoiceID = body.data.object.invoice as string
|
||||
@@ -55,8 +54,7 @@ export async function POST(input: APIEvent) {
|
||||
|
||||
await Actor.provide("system", { workspaceID }, async () => {
|
||||
const customer = await Billing.get()
|
||||
if (customer?.customerID && customer.customerID !== customerID)
|
||||
throw new Error("Customer ID mismatch")
|
||||
if (customer?.customerID && customer.customerID !== customerID) throw new Error("Customer ID mismatch")
|
||||
|
||||
// set customer metadata
|
||||
if (!customer?.customerID) {
|
||||
@@ -72,8 +70,7 @@ export async function POST(input: APIEvent) {
|
||||
expand: ["payment_method"],
|
||||
})
|
||||
const paymentMethod = paymentIntent.payment_method
|
||||
if (!paymentMethod || typeof paymentMethod === "string")
|
||||
throw new Error("Payment method not expanded")
|
||||
if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded")
|
||||
|
||||
await Database.transaction(async (tx) => {
|
||||
await tx
|
||||
@@ -128,12 +125,7 @@ export async function POST(input: APIEvent) {
|
||||
amount: PaymentTable.amount,
|
||||
})
|
||||
.from(PaymentTable)
|
||||
.where(
|
||||
and(
|
||||
eq(PaymentTable.paymentID, paymentIntentID),
|
||||
eq(PaymentTable.workspaceID, workspaceID),
|
||||
),
|
||||
)
|
||||
.where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID)))
|
||||
.then((rows) => rows[0]?.amount),
|
||||
)
|
||||
if (!amount) throw new Error("Payment not found")
|
||||
@@ -144,12 +136,7 @@ export async function POST(input: APIEvent) {
|
||||
.set({
|
||||
timeRefunded: new Date(body.created * 1000),
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(PaymentTable.paymentID, paymentIntentID),
|
||||
eq(PaymentTable.workspaceID, workspaceID),
|
||||
),
|
||||
)
|
||||
.where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID)))
|
||||
|
||||
await tx
|
||||
.update(BillingTable)
|
||||
|
||||
@@ -79,19 +79,17 @@ export default function Home() {
|
||||
<strong>LSP enabled</strong> Automatically loads the right LSPs for the LLM
|
||||
</li>
|
||||
<li>
|
||||
<strong>opencode zen</strong> A <a href="/docs/zen">curated list of models</a>{" "}
|
||||
provided by opencode <label>New</label>
|
||||
<strong>opencode zen</strong> A <a href="/docs/zen">curated list of models</a> provided by opencode{" "}
|
||||
<label>New</label>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Multi-session</strong> Start multiple agents in parallel on the same project
|
||||
</li>
|
||||
<li>
|
||||
<strong>Shareable links</strong> Share a link to any sessions for reference or to
|
||||
debug
|
||||
<strong>Shareable links</strong> Share a link to any sessions for reference or to debug
|
||||
</li>
|
||||
<li>
|
||||
<strong>Claude Pro</strong> Log in with Anthropic to use your Claude Pro or Max
|
||||
account
|
||||
<strong>Claude Pro</strong> Log in with Anthropic to use your Claude Pro or Max account
|
||||
</li>
|
||||
<li>
|
||||
<strong>Use any model</strong> Supports 75+ LLM providers through{" "}
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
color: var(--color-danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,4 +71,4 @@
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,4 +104,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,4 +182,4 @@
|
||||
padding: var(--space-4);
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,17 @@ export function BillingSection() {
|
||||
const sessionSubmission = useSubmission(createSessionUrl)
|
||||
const [store, setStore] = createStore({
|
||||
showAddBalanceForm: false,
|
||||
addBalanceAmount: "",
|
||||
addBalanceAmount: billingInfo()?.reloadAmount.toString() ?? "",
|
||||
checkoutRedirecting: false,
|
||||
sessionRedirecting: false,
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const info = billingInfo()
|
||||
if (info) {
|
||||
setStore("addBalanceAmount", info.reloadAmount.toString())
|
||||
}
|
||||
})
|
||||
const balance = createMemo(() => formatBalance(billingInfo()?.balance ?? 0))
|
||||
|
||||
async function onClickCheckout() {
|
||||
@@ -67,7 +74,6 @@ export function BillingSection() {
|
||||
}
|
||||
setStore({
|
||||
showAddBalanceForm: true,
|
||||
addBalanceAmount: billingInfo()!.reloadAmount.toString(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -133,8 +139,7 @@ export function BillingSection() {
|
||||
<div data-slot="section-title">
|
||||
<h2>Billing</h2>
|
||||
<p>
|
||||
Manage payments methods. <a href="mailto:contact@anoma.ly">Contact us</a> if you have any
|
||||
questions.
|
||||
Manage payments methods. <a href="mailto:contact@anoma.ly">Contact us</a> if you have any questions.
|
||||
</p>
|
||||
</div>
|
||||
<div data-slot="section-content">
|
||||
@@ -164,32 +169,20 @@ export function BillingSection() {
|
||||
placeholder="Enter amount"
|
||||
/>
|
||||
<div data-slot="form-actions">
|
||||
<button
|
||||
data-color="ghost"
|
||||
type="button"
|
||||
onClick={() => hideAddBalanceForm()}
|
||||
>
|
||||
<button data-color="ghost" type="button" onClick={() => hideAddBalanceForm()}>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
data-color="primary"
|
||||
type="button"
|
||||
disabled={
|
||||
!store.addBalanceAmount ||
|
||||
checkoutSubmission.pending ||
|
||||
store.checkoutRedirecting
|
||||
}
|
||||
disabled={!store.addBalanceAmount || checkoutSubmission.pending || store.checkoutRedirecting}
|
||||
onClick={onClickCheckout}
|
||||
>
|
||||
{checkoutSubmission.pending || store.checkoutRedirecting
|
||||
? "Loading..."
|
||||
: "Add"}
|
||||
{checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Add"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Show
|
||||
when={checkoutSubmission.result && (checkoutSubmission.result as any).error}
|
||||
>
|
||||
<Show when={checkoutSubmission.result && (checkoutSubmission.result as any).error}>
|
||||
{(err: any) => <div data-slot="form-error">{err()}</div>}
|
||||
</Show>
|
||||
</div>
|
||||
@@ -210,10 +203,7 @@ export function BillingSection() {
|
||||
<div data-slot="card-details">
|
||||
<Switch>
|
||||
<Match when={billingInfo()?.paymentMethodType === "card"}>
|
||||
<Show
|
||||
when={billingInfo()?.paymentMethodLast4}
|
||||
fallback={<span data-slot="number">----</span>}
|
||||
>
|
||||
<Show when={billingInfo()?.paymentMethodLast4} fallback={<span data-slot="number">----</span>}>
|
||||
<span data-slot="secret">••••</span>
|
||||
<span data-slot="number">{billingInfo()?.paymentMethodLast4}</span>
|
||||
</Show>
|
||||
@@ -241,9 +231,7 @@ export function BillingSection() {
|
||||
disabled={checkoutSubmission.pending || store.checkoutRedirecting}
|
||||
onClick={onClickCheckout}
|
||||
>
|
||||
{checkoutSubmission.pending || store.checkoutRedirecting
|
||||
? "Loading..."
|
||||
: "Enable Billing"}
|
||||
{checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Enable Billing"}
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -93,4 +93,4 @@
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,13 +104,9 @@ export function MonthlyLimitSection() {
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
<Show
|
||||
when={billingInfo()?.monthlyLimit}
|
||||
fallback={<p data-slot="usage-status">No usage limit set.</p>}
|
||||
>
|
||||
<Show when={billingInfo()?.monthlyLimit} fallback={<p data-slot="usage-status">No usage limit set.</p>}>
|
||||
<p data-slot="usage-status">
|
||||
Current usage for{" "}
|
||||
{new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $
|
||||
Current usage for {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $
|
||||
{(() => {
|
||||
const dateLastUsed = billingInfo()?.timeMonthlyUsageUpdated
|
||||
if (!dateLastUsed) return "0"
|
||||
|
||||
@@ -259,4 +259,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,11 +69,7 @@ export function ReloadSection() {
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (
|
||||
!setReloadSubmission.pending &&
|
||||
setReloadSubmission.result &&
|
||||
!(setReloadSubmission.result as any).error
|
||||
) {
|
||||
if (!setReloadSubmission.pending && setReloadSubmission.result && !(setReloadSubmission.result as any).error) {
|
||||
setStore("show", false)
|
||||
}
|
||||
})
|
||||
@@ -108,8 +104,8 @@ export function ReloadSection() {
|
||||
}
|
||||
>
|
||||
<p>
|
||||
Auto reload is <b>enabled</b>. We'll reload <b>${billingInfo()?.reloadAmount}</b>{" "}
|
||||
(+$1.23 processing fee) when balance reaches <b>${billingInfo()?.reloadTrigger}</b>.
|
||||
Auto reload is <b>enabled</b>. We'll reload <b>${billingInfo()?.reloadAmount}</b> (+$1.23 processing fee)
|
||||
when balance reaches <b>${billingInfo()?.reloadTrigger}</b>.
|
||||
</p>
|
||||
</Show>
|
||||
<button data-color="primary" type="button" onClick={() => show()}>
|
||||
@@ -194,8 +190,8 @@ export function ReloadSection() {
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
})}
|
||||
. Reason: {billingInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment
|
||||
method and try again.
|
||||
. Reason: {billingInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment method and try
|
||||
again.
|
||||
</p>
|
||||
<form action={reload} method="post" data-slot="create-form">
|
||||
<input type="hidden" name="workspaceID" value={params.id} />
|
||||
|
||||
@@ -51,9 +51,7 @@ export default function () {
|
||||
disabled={checkoutSubmission.pending || store.checkoutRedirecting}
|
||||
onClick={onClickCheckout}
|
||||
>
|
||||
{checkoutSubmission.pending || store.checkoutRedirecting
|
||||
? "Loading..."
|
||||
: "Enable billing"}
|
||||
{checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Enable billing"}
|
||||
</button>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -171,7 +171,6 @@
|
||||
}
|
||||
|
||||
@media (max-width: 40rem) {
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: var(--space-2) var(--space-3);
|
||||
@@ -181,8 +180,7 @@
|
||||
th {
|
||||
&:nth-child(3)
|
||||
|
||||
/* Date */
|
||||
{
|
||||
/* Date */ {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -190,11 +188,10 @@
|
||||
td {
|
||||
&:nth-child(3)
|
||||
|
||||
/* Date */
|
||||
{
|
||||
/* Date */ {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,4 +69,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,7 @@ import { withActor } from "~/context/auth.withActor"
|
||||
import { ZenData } from "@opencode-ai/console-core/model.js"
|
||||
import styles from "./model-section.module.css"
|
||||
import { querySessionInfo } from "../common"
|
||||
import {
|
||||
IconAlibaba,
|
||||
IconAnthropic,
|
||||
IconMoonshotAI,
|
||||
IconOpenAI,
|
||||
IconStealth,
|
||||
IconXai,
|
||||
IconZai,
|
||||
} from "~/component/icon"
|
||||
import { IconAlibaba, IconAnthropic, IconMoonshotAI, IconOpenAI, IconStealth, IconXai, IconZai } from "~/component/icon"
|
||||
|
||||
const getModelLab = (modelId: string) => {
|
||||
if (modelId.startsWith("claude")) return "Anthropic"
|
||||
@@ -76,8 +68,7 @@ export function ModelSection() {
|
||||
<div data-slot="section-title">
|
||||
<h2>Models</h2>
|
||||
<p>
|
||||
Manage which models workspace members can access.{" "}
|
||||
<a href="/docs/zen#pricing ">Learn more</a>.
|
||||
Manage which models workspace members can access. <a href="/docs/zen#pricing ">Learn more</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div data-slot="models-list">
|
||||
|
||||
@@ -140,4 +140,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,6 @@
|
||||
}
|
||||
|
||||
@media (max-width: 40rem) {
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: var(--space-2) var(--space-3);
|
||||
@@ -136,4 +135,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ const removeProvider = action(async (form: FormData) => {
|
||||
if (!provider) return { error: "Provider is required" }
|
||||
const workspaceID = form.get("workspaceID")?.toString()
|
||||
if (!workspaceID) return { error: "Workspace ID is required" }
|
||||
return json(await withActor(() => Provider.remove({ provider }), workspaceID), { revalidate: listProviders.key })
|
||||
return json(await withActor(() => Provider.remove({ provider }), workspaceID), {
|
||||
revalidate: listProviders.key,
|
||||
})
|
||||
}, "provider.remove")
|
||||
|
||||
const saveProvider = action(async (form: FormData) => {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
>button {
|
||||
> button {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
>button[type="reset"] {
|
||||
> button[type="reset"] {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
@@ -91,4 +91,4 @@
|
||||
margin-top: calc(var(--space-1) * -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,10 +67,7 @@ export const querySessionInfo = query(async (workspaceID: string) => {
|
||||
return withActor(() => {
|
||||
return {
|
||||
isAdmin: Actor.userRole() === "admin",
|
||||
isBeta:
|
||||
Resource.App.stage === "production"
|
||||
? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y"
|
||||
: true,
|
||||
isBeta: Resource.App.stage === "production" ? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y" : true,
|
||||
}
|
||||
}, workspaceID)
|
||||
}, "session.get")
|
||||
|
||||
@@ -277,7 +277,7 @@ body {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
strong {
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
color: var(--color-text-strong);
|
||||
font-weight: 500;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createAsync, query, redirect } from "@solidjs/router"
|
||||
import { Title, Meta, Link } from "@solidjs/meta"
|
||||
import { HttpHeader } from "@solidjs/start"
|
||||
import zenLogoLight from "../../asset/zen-ornate-light.svg"
|
||||
import { config } from "~/config"
|
||||
import zenLogoDark from "../../asset/zen-ornate-dark.svg"
|
||||
import compareVideo from "../../asset/lander/opencode-comparison-min.mp4"
|
||||
import compareVideoPoster from "../../asset/lander/opencode-comparison-poster.png"
|
||||
@@ -30,6 +31,7 @@ export default function Home() {
|
||||
<main data-page="zen">
|
||||
<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
|
||||
<Title>OpenCode Zen | A curated set of reliable optimized models for coding agents</Title>
|
||||
<Link rel="canonical" href={`${config.baseUrl}/zen`} />
|
||||
<Link rel="icon" type="image/svg+xml" href="/favicon-zen.svg" />
|
||||
<Meta property="og:image" content="/social-share-zen.png" />
|
||||
<Meta name="twitter:image" content="/social-share-zen.png" />
|
||||
@@ -42,7 +44,7 @@ export default function Home() {
|
||||
<div data-slot="hero-copy">
|
||||
<img data-slot="zen logo light" src={zenLogoLight} alt="zen logo light" />
|
||||
<img data-slot="zen logo dark" src={zenLogoDark} alt="zen logo dark" />
|
||||
<strong>Reliable optimized models for coding agents</strong>
|
||||
<h1>Reliable optimized models for coding agents</h1>
|
||||
<p>
|
||||
Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically
|
||||
for coding agents. No need to worry about inconsistent performance and quality, use validated models
|
||||
|
||||
@@ -3,3 +3,4 @@ export class CreditsError extends Error {}
|
||||
export class MonthlyLimitError extends Error {}
|
||||
export class UserLimitError extends Error {}
|
||||
export class ModelError extends Error {}
|
||||
export class RateLimitError extends Error {}
|
||||
|
||||
@@ -12,18 +12,14 @@ import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
|
||||
import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js"
|
||||
import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js"
|
||||
import { logger } from "./logger"
|
||||
import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error"
|
||||
import {
|
||||
createBodyConverter,
|
||||
createStreamPartConverter,
|
||||
createResponseConverter,
|
||||
} from "./provider/provider"
|
||||
import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError, RateLimitError } from "./error"
|
||||
import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider"
|
||||
import { anthropicHelper } from "./provider/anthropic"
|
||||
import { openaiHelper } from "./provider/openai"
|
||||
import { oaCompatHelper } from "./provider/openai-compatible"
|
||||
import { createRateLimiter } from "./rateLimiter"
|
||||
|
||||
type ZenData = Awaited<ReturnType<typeof ZenData.list>>
|
||||
type Model = ZenData["models"][string]
|
||||
|
||||
export async function handler(
|
||||
input: APIEvent,
|
||||
@@ -32,6 +28,10 @@ export async function handler(
|
||||
parseApiKey: (headers: Headers) => string | undefined
|
||||
},
|
||||
) {
|
||||
type AuthInfo = Awaited<ReturnType<typeof authenticate>>
|
||||
type ModelInfo = Awaited<ReturnType<typeof validateModel>>
|
||||
type ProviderInfo = Awaited<ReturnType<typeof selectProvider>>
|
||||
|
||||
const FREE_WORKSPACES = [
|
||||
"wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
|
||||
"wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench
|
||||
@@ -39,6 +39,7 @@ export async function handler(
|
||||
|
||||
try {
|
||||
const body = await input.request.json()
|
||||
const ip = input.request.headers.get("x-real-ip") ?? ""
|
||||
logger.metric({
|
||||
is_tream: !!body.stream,
|
||||
session: input.request.headers.get("x-opencode-session"),
|
||||
@@ -46,13 +47,11 @@ export async function handler(
|
||||
})
|
||||
const zenData = ZenData.list()
|
||||
const modelInfo = validateModel(zenData, body.model)
|
||||
const providerInfo = selectProvider(
|
||||
zenData,
|
||||
modelInfo,
|
||||
input.request.headers.get("x-real-ip") ?? "",
|
||||
)
|
||||
const providerInfo = selectProvider(zenData, modelInfo, ip)
|
||||
const authInfo = await authenticate(modelInfo, providerInfo)
|
||||
validateBilling(modelInfo, authInfo)
|
||||
const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
|
||||
await rateLimiter?.check()
|
||||
validateBilling(authInfo, modelInfo)
|
||||
validateModelSettings(authInfo)
|
||||
updateProviderKey(authInfo, providerInfo)
|
||||
logger.metric({ provider: providerInfo.id })
|
||||
@@ -67,7 +66,7 @@ export async function handler(
|
||||
}),
|
||||
)
|
||||
logger.debug("REQUEST URL: " + reqUrl)
|
||||
logger.debug("REQUEST: " + reqBody)
|
||||
logger.debug("REQUEST: " + reqBody.substring(0, 300) + "...")
|
||||
const res = await fetch(reqUrl, {
|
||||
method: "POST",
|
||||
headers: (() => {
|
||||
@@ -92,9 +91,6 @@ export async function handler(
|
||||
}
|
||||
}
|
||||
logger.debug("STATUS: " + res.status + " " + res.statusText)
|
||||
if (res.status === 400 || res.status === 503) {
|
||||
logger.debug("RESPONSE: " + (await res.text()))
|
||||
}
|
||||
|
||||
// Handle non-streaming response
|
||||
if (!body.stream) {
|
||||
@@ -103,6 +99,7 @@ export async function handler(
|
||||
const body = JSON.stringify(responseConverter(json))
|
||||
logger.metric({ response_length: body.length })
|
||||
logger.debug("RESPONSE: " + body)
|
||||
await rateLimiter?.track()
|
||||
await trackUsage(authInfo, modelInfo, providerInfo, json.usage)
|
||||
await reload(authInfo)
|
||||
return new Response(body, {
|
||||
@@ -131,6 +128,7 @@ export async function handler(
|
||||
response_length: responseLength,
|
||||
"timestamp.last_byte": Date.now(),
|
||||
})
|
||||
await rateLimiter?.track()
|
||||
const usage = usageParser.retrieve()
|
||||
if (usage) {
|
||||
await trackUsage(authInfo, modelInfo, providerInfo, usage)
|
||||
@@ -205,6 +203,15 @@ export async function handler(
|
||||
{ status: 401 },
|
||||
)
|
||||
|
||||
if (error instanceof RateLimitError)
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
error: { type: error.constructor.name, message: error.message },
|
||||
}),
|
||||
{ status: 429 },
|
||||
)
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
@@ -229,12 +236,8 @@ export async function handler(
|
||||
return { id: modelId, ...modelData }
|
||||
}
|
||||
|
||||
function selectProvider(
|
||||
zenData: ZenData,
|
||||
model: Awaited<ReturnType<typeof validateModel>>,
|
||||
ip: string,
|
||||
) {
|
||||
const providers = model.providers
|
||||
function selectProvider(zenData: ZenData, modelInfo: ModelInfo, ip: string) {
|
||||
const providers = modelInfo.providers
|
||||
.filter((provider) => !provider.disabled)
|
||||
.flatMap((provider) => Array<typeof provider>(provider.weight ?? 1).fill(provider))
|
||||
|
||||
@@ -247,26 +250,22 @@ export async function handler(
|
||||
throw new ModelError(`Provider ${provider.id} not supported`)
|
||||
}
|
||||
|
||||
const format = zenData.providers[provider.id].format
|
||||
|
||||
return {
|
||||
...provider,
|
||||
...zenData.providers[provider.id],
|
||||
...(format === "anthropic"
|
||||
? anthropicHelper
|
||||
: format === "openai"
|
||||
? openaiHelper
|
||||
: oaCompatHelper),
|
||||
...(() => {
|
||||
const format = zenData.providers[provider.id].format
|
||||
if (format === "anthropic") return anthropicHelper
|
||||
if (format === "openai") return openaiHelper
|
||||
return oaCompatHelper
|
||||
})(),
|
||||
}
|
||||
}
|
||||
|
||||
async function authenticate(
|
||||
model: Awaited<ReturnType<typeof validateModel>>,
|
||||
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
|
||||
) {
|
||||
async function authenticate(modelInfo: ModelInfo, providerInfo: ProviderInfo) {
|
||||
const apiKey = opts.parseApiKey(input.request.headers)
|
||||
if (!apiKey) {
|
||||
if (model.allowAnonymous) return
|
||||
if (modelInfo.allowAnonymous) return
|
||||
throw new AuthError("Missing API key.")
|
||||
}
|
||||
|
||||
@@ -297,20 +296,11 @@ export async function handler(
|
||||
.from(KeyTable)
|
||||
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
||||
.innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
|
||||
.innerJoin(
|
||||
UserTable,
|
||||
and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)),
|
||||
)
|
||||
.leftJoin(
|
||||
ModelTable,
|
||||
and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id)),
|
||||
)
|
||||
.innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)))
|
||||
.leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, modelInfo.id)))
|
||||
.leftJoin(
|
||||
ProviderTable,
|
||||
and(
|
||||
eq(ProviderTable.workspaceID, KeyTable.workspaceID),
|
||||
eq(ProviderTable.provider, providerInfo.id),
|
||||
),
|
||||
and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)),
|
||||
)
|
||||
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
||||
.then((rows) => rows[0]),
|
||||
@@ -333,11 +323,11 @@ export async function handler(
|
||||
}
|
||||
}
|
||||
|
||||
function validateBilling(model: Model, authInfo: Awaited<ReturnType<typeof authenticate>>) {
|
||||
function validateBilling(authInfo: AuthInfo, modelInfo: ModelInfo) {
|
||||
if (!authInfo) return
|
||||
if (authInfo.provider?.credentials) return
|
||||
if (authInfo.isFree) return
|
||||
if (model.allowAnonymous) return
|
||||
if (modelInfo.allowAnonymous) return
|
||||
|
||||
const billing = authInfo.billing
|
||||
if (!billing.paymentMethodID)
|
||||
@@ -381,39 +371,24 @@ export async function handler(
|
||||
}
|
||||
}
|
||||
|
||||
function validateModelSettings(authInfo: Awaited<ReturnType<typeof authenticate>>) {
|
||||
function validateModelSettings(authInfo: AuthInfo) {
|
||||
if (!authInfo) return
|
||||
if (authInfo.isDisabled) throw new ModelError("Model is disabled")
|
||||
}
|
||||
|
||||
function updateProviderKey(
|
||||
authInfo: Awaited<ReturnType<typeof authenticate>>,
|
||||
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
|
||||
) {
|
||||
function updateProviderKey(authInfo: AuthInfo, providerInfo: ProviderInfo) {
|
||||
if (!authInfo) return
|
||||
if (!authInfo.provider?.credentials) return
|
||||
providerInfo.apiKey = authInfo.provider.credentials
|
||||
}
|
||||
|
||||
async function trackUsage(
|
||||
authInfo: Awaited<ReturnType<typeof authenticate>>,
|
||||
modelInfo: ReturnType<typeof validateModel>,
|
||||
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
|
||||
usage: any,
|
||||
) {
|
||||
const {
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
reasoningTokens,
|
||||
cacheReadTokens,
|
||||
cacheWrite5mTokens,
|
||||
cacheWrite1hTokens,
|
||||
} = providerInfo.normalizeUsage(usage)
|
||||
async function trackUsage(authInfo: AuthInfo, modelInfo: ModelInfo, providerInfo: ProviderInfo, usage: any) {
|
||||
const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } =
|
||||
providerInfo.normalizeUsage(usage)
|
||||
|
||||
const modelCost =
|
||||
modelInfo.cost200K &&
|
||||
inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) >
|
||||
200_000
|
||||
inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) > 200_000
|
||||
? modelInfo.cost200K
|
||||
: modelInfo.cost
|
||||
|
||||
@@ -464,8 +439,7 @@ export async function handler(
|
||||
|
||||
if (!authInfo) return
|
||||
|
||||
const cost =
|
||||
authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent)
|
||||
const cost = authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent)
|
||||
await Database.transaction(async (tx) => {
|
||||
await tx.insert(UsageTable).values({
|
||||
workspaceID: authInfo.workspaceID,
|
||||
@@ -505,9 +479,7 @@ export async function handler(
|
||||
`,
|
||||
timeMonthlyUsageUpdated: sql`now()`,
|
||||
})
|
||||
.where(
|
||||
and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)),
|
||||
)
|
||||
.where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)))
|
||||
})
|
||||
|
||||
await Database.use((tx) =>
|
||||
@@ -518,7 +490,7 @@ export async function handler(
|
||||
)
|
||||
}
|
||||
|
||||
async function reload(authInfo: Awaited<ReturnType<typeof authenticate>>) {
|
||||
async function reload(authInfo: AuthInfo) {
|
||||
if (!authInfo) return
|
||||
if (authInfo.isFree) return
|
||||
if (authInfo.provider?.credentials) return
|
||||
@@ -537,10 +509,7 @@ export async function handler(
|
||||
BillingTable.balance,
|
||||
centsToMicroCents((authInfo.billing.reloadTrigger ?? Billing.RELOAD_TRIGGER) * 100),
|
||||
),
|
||||
or(
|
||||
isNull(BillingTable.timeReloadLockedTill),
|
||||
lt(BillingTable.timeReloadLockedTill, sql`now()`),
|
||||
),
|
||||
or(isNull(BillingTable.timeReloadLockedTill), lt(BillingTable.timeReloadLockedTill, sql`now()`)),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -98,7 +98,10 @@ export function fromAnthropicRequest(body: any): CommonRequest {
|
||||
typeof (src as any).media_type === "string" &&
|
||||
typeof (src as any).data === "string"
|
||||
)
|
||||
return { type: "image_url", image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` } }
|
||||
return {
|
||||
type: "image_url",
|
||||
image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` },
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -165,7 +168,11 @@ export function fromAnthropicRequest(body: any): CommonRequest {
|
||||
.filter((t: any) => t && typeof t === "object" && "input_schema" in t)
|
||||
.map((t: any) => ({
|
||||
type: "function",
|
||||
function: { name: (t as any).name, description: (t as any).description, parameters: (t as any).input_schema },
|
||||
function: {
|
||||
name: (t as any).name,
|
||||
description: (t as any).description,
|
||||
parameters: (t as any).input_schema,
|
||||
},
|
||||
}))
|
||||
: undefined
|
||||
|
||||
@@ -452,7 +459,12 @@ export function toAnthropicResponse(resp: CommonResponse) {
|
||||
} catch {
|
||||
input = (tc as any).function.arguments
|
||||
}
|
||||
content.push({ type: "tool_use", id: (tc as any).id, name: (tc as any).function.name, input })
|
||||
content.push({
|
||||
type: "tool_use",
|
||||
id: (tc as any).id,
|
||||
name: (tc as any).function.name,
|
||||
input,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -511,13 +523,22 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
|
||||
if (json.type === "content_block_start") {
|
||||
const cb = json.content_block
|
||||
if (cb?.type === "text") {
|
||||
out.choices.push({ index: json.index ?? 0, delta: { role: "assistant", content: "" }, finish_reason: null })
|
||||
out.choices.push({
|
||||
index: json.index ?? 0,
|
||||
delta: { role: "assistant", content: "" },
|
||||
finish_reason: null,
|
||||
})
|
||||
} else if (cb?.type === "tool_use") {
|
||||
out.choices.push({
|
||||
index: json.index ?? 0,
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{ index: json.index ?? 0, id: cb.id, type: "function", function: { name: cb.name, arguments: "" } },
|
||||
{
|
||||
index: json.index ?? 0,
|
||||
id: cb.id,
|
||||
type: "function",
|
||||
function: { name: cb.name, arguments: "" },
|
||||
},
|
||||
],
|
||||
},
|
||||
finish_reason: null,
|
||||
@@ -532,7 +553,9 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
|
||||
} else if (d?.type === "input_json_delta") {
|
||||
out.choices.push({
|
||||
index: json.index ?? 0,
|
||||
delta: { tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }] },
|
||||
delta: {
|
||||
tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }],
|
||||
},
|
||||
finish_reason: null,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -532,7 +532,9 @@ export function toOaCompatibleChunk(chunk: CommonChunk): string {
|
||||
total_tokens: chunk.usage.total_tokens,
|
||||
...(chunk.usage.prompt_tokens_details?.cached_tokens
|
||||
? {
|
||||
prompt_tokens_details: { cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens },
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
|
||||
@@ -77,7 +77,10 @@ export function fromOpenaiRequest(body: any): CommonRequest {
|
||||
typeof (s as any).media_type === "string" &&
|
||||
typeof (s as any).data === "string"
|
||||
)
|
||||
return { type: "image_url", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } }
|
||||
return {
|
||||
type: "image_url",
|
||||
image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` },
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -153,7 +156,11 @@ export function fromOpenaiRequest(body: any): CommonRequest {
|
||||
}
|
||||
|
||||
if ((m as any).role === "tool") {
|
||||
msgs.push({ role: "tool", tool_call_id: (m as any).tool_call_id, content: (m as any).content })
|
||||
msgs.push({
|
||||
role: "tool",
|
||||
tool_call_id: (m as any).tool_call_id,
|
||||
content: (m as any).content,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -210,7 +217,10 @@ export function toOpenaiRequest(body: CommonRequest) {
|
||||
typeof (s as any).media_type === "string" &&
|
||||
typeof (s as any).data === "string"
|
||||
)
|
||||
return { type: "input_image", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } }
|
||||
return {
|
||||
type: "input_image",
|
||||
image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` },
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -498,7 +508,9 @@ export function fromOpenaiChunk(chunk: string): CommonChunk | string {
|
||||
if (typeof name === "string" && name.length > 0) {
|
||||
out.choices.push({
|
||||
index: 0,
|
||||
delta: { tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }] },
|
||||
delta: {
|
||||
tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }],
|
||||
},
|
||||
finish_reason: null,
|
||||
})
|
||||
}
|
||||
@@ -555,7 +567,12 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
|
||||
const model = chunk.model
|
||||
|
||||
if (d.content) {
|
||||
const data = { id, type: "response.output_text.delta", delta: d.content, response: { id, model } }
|
||||
const data = {
|
||||
id,
|
||||
type: "response.output_text.delta",
|
||||
delta: d.content,
|
||||
response: { id, model },
|
||||
}
|
||||
return `event: response.output_text.delta\ndata: ${JSON.stringify(data)}`
|
||||
}
|
||||
|
||||
@@ -565,7 +582,13 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
|
||||
const data = {
|
||||
type: "response.output_item.added",
|
||||
output_index: 0,
|
||||
item: { id: tc.id, type: "function_call", name: tc.function.name, call_id: tc.id, arguments: "" },
|
||||
item: {
|
||||
id: tc.id,
|
||||
type: "function_call",
|
||||
name: tc.function.name,
|
||||
call_id: tc.id,
|
||||
arguments: "",
|
||||
},
|
||||
}
|
||||
return `event: response.output_item.added\ndata: ${JSON.stringify(data)}`
|
||||
}
|
||||
@@ -593,7 +616,11 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
|
||||
}
|
||||
: undefined
|
||||
|
||||
const data: any = { id, type: "response.completed", response: { id, model, ...(usage ? { usage } : {}) } }
|
||||
const data: any = {
|
||||
id,
|
||||
type: "response.completed",
|
||||
response: { id, model, ...(usage ? { usage } : {}) },
|
||||
}
|
||||
return `event: response.completed\ndata: ${JSON.stringify(data)}`
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Resource } from "@opencode-ai/console-resource"
|
||||
import { RateLimitError } from "./error"
|
||||
import { logger } from "./logger"
|
||||
|
||||
export function createRateLimiter(model: string, limit: number | undefined, ip: string) {
|
||||
if (!limit) return
|
||||
|
||||
const now = Date.now()
|
||||
const currKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now)}`
|
||||
const prevKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now - 3_600_000)}`
|
||||
let currRate: number
|
||||
let prevRate: number
|
||||
|
||||
return {
|
||||
track: async () => {
|
||||
await Resource.GatewayKv.put(currKey, currRate + 1, { expirationTtl: 3600 })
|
||||
},
|
||||
check: async () => {
|
||||
const values = await Resource.GatewayKv.get([currKey, prevKey])
|
||||
const prevValue = values?.get(prevKey)
|
||||
const currValue = values?.get(currKey)
|
||||
prevRate = prevValue ? parseInt(prevValue) : 0
|
||||
currRate = currValue ? parseInt(currValue) : 0
|
||||
logger.debug(`rate limit ${model} prev/curr: ${prevRate}/${currRate}`)
|
||||
if (prevRate + currRate >= limit) throw new RateLimitError(`Rate limit exceeded. Please try again later.`)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function buildYYYYMMDDHH(timestamp: number) {
|
||||
return new Date(timestamp)
|
||||
.toISOString()
|
||||
.replace(/[^0-9]/g, "")
|
||||
.substring(0, 10)
|
||||
}
|
||||
@@ -50,10 +50,7 @@ export async function GET(input: APIEvent) {
|
||||
})
|
||||
.from(KeyTable)
|
||||
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
||||
.leftJoin(
|
||||
ModelTable,
|
||||
and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)),
|
||||
)
|
||||
.leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)))
|
||||
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
||||
.then((rows) => rows.map((row) => row.model)),
|
||||
)
|
||||
|
||||
Vendored
+1
-1
@@ -6,4 +6,4 @@
|
||||
/// <reference path="../../../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
export {}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,17 +473,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -504,10 +486,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -599,10 +578,7 @@
|
||||
"indexes": {
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -610,10 +586,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -670,9 +643,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -680,9 +651,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -699,4 +668,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,17 +473,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -504,10 +486,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -599,10 +578,7 @@
|
||||
"indexes": {
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -610,10 +586,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -670,9 +643,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -680,9 +651,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -699,4 +668,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,17 +473,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -504,10 +486,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -592,10 +571,7 @@
|
||||
"indexes": {
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -603,10 +579,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -663,9 +636,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -673,9 +644,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -692,4 +661,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,17 +473,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -504,10 +486,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -599,10 +578,7 @@
|
||||
"indexes": {
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -610,10 +586,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -670,9 +643,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -680,9 +651,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -699,4 +668,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,17 +473,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -504,10 +486,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -613,18 +592,12 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -632,10 +605,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -692,9 +662,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -702,9 +670,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -721,4 +687,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,17 +473,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -504,10 +486,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -613,32 +592,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -646,10 +615,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -706,9 +672,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -716,9 +680,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -735,4 +697,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,17 +473,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -504,10 +486,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -599,32 +578,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -632,10 +601,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -692,9 +658,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -702,9 +666,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -721,4 +683,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -493,17 +480,12 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"name"
|
||||
],
|
||||
"columns": ["workspace_id", "name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -511,10 +493,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -606,32 +585,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -639,10 +608,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -699,9 +665,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -709,9 +673,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -728,4 +690,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -493,9 +480,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -503,10 +488,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -598,32 +580,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -631,10 +603,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -691,9 +660,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -701,9 +668,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -720,4 +685,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -479,9 +466,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -489,10 +474,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -584,32 +566,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -617,10 +589,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -677,9 +646,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -687,9 +654,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -706,4 +671,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -479,9 +466,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -489,10 +474,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -584,32 +566,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -617,10 +589,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -677,9 +646,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -687,9 +654,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -706,4 +671,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -479,9 +466,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -489,10 +474,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -605,32 +587,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -638,10 +610,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -698,9 +667,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -708,9 +675,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -727,4 +692,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -479,9 +466,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -489,10 +474,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -549,10 +531,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -560,10 +539,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -676,32 +652,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -709,10 +675,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -769,9 +732,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -779,9 +740,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -798,4 +757,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -398,10 +388,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -479,9 +466,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -489,10 +474,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -549,10 +531,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -560,10 +539,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -627,10 +603,7 @@
|
||||
"indexes": {
|
||||
"workspace_provider": {
|
||||
"name": "workspace_provider",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"provider"
|
||||
],
|
||||
"columns": ["workspace_id", "provider"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -638,10 +611,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"provider_workspace_id_id_pk": {
|
||||
"name": "provider_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -754,32 +724,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -787,10 +747,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -847,9 +804,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -857,9 +812,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -876,4 +829,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -180,9 +178,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -190,10 +186,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -280,10 +273,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -405,10 +395,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -486,9 +473,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -496,10 +481,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -556,10 +538,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -567,10 +546,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -634,10 +610,7 @@
|
||||
"indexes": {
|
||||
"workspace_provider": {
|
||||
"name": "workspace_provider",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"provider"
|
||||
],
|
||||
"columns": ["workspace_id", "provider"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -645,10 +618,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"provider_workspace_id_id_pk": {
|
||||
"name": "provider_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -761,32 +731,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -794,10 +754,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -854,9 +811,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -864,9 +819,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -883,4 +836,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -187,9 +185,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -197,10 +193,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -287,10 +280,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -412,10 +402,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -493,9 +480,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -503,10 +488,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -563,10 +545,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -574,10 +553,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -641,10 +617,7 @@
|
||||
"indexes": {
|
||||
"workspace_provider": {
|
||||
"name": "workspace_provider",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"provider"
|
||||
],
|
||||
"columns": ["workspace_id", "provider"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -652,10 +625,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"provider_workspace_id_id_pk": {
|
||||
"name": "provider_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -768,32 +738,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -801,10 +761,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -861,9 +818,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -871,9 +826,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -890,4 +843,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"indexes": {
|
||||
"email": {
|
||||
"name": "email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -117,10 +115,7 @@
|
||||
"indexes": {
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"columns": [
|
||||
"provider",
|
||||
"subject"
|
||||
],
|
||||
"columns": ["provider", "subject"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -257,9 +252,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -267,10 +260,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -357,10 +347,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -482,10 +469,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -563,9 +547,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -573,10 +555,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -633,10 +612,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -644,10 +620,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -711,10 +684,7 @@
|
||||
"indexes": {
|
||||
"workspace_provider": {
|
||||
"name": "workspace_provider",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"provider"
|
||||
],
|
||||
"columns": ["workspace_id", "provider"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -722,10 +692,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"provider_workspace_id_id_pk": {
|
||||
"name": "provider_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -838,32 +805,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -871,10 +828,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -931,9 +885,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -941,9 +893,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -960,4 +910,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,17 +102,12 @@
|
||||
"indexes": {
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"columns": [
|
||||
"provider",
|
||||
"subject"
|
||||
],
|
||||
"columns": ["provider", "subject"],
|
||||
"isUnique": true
|
||||
},
|
||||
"account_id": {
|
||||
"name": "account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -249,9 +244,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -259,10 +252,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -349,10 +339,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -474,10 +461,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -555,9 +539,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -565,10 +547,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -625,10 +604,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -636,10 +612,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -703,10 +676,7 @@
|
||||
"indexes": {
|
||||
"workspace_provider": {
|
||||
"name": "workspace_provider",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"provider"
|
||||
],
|
||||
"columns": ["workspace_id", "provider"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -714,10 +684,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"provider_workspace_id_id_pk": {
|
||||
"name": "provider_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -830,32 +797,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -863,10 +820,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -923,9 +877,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -933,9 +885,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -952,4 +902,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"account_id_pk": {
|
||||
"name": "account_id_pk",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -109,17 +107,12 @@
|
||||
"indexes": {
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"columns": [
|
||||
"provider",
|
||||
"subject"
|
||||
],
|
||||
"columns": ["provider", "subject"],
|
||||
"isUnique": true
|
||||
},
|
||||
"account_id": {
|
||||
"name": "account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -127,9 +120,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"auth_id_pk": {
|
||||
"name": "auth_id_pk",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -263,9 +254,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -273,10 +262,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -363,10 +349,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -488,10 +471,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -569,9 +549,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -579,10 +557,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -639,10 +614,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -650,10 +622,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -717,10 +686,7 @@
|
||||
"indexes": {
|
||||
"workspace_provider": {
|
||||
"name": "workspace_provider",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"provider"
|
||||
],
|
||||
"columns": ["workspace_id", "provider"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -728,10 +694,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"provider_workspace_id_id_pk": {
|
||||
"name": "provider_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -844,32 +807,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -877,10 +830,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -937,9 +887,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -947,9 +895,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -966,4 +912,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"account_id_pk": {
|
||||
"name": "account_id_pk",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -109,17 +107,12 @@
|
||||
"indexes": {
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"columns": [
|
||||
"provider",
|
||||
"subject"
|
||||
],
|
||||
"columns": ["provider", "subject"],
|
||||
"isUnique": true
|
||||
},
|
||||
"account_id": {
|
||||
"name": "account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -127,9 +120,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"auth_id_pk": {
|
||||
"name": "auth_id_pk",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -277,9 +268,7 @@
|
||||
"indexes": {
|
||||
"global_customer_id": {
|
||||
"name": "global_customer_id",
|
||||
"columns": [
|
||||
"customer_id"
|
||||
],
|
||||
"columns": ["customer_id"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -287,10 +276,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"billing_workspace_id_id_pk": {
|
||||
"name": "billing_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -377,10 +363,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"payment_workspace_id_id_pk": {
|
||||
"name": "payment_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -502,10 +485,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"usage_workspace_id_id_pk": {
|
||||
"name": "usage_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -583,9 +563,7 @@
|
||||
"indexes": {
|
||||
"global_key": {
|
||||
"name": "global_key",
|
||||
"columns": [
|
||||
"key"
|
||||
],
|
||||
"columns": ["key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -593,10 +571,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"key_workspace_id_id_pk": {
|
||||
"name": "key_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -653,10 +628,7 @@
|
||||
"indexes": {
|
||||
"model_workspace_model": {
|
||||
"name": "model_workspace_model",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"model"
|
||||
],
|
||||
"columns": ["workspace_id", "model"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -664,10 +636,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"model_workspace_id_id_pk": {
|
||||
"name": "model_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -731,10 +700,7 @@
|
||||
"indexes": {
|
||||
"workspace_provider": {
|
||||
"name": "workspace_provider",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"provider"
|
||||
],
|
||||
"columns": ["workspace_id", "provider"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -742,10 +708,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"provider_workspace_id_id_pk": {
|
||||
"name": "provider_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -858,32 +821,22 @@
|
||||
"indexes": {
|
||||
"user_account_id": {
|
||||
"name": "user_account_id",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["workspace_id", "account_id"],
|
||||
"isUnique": true
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"email"
|
||||
],
|
||||
"columns": ["workspace_id", "email"],
|
||||
"isUnique": true
|
||||
},
|
||||
"global_account_id": {
|
||||
"name": "global_account_id",
|
||||
"columns": [
|
||||
"account_id"
|
||||
],
|
||||
"columns": ["account_id"],
|
||||
"isUnique": false
|
||||
},
|
||||
"global_email": {
|
||||
"name": "global_email",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -891,10 +844,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_workspace_id_id_pk": {
|
||||
"name": "user_workspace_id_id_pk",
|
||||
"columns": [
|
||||
"workspace_id",
|
||||
"id"
|
||||
]
|
||||
"columns": ["workspace_id", "id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -951,9 +901,7 @@
|
||||
"indexes": {
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -961,9 +909,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -980,4 +926,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,4 +269,4 @@
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -8,22 +8,15 @@ if (!email) {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const authData = await printTable("Auth", (tx) =>
|
||||
tx.select().from(AuthTable).where(eq(AuthTable.subject, email)),
|
||||
)
|
||||
const authData = await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.subject, email)))
|
||||
if (authData.length === 0) {
|
||||
console.error("User not found")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
await printTable("Auth", (tx) =>
|
||||
tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID)),
|
||||
)
|
||||
await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID)))
|
||||
|
||||
function printTable(
|
||||
title: string,
|
||||
callback: (tx: Database.TxOrDb) => Promise<any[]>,
|
||||
): Promise<any[]> {
|
||||
function printTable(title: string, callback: (tx: Database.TxOrDb) => Promise<any[]>): Promise<any[]> {
|
||||
return Database.use(async (tx) => {
|
||||
const data = await callback(tx)
|
||||
console.log(`== ${title} ==`)
|
||||
|
||||
@@ -8,14 +8,6 @@ import { KeyTable } from "../src/schema/key.sql.js"
|
||||
|
||||
if (Resource.App.stage !== "frank") throw new Error("This script is only for frank")
|
||||
|
||||
for (const table of [
|
||||
AccountTable,
|
||||
BillingTable,
|
||||
KeyTable,
|
||||
PaymentTable,
|
||||
UsageTable,
|
||||
UserTable,
|
||||
WorkspaceTable,
|
||||
]) {
|
||||
for (const table of [AccountTable, BillingTable, KeyTable, PaymentTable, UsageTable, UserTable, WorkspaceTable]) {
|
||||
await Database.use((tx) => tx.delete(table))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { ZenData } from "../src/model"
|
||||
|
||||
const root = path.resolve(process.cwd(), "..", "..", "..")
|
||||
const models = await $`bun sst secret list`.cwd(root).text()
|
||||
console.log("models", models)
|
||||
|
||||
// read the line starting with "ZEN_MODELS"
|
||||
const oldValue1 = models
|
||||
|
||||
@@ -24,6 +24,7 @@ export namespace ZenData {
|
||||
cost: ModelCostSchema,
|
||||
cost200K: ModelCostSchema.optional(),
|
||||
allowAnonymous: z.boolean().optional(),
|
||||
rateLimit: z.number().optional(),
|
||||
providers: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
@@ -60,9 +61,7 @@ export namespace Model {
|
||||
export const enable = fn(z.object({ model: z.string() }), ({ model }) => {
|
||||
Actor.assertAdmin()
|
||||
return Database.use((db) =>
|
||||
db
|
||||
.delete(ModelTable)
|
||||
.where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))),
|
||||
db.delete(ModelTable).where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))),
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
Vendored
+78
-69
@@ -6,99 +6,108 @@
|
||||
import "sst"
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"ADMIN_SECRET": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
ADMIN_SECRET: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"AUTH_API_URL": {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
AUTH_API_URL: {
|
||||
type: "sst.sst.Linkable"
|
||||
value: string
|
||||
}
|
||||
"AWS_SES_ACCESS_KEY_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
AWS_SES_ACCESS_KEY_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"AWS_SES_SECRET_ACCESS_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
AWS_SES_SECRET_ACCESS_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Console": {
|
||||
"type": "sst.cloudflare.SolidStart"
|
||||
"url": string
|
||||
CLOUDFLARE_API_TOKEN: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Database": {
|
||||
"database": string
|
||||
"host": string
|
||||
"password": string
|
||||
"port": number
|
||||
"type": "sst.sst.Linkable"
|
||||
"username": string
|
||||
CLOUDFLARE_DEFAULT_ACCOUNT_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Desktop": {
|
||||
"type": "sst.cloudflare.StaticSite"
|
||||
"url": string
|
||||
Console: {
|
||||
type: "sst.cloudflare.SolidStart"
|
||||
url: string
|
||||
}
|
||||
"EMAILOCTOPUS_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Database: {
|
||||
database: string
|
||||
host: string
|
||||
password: string
|
||||
port: number
|
||||
type: "sst.sst.Linkable"
|
||||
username: string
|
||||
}
|
||||
"GITHUB_APP_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Desktop: {
|
||||
type: "sst.cloudflare.StaticSite"
|
||||
url: string
|
||||
}
|
||||
"GITHUB_APP_PRIVATE_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
EMAILOCTOPUS_API_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GITHUB_CLIENT_ID_CONSOLE": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_APP_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GITHUB_CLIENT_SECRET_CONSOLE": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_APP_PRIVATE_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GOOGLE_CLIENT_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_CLIENT_ID_CONSOLE: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"HONEYCOMB_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_CLIENT_SECRET_CONSOLE: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"STRIPE_SECRET_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GOOGLE_CLIENT_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"STRIPE_WEBHOOK_SECRET": {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
HONEYCOMB_API_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Web": {
|
||||
"type": "sst.cloudflare.Astro"
|
||||
"url": string
|
||||
STRIPE_SECRET_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"ZEN_MODELS1": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
STRIPE_WEBHOOK_SECRET: {
|
||||
type: "sst.sst.Linkable"
|
||||
value: string
|
||||
}
|
||||
"ZEN_MODELS2": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Web: {
|
||||
type: "sst.cloudflare.Astro"
|
||||
url: string
|
||||
}
|
||||
ZEN_MODELS1: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
ZEN_MODELS2: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
}
|
||||
}
|
||||
// cloudflare
|
||||
import * as cloudflare from "@cloudflare/workers-types";
|
||||
// cloudflare
|
||||
import * as cloudflare from "@cloudflare/workers-types"
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"Api": cloudflare.Service
|
||||
"AuthApi": cloudflare.Service
|
||||
"AuthStorage": cloudflare.KVNamespace
|
||||
"Bucket": cloudflare.R2Bucket
|
||||
"LogProcessor": cloudflare.Service
|
||||
Api: cloudflare.Service
|
||||
AuthApi: cloudflare.Service
|
||||
AuthStorage: cloudflare.KVNamespace
|
||||
Bucket: cloudflare.R2Bucket
|
||||
GatewayKv: cloudflare.KVNamespace
|
||||
LogProcessor: cloudflare.Service
|
||||
}
|
||||
}
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
export {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
+78
-69
@@ -6,99 +6,108 @@
|
||||
import "sst"
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"ADMIN_SECRET": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
ADMIN_SECRET: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"AUTH_API_URL": {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
AUTH_API_URL: {
|
||||
type: "sst.sst.Linkable"
|
||||
value: string
|
||||
}
|
||||
"AWS_SES_ACCESS_KEY_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
AWS_SES_ACCESS_KEY_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"AWS_SES_SECRET_ACCESS_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
AWS_SES_SECRET_ACCESS_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Console": {
|
||||
"type": "sst.cloudflare.SolidStart"
|
||||
"url": string
|
||||
CLOUDFLARE_API_TOKEN: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Database": {
|
||||
"database": string
|
||||
"host": string
|
||||
"password": string
|
||||
"port": number
|
||||
"type": "sst.sst.Linkable"
|
||||
"username": string
|
||||
CLOUDFLARE_DEFAULT_ACCOUNT_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Desktop": {
|
||||
"type": "sst.cloudflare.StaticSite"
|
||||
"url": string
|
||||
Console: {
|
||||
type: "sst.cloudflare.SolidStart"
|
||||
url: string
|
||||
}
|
||||
"EMAILOCTOPUS_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Database: {
|
||||
database: string
|
||||
host: string
|
||||
password: string
|
||||
port: number
|
||||
type: "sst.sst.Linkable"
|
||||
username: string
|
||||
}
|
||||
"GITHUB_APP_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Desktop: {
|
||||
type: "sst.cloudflare.StaticSite"
|
||||
url: string
|
||||
}
|
||||
"GITHUB_APP_PRIVATE_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
EMAILOCTOPUS_API_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GITHUB_CLIENT_ID_CONSOLE": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_APP_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GITHUB_CLIENT_SECRET_CONSOLE": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_APP_PRIVATE_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GOOGLE_CLIENT_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_CLIENT_ID_CONSOLE: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"HONEYCOMB_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_CLIENT_SECRET_CONSOLE: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"STRIPE_SECRET_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GOOGLE_CLIENT_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"STRIPE_WEBHOOK_SECRET": {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
HONEYCOMB_API_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Web": {
|
||||
"type": "sst.cloudflare.Astro"
|
||||
"url": string
|
||||
STRIPE_SECRET_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"ZEN_MODELS1": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
STRIPE_WEBHOOK_SECRET: {
|
||||
type: "sst.sst.Linkable"
|
||||
value: string
|
||||
}
|
||||
"ZEN_MODELS2": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Web: {
|
||||
type: "sst.cloudflare.Astro"
|
||||
url: string
|
||||
}
|
||||
ZEN_MODELS1: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
ZEN_MODELS2: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
}
|
||||
}
|
||||
// cloudflare
|
||||
import * as cloudflare from "@cloudflare/workers-types";
|
||||
// cloudflare
|
||||
import * as cloudflare from "@cloudflare/workers-types"
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"Api": cloudflare.Service
|
||||
"AuthApi": cloudflare.Service
|
||||
"AuthStorage": cloudflare.KVNamespace
|
||||
"Bucket": cloudflare.R2Bucket
|
||||
"LogProcessor": cloudflare.Service
|
||||
Api: cloudflare.Service
|
||||
AuthApi: cloudflare.Service
|
||||
AuthStorage: cloudflare.KVNamespace
|
||||
Bucket: cloudflare.R2Bucket
|
||||
GatewayKv: cloudflare.KVNamespace
|
||||
LogProcessor: cloudflare.Service
|
||||
}
|
||||
}
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
export {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
|
||||
Vendored
+1
-1
@@ -6,4 +6,4 @@
|
||||
/// <reference path="../../../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
export {}
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node22": "22.0.2"
|
||||
"@cloudflare/workers-types": "catalog:",
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
"@types/node": "catalog:",
|
||||
"cloudflare": "5.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,58 @@
|
||||
export { Resource } from "sst"
|
||||
import type { KVNamespaceListOptions, KVNamespaceListResult, KVNamespacePutOptions } from "@cloudflare/workers-types"
|
||||
import { Resource as ResourceBase } from "sst"
|
||||
import Cloudflare from "cloudflare"
|
||||
|
||||
export const Resource = new Proxy(
|
||||
{},
|
||||
{
|
||||
get(_target, prop: keyof typeof ResourceBase) {
|
||||
const value = ResourceBase[prop]
|
||||
// @ts-ignore
|
||||
if ("type" in value && value.type === "sst.cloudflare.Kv") {
|
||||
const client = new Cloudflare({
|
||||
apiToken: ResourceBase.CLOUDFLARE_API_TOKEN.value,
|
||||
})
|
||||
// @ts-ignore
|
||||
const namespaceId = value.namespaceId
|
||||
const accountId = ResourceBase.CLOUDFLARE_DEFAULT_ACCOUNT_ID.value
|
||||
return {
|
||||
get: (k: string | string[]) => {
|
||||
const isMulti = Array.isArray(k)
|
||||
return client.kv.namespaces
|
||||
.bulkGet(namespaceId, {
|
||||
keys: Array.isArray(k) ? k : [k],
|
||||
account_id: accountId,
|
||||
})
|
||||
.then((result) => (isMulti ? new Map(Object.entries(result?.values ?? {})) : result?.values?.[k]))
|
||||
},
|
||||
put: (k: string, v: string, opts?: KVNamespacePutOptions) =>
|
||||
client.kv.namespaces.values.update(namespaceId, k, {
|
||||
account_id: accountId,
|
||||
value: v,
|
||||
expiration: opts?.expiration,
|
||||
expiration_ttl: opts?.expirationTtl,
|
||||
metadata: opts?.metadata,
|
||||
}),
|
||||
delete: (k: string) =>
|
||||
client.kv.namespaces.values.delete(namespaceId, k, {
|
||||
account_id: accountId,
|
||||
}),
|
||||
list: (opts?: KVNamespaceListOptions): Promise<KVNamespaceListResult<unknown, string>> =>
|
||||
client.kv.namespaces.keys
|
||||
.list(namespaceId, {
|
||||
account_id: accountId,
|
||||
prefix: opts?.prefix ?? undefined,
|
||||
})
|
||||
.then((result) => {
|
||||
return {
|
||||
keys: result.result,
|
||||
list_complete: true,
|
||||
cacheStatus: null,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
return value
|
||||
},
|
||||
},
|
||||
) as Record<string, any>
|
||||
|
||||
+78
-69
@@ -6,99 +6,108 @@
|
||||
import "sst"
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"ADMIN_SECRET": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
ADMIN_SECRET: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"AUTH_API_URL": {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
AUTH_API_URL: {
|
||||
type: "sst.sst.Linkable"
|
||||
value: string
|
||||
}
|
||||
"AWS_SES_ACCESS_KEY_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
AWS_SES_ACCESS_KEY_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"AWS_SES_SECRET_ACCESS_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
AWS_SES_SECRET_ACCESS_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Console": {
|
||||
"type": "sst.cloudflare.SolidStart"
|
||||
"url": string
|
||||
CLOUDFLARE_API_TOKEN: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Database": {
|
||||
"database": string
|
||||
"host": string
|
||||
"password": string
|
||||
"port": number
|
||||
"type": "sst.sst.Linkable"
|
||||
"username": string
|
||||
CLOUDFLARE_DEFAULT_ACCOUNT_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Desktop": {
|
||||
"type": "sst.cloudflare.StaticSite"
|
||||
"url": string
|
||||
Console: {
|
||||
type: "sst.cloudflare.SolidStart"
|
||||
url: string
|
||||
}
|
||||
"EMAILOCTOPUS_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Database: {
|
||||
database: string
|
||||
host: string
|
||||
password: string
|
||||
port: number
|
||||
type: "sst.sst.Linkable"
|
||||
username: string
|
||||
}
|
||||
"GITHUB_APP_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Desktop: {
|
||||
type: "sst.cloudflare.StaticSite"
|
||||
url: string
|
||||
}
|
||||
"GITHUB_APP_PRIVATE_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
EMAILOCTOPUS_API_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GITHUB_CLIENT_ID_CONSOLE": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_APP_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GITHUB_CLIENT_SECRET_CONSOLE": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_APP_PRIVATE_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"GOOGLE_CLIENT_ID": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_CLIENT_ID_CONSOLE: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"HONEYCOMB_API_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GITHUB_CLIENT_SECRET_CONSOLE: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"STRIPE_SECRET_KEY": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
GOOGLE_CLIENT_ID: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"STRIPE_WEBHOOK_SECRET": {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
HONEYCOMB_API_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"Web": {
|
||||
"type": "sst.cloudflare.Astro"
|
||||
"url": string
|
||||
STRIPE_SECRET_KEY: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
"ZEN_MODELS1": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
STRIPE_WEBHOOK_SECRET: {
|
||||
type: "sst.sst.Linkable"
|
||||
value: string
|
||||
}
|
||||
"ZEN_MODELS2": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
Web: {
|
||||
type: "sst.cloudflare.Astro"
|
||||
url: string
|
||||
}
|
||||
ZEN_MODELS1: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
ZEN_MODELS2: {
|
||||
type: "sst.sst.Secret"
|
||||
value: string
|
||||
}
|
||||
}
|
||||
}
|
||||
// cloudflare
|
||||
import * as cloudflare from "@cloudflare/workers-types";
|
||||
// cloudflare
|
||||
import * as cloudflare from "@cloudflare/workers-types"
|
||||
declare module "sst" {
|
||||
export interface Resource {
|
||||
"Api": cloudflare.Service
|
||||
"AuthApi": cloudflare.Service
|
||||
"AuthStorage": cloudflare.KVNamespace
|
||||
"Bucket": cloudflare.R2Bucket
|
||||
"LogProcessor": cloudflare.Service
|
||||
Api: cloudflare.Service
|
||||
AuthApi: cloudflare.Service
|
||||
AuthStorage: cloudflare.KVNamespace
|
||||
Bucket: cloudflare.R2Bucket
|
||||
GatewayKv: cloudflare.KVNamespace
|
||||
LogProcessor: cloudflare.Service
|
||||
}
|
||||
}
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
export {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.48",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -46,9 +46,5 @@
|
||||
"solid-list": "catalog:",
|
||||
"tailwindcss": "catalog:",
|
||||
"virtua": "catalog:"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 120
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,846 +0,0 @@
|
||||
import { bundledLanguages, type BundledLanguage, type ShikiTransformer } from "shiki"
|
||||
import { splitProps, type ComponentProps, createEffect, onMount, onCleanup, createMemo, createResource } from "solid-js"
|
||||
import { useLocal, type TextSelection } from "@/context/local"
|
||||
import { getFileExtension, getNodeOffsetInLine, getSelectionInContainer } from "@/utils"
|
||||
import { useShiki } from "@opencode-ai/ui"
|
||||
|
||||
type DefinedSelection = Exclude<TextSelection, undefined>
|
||||
|
||||
interface Props extends ComponentProps<"div"> {
|
||||
code: string
|
||||
path: string
|
||||
}
|
||||
|
||||
export function Code(props: Props) {
|
||||
const ctx = useLocal()
|
||||
const highlighter = useShiki()
|
||||
const [local, others] = splitProps(props, ["class", "classList", "code", "path"])
|
||||
const lang = createMemo(() => {
|
||||
const ext = getFileExtension(local.path)
|
||||
if (ext in bundledLanguages) return ext
|
||||
return "text"
|
||||
})
|
||||
|
||||
let container: HTMLDivElement | undefined
|
||||
let isProgrammaticSelection = false
|
||||
|
||||
const ranges = createMemo<DefinedSelection[]>(() => {
|
||||
const items = ctx.context.all() as Array<{ type: "file"; path: string; selection?: DefinedSelection }>
|
||||
const result: DefinedSelection[] = []
|
||||
for (const item of items) {
|
||||
if (item.path !== local.path) continue
|
||||
const selection = item.selection
|
||||
if (!selection) continue
|
||||
result.push(selection)
|
||||
}
|
||||
return result
|
||||
})
|
||||
|
||||
const createLineNumberTransformer = (selections: DefinedSelection[]): ShikiTransformer => {
|
||||
const highlighted = new Set<number>()
|
||||
for (const selection of selections) {
|
||||
const startLine = selection.startLine
|
||||
const endLine = selection.endLine
|
||||
const start = Math.max(1, Math.min(startLine, endLine))
|
||||
const end = Math.max(start, Math.max(startLine, endLine))
|
||||
const count = end - start + 1
|
||||
if (count <= 0) continue
|
||||
const values = Array.from({ length: count }, (_, index) => start + index)
|
||||
for (const value of values) highlighted.add(value)
|
||||
}
|
||||
return {
|
||||
name: "line-number-highlight",
|
||||
line(node, index) {
|
||||
if (!highlighted.has(index)) return
|
||||
this.addClassToHast(node, "line-number-highlight")
|
||||
const children = node.children
|
||||
if (!Array.isArray(children)) return
|
||||
for (const child of children) {
|
||||
if (!child || typeof child !== "object") continue
|
||||
const element = child as { type?: string; properties?: { className?: string[] } }
|
||||
if (element.type !== "element") continue
|
||||
const className = element.properties?.className
|
||||
if (!Array.isArray(className)) continue
|
||||
const matches = className.includes("diff-oldln") || className.includes("diff-newln")
|
||||
if (!matches) continue
|
||||
if (className.includes("line-number-highlight")) continue
|
||||
className.push("line-number-highlight")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const [html] = createResource(
|
||||
() => ranges(),
|
||||
async (activeRanges) => {
|
||||
if (!highlighter.getLoadedLanguages().includes(lang())) {
|
||||
await highlighter.loadLanguage(lang() as BundledLanguage)
|
||||
}
|
||||
return highlighter.codeToHtml(local.code || "", {
|
||||
lang: lang() && lang() in bundledLanguages ? lang() : "text",
|
||||
theme: "opencode",
|
||||
transformers: [transformerUnifiedDiff(), transformerDiffGroups(), createLineNumberTransformer(activeRanges)],
|
||||
}) as string
|
||||
},
|
||||
)
|
||||
|
||||
onMount(() => {
|
||||
if (!container) return
|
||||
|
||||
let ticking = false
|
||||
const onScroll = () => {
|
||||
if (!container) return
|
||||
// if (ctx.file.active()?.path !== local.path) return
|
||||
if (ticking) return
|
||||
ticking = true
|
||||
requestAnimationFrame(() => {
|
||||
ticking = false
|
||||
ctx.file.scroll(local.path, container!.scrollTop)
|
||||
})
|
||||
}
|
||||
|
||||
const onSelectionChange = async () => {
|
||||
if (!container) return
|
||||
if (isProgrammaticSelection) return
|
||||
// if (ctx.file.active()?.path !== local.path) return
|
||||
const d = getSelectionInContainer(container)
|
||||
if (!d) return
|
||||
const p = (await ctx.file.node(local.path))?.selection
|
||||
if (p && p.startLine === d.sl && p.endLine === d.el && p.startChar === d.sch && p.endChar === d.ech) return
|
||||
ctx.file.select(local.path, { startLine: d.sl, startChar: d.sch, endLine: d.el, endChar: d.ech })
|
||||
}
|
||||
|
||||
const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control"
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
// if (ctx.file.active()?.path !== local.path) return
|
||||
const ae = document.activeElement as HTMLElement | undefined
|
||||
const tag = (ae?.tagName || "").toLowerCase()
|
||||
const inputFocused = !!ae && (tag === "input" || tag === "textarea" || ae.isContentEditable)
|
||||
if (inputFocused) return
|
||||
if (e.getModifierState(MOD) && e.key.toLowerCase() === "a") {
|
||||
e.preventDefault()
|
||||
if (!container) return
|
||||
const element = container.querySelector("code") as HTMLElement | undefined
|
||||
if (!element) return
|
||||
const lines = Array.from(element.querySelectorAll(".line"))
|
||||
if (!lines.length) return
|
||||
const r = document.createRange()
|
||||
const last = lines[lines.length - 1]
|
||||
r.selectNodeContents(last)
|
||||
const lastLen = r.toString().length
|
||||
ctx.file.select(local.path, { startLine: 1, startChar: 0, endLine: lines.length, endChar: lastLen })
|
||||
}
|
||||
}
|
||||
|
||||
container.addEventListener("scroll", onScroll)
|
||||
document.addEventListener("selectionchange", onSelectionChange)
|
||||
document.addEventListener("keydown", onKeyDown)
|
||||
|
||||
onCleanup(() => {
|
||||
container?.removeEventListener("scroll", onScroll)
|
||||
document.removeEventListener("selectionchange", onSelectionChange)
|
||||
document.removeEventListener("keydown", onKeyDown)
|
||||
})
|
||||
})
|
||||
|
||||
// Restore scroll position from store when content is ready
|
||||
createEffect(async () => {
|
||||
const content = html()
|
||||
if (!container || !content) return
|
||||
const top = (await ctx.file.node(local.path))?.scrollTop
|
||||
if (top !== undefined && container.scrollTop !== top) container.scrollTop = top
|
||||
})
|
||||
|
||||
// Sync selection from store -> DOM
|
||||
createEffect(async () => {
|
||||
const content = html()
|
||||
if (!container || !content) return
|
||||
// if (ctx.file.active()?.path !== local.path) return
|
||||
const codeEl = container.querySelector("code") as HTMLElement | undefined
|
||||
if (!codeEl) return
|
||||
const target = (await ctx.file.node(local.path))?.selection
|
||||
const current = getSelectionInContainer(container)
|
||||
const sel = window.getSelection()
|
||||
if (!sel) return
|
||||
if (!target) {
|
||||
if (current) {
|
||||
isProgrammaticSelection = true
|
||||
sel.removeAllRanges()
|
||||
queueMicrotask(() => {
|
||||
isProgrammaticSelection = false
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
const matches = !!(
|
||||
current &&
|
||||
current.sl === target.startLine &&
|
||||
current.sch === target.startChar &&
|
||||
current.el === target.endLine &&
|
||||
current.ech === target.endChar
|
||||
)
|
||||
if (matches) return
|
||||
const lines = Array.from(codeEl.querySelectorAll(".line"))
|
||||
if (lines.length === 0) return
|
||||
let sIdx = Math.max(0, target.startLine - 1)
|
||||
let eIdx = Math.max(0, target.endLine - 1)
|
||||
let sChar = Math.max(0, target.startChar || 0)
|
||||
let eChar = Math.max(0, target.endChar || 0)
|
||||
if (sIdx > eIdx || (sIdx === eIdx && sChar > eChar)) {
|
||||
const ti = sIdx
|
||||
sIdx = eIdx
|
||||
eIdx = ti
|
||||
const tc = sChar
|
||||
sChar = eChar
|
||||
eChar = tc
|
||||
}
|
||||
if (eChar === 0 && eIdx > sIdx) {
|
||||
eIdx = eIdx - 1
|
||||
eChar = Number.POSITIVE_INFINITY
|
||||
}
|
||||
if (sIdx >= lines.length) return
|
||||
if (eIdx >= lines.length) eIdx = lines.length - 1
|
||||
const s = getNodeOffsetInLine(lines[sIdx], sChar) ?? { node: lines[sIdx], offset: 0 }
|
||||
const e = getNodeOffsetInLine(lines[eIdx], eChar) ?? { node: lines[eIdx], offset: lines[eIdx].childNodes.length }
|
||||
const range = document.createRange()
|
||||
range.setStart(s.node, s.offset)
|
||||
range.setEnd(e.node, e.offset)
|
||||
isProgrammaticSelection = true
|
||||
sel.removeAllRanges()
|
||||
sel.addRange(range)
|
||||
queueMicrotask(() => {
|
||||
isProgrammaticSelection = false
|
||||
})
|
||||
})
|
||||
|
||||
// Build/toggle split layout and apply folding (both unified and split)
|
||||
createEffect(() => {
|
||||
const content = html()
|
||||
if (!container || !content) return
|
||||
const view = ctx.file.view(local.path)
|
||||
|
||||
const pres = Array.from(container.querySelectorAll<HTMLPreElement>("pre"))
|
||||
if (pres.length === 0) return
|
||||
const originalPre = pres[0]
|
||||
|
||||
const split = container.querySelector<HTMLElement>(".diff-split")
|
||||
if (view === "diff-split") {
|
||||
applySplitDiff(container)
|
||||
const next = container.querySelector<HTMLElement>(".diff-split")
|
||||
if (next) next.style.display = ""
|
||||
originalPre.style.display = "none"
|
||||
} else {
|
||||
if (split) split.style.display = "none"
|
||||
originalPre.style.display = ""
|
||||
}
|
||||
|
||||
const expanded = ctx.file.folded(local.path)
|
||||
if (view === "diff-split") {
|
||||
const left = container.querySelector<HTMLElement>(".diff-split pre:nth-child(1) code")
|
||||
const right = container.querySelector<HTMLElement>(".diff-split pre:nth-child(2) code")
|
||||
if (left)
|
||||
applyDiffFolding(left, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "left" })
|
||||
if (right)
|
||||
applyDiffFolding(right, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "right" })
|
||||
} else {
|
||||
const code = container.querySelector<HTMLElement>("pre code")
|
||||
if (code)
|
||||
applyDiffFolding(code, 3, {
|
||||
expanded,
|
||||
onExpand: (key) => ctx.file.unfold(local.path, key),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Highlight groups + scroll coupling
|
||||
const clearHighlights = () => {
|
||||
if (!container) return
|
||||
container.querySelectorAll<HTMLElement>(".diff-selected").forEach((el) => el.classList.remove("diff-selected"))
|
||||
}
|
||||
|
||||
const applyHighlight = (idx: number, scroll?: boolean) => {
|
||||
if (!container) return
|
||||
const view = ctx.file.view(local.path)
|
||||
if (view === "raw") return
|
||||
|
||||
clearHighlights()
|
||||
|
||||
const nodes: HTMLElement[] = []
|
||||
if (view === "diff-split") {
|
||||
const left = container.querySelector<HTMLElement>(".diff-split pre:nth-child(1) code")
|
||||
const right = container.querySelector<HTMLElement>(".diff-split pre:nth-child(2) code")
|
||||
if (left)
|
||||
nodes.push(...Array.from(left.querySelectorAll<HTMLElement>(`[data-chgrp="${idx}"][data-diff="remove"]`)))
|
||||
if (right)
|
||||
nodes.push(...Array.from(right.querySelectorAll<HTMLElement>(`[data-chgrp="${idx}"][data-diff="add"]`)))
|
||||
} else {
|
||||
const code = container.querySelector<HTMLElement>("pre code")
|
||||
if (code) nodes.push(...Array.from(code.querySelectorAll<HTMLElement>(`[data-chgrp="${idx}"]`)))
|
||||
}
|
||||
|
||||
for (const n of nodes) n.classList.add("diff-selected")
|
||||
if (scroll && nodes.length) nodes[0].scrollIntoView({ block: "center", behavior: "smooth" })
|
||||
}
|
||||
|
||||
const countGroups = () => {
|
||||
if (!container) return 0
|
||||
const code = container.querySelector<HTMLElement>("pre code")
|
||||
if (!code) return 0
|
||||
const set = new Set<string>()
|
||||
for (const el of Array.from(code.querySelectorAll<HTMLElement>(".diff-line[data-chgrp]"))) {
|
||||
const v = el.getAttribute("data-chgrp")
|
||||
if (v != undefined) set.add(v)
|
||||
}
|
||||
return set.size
|
||||
}
|
||||
|
||||
let lastIdx: number | undefined = undefined
|
||||
let lastView: string | undefined
|
||||
let lastContent: string | undefined
|
||||
let lastRawIdx: number | undefined = undefined
|
||||
createEffect(() => {
|
||||
const content = html()
|
||||
if (!container || !content) return
|
||||
const view = ctx.file.view(local.path)
|
||||
const raw = ctx.file.changeIndex(local.path)
|
||||
if (raw === undefined) return
|
||||
const total = countGroups()
|
||||
if (total <= 0) return
|
||||
const next = ((raw % total) + total) % total
|
||||
|
||||
const navigated = lastRawIdx !== undefined && lastRawIdx !== raw
|
||||
|
||||
if (next !== raw) {
|
||||
ctx.file.setChangeIndex(local.path, next)
|
||||
applyHighlight(next, true)
|
||||
} else {
|
||||
if (lastView !== view || lastContent !== content) applyHighlight(next)
|
||||
if ((lastIdx !== undefined && lastIdx !== next) || navigated) applyHighlight(next, true)
|
||||
}
|
||||
|
||||
lastRawIdx = raw
|
||||
lastIdx = next
|
||||
lastView = view
|
||||
lastContent = content
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={(el) => {
|
||||
container = el
|
||||
}}
|
||||
innerHTML={html()}
|
||||
class="
|
||||
font-mono text-xs tracking-wide overflow-y-auto h-full
|
||||
[&]:[counter-reset:line]
|
||||
[&_pre]:focus-visible:outline-none
|
||||
[&_pre]:overflow-x-auto [&_pre]:no-scrollbar
|
||||
[&_code]:min-w-full [&_code]:inline-block
|
||||
[&_.tab]:relative
|
||||
[&_.tab::before]:content['⇥']
|
||||
[&_.tab::before]:absolute
|
||||
[&_.tab::before]:opacity-0
|
||||
[&_.space]:relative
|
||||
[&_.space::before]:content-['·']
|
||||
[&_.space::before]:absolute
|
||||
[&_.space::before]:opacity-0
|
||||
[&_.line]:inline-block [&_.line]:w-full
|
||||
[&_.line]:hover:bg-background-element
|
||||
[&_.line::before]:sticky [&_.line::before]:left-0
|
||||
[&_.line::before]:w-12 [&_.line::before]:pr-4
|
||||
[&_.line::before]:z-10
|
||||
[&_.line::before]:bg-background-panel
|
||||
[&_.line::before]:text-text-muted/60
|
||||
[&_.line::before]:text-right [&_.line::before]:inline-block
|
||||
[&_.line::before]:select-none
|
||||
[&_.line::before]:[counter-increment:line]
|
||||
[&_.line::before]:content-[counter(line)]
|
||||
[&_.line-number-highlight]:bg-accent/20
|
||||
[&_.line-number-highlight::before]:bg-accent/40!
|
||||
[&_.line-number-highlight::before]:text-background-panel!
|
||||
[&_code.code-diff_.line::before]:content-['']
|
||||
[&_code.code-diff_.line::before]:w-0
|
||||
[&_code.code-diff_.line::before]:pr-0
|
||||
[&_.diff-split_code.code-diff::before]:w-10
|
||||
[&_.diff-split_.diff-newln]:left-0
|
||||
[&_.diff-oldln]:sticky [&_.diff-oldln]:left-0
|
||||
[&_.diff-oldln]:w-10 [&_.diff-oldln]:pr-2
|
||||
[&_.diff-oldln]:z-40
|
||||
[&_.diff-oldln]:text-text-muted/60
|
||||
[&_.diff-oldln]:text-right [&_.diff-oldln]:inline-block
|
||||
[&_.diff-oldln]:select-none
|
||||
[&_.diff-oldln]:bg-background-panel
|
||||
[&_.diff-newln]:sticky [&_.diff-newln]:left-10
|
||||
[&_.diff-newln]:w-10 [&_.diff-newln]:pr-2
|
||||
[&_.diff-newln]:z-40
|
||||
[&_.diff-newln]:text-text-muted/60
|
||||
[&_.diff-newln]:text-right [&_.diff-newln]:inline-block
|
||||
[&_.diff-newln]:select-none
|
||||
[&_.diff-newln]:bg-background-panel
|
||||
[&_.diff-add]:bg-success/20!
|
||||
[&_.diff-add.diff-selected]:bg-success/50!
|
||||
[&_.diff-add_.diff-oldln]:bg-success!
|
||||
[&_.diff-add_.diff-oldln]:text-background-panel!
|
||||
[&_.diff-add_.diff-newln]:bg-success!
|
||||
[&_.diff-add_.diff-newln]:text-background-panel!
|
||||
[&_.diff-remove]:bg-error/20!
|
||||
[&_.diff-remove.diff-selected]:bg-error/50!
|
||||
[&_.diff-remove_.diff-newln]:bg-error!
|
||||
[&_.diff-remove_.diff-newln]:text-background-panel!
|
||||
[&_.diff-remove_.diff-oldln]:bg-error!
|
||||
[&_.diff-remove_.diff-oldln]:text-background-panel!
|
||||
[&_.diff-sign]:inline-block [&_.diff-sign]:px-2 [&_.diff-sign]:select-none
|
||||
[&_.diff-blank]:bg-background-element
|
||||
[&_.diff-blank_.diff-oldln]:bg-background-element
|
||||
[&_.diff-blank_.diff-newln]:bg-background-element
|
||||
[&_.diff-collapsed]:block! [&_.diff-collapsed]:w-full [&_.diff-collapsed]:relative
|
||||
[&_.diff-collapsed]:select-none
|
||||
[&_.diff-collapsed]:bg-info/20 [&_.diff-collapsed]:hover:bg-info/40!
|
||||
[&_.diff-collapsed]:text-info/80 [&_.diff-collapsed]:hover:text-info
|
||||
[&_.diff-collapsed]:text-xs
|
||||
[&_.diff-collapsed_.diff-oldln]:bg-info!
|
||||
[&_.diff-collapsed_.diff-newln]:bg-info!
|
||||
"
|
||||
classList={{
|
||||
...(local.classList || {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
{...others}
|
||||
></div>
|
||||
)
|
||||
}
|
||||
|
||||
function transformerUnifiedDiff(): ShikiTransformer {
|
||||
const kinds = new Map<number, string>()
|
||||
const meta = new Map<number, { old?: number; new?: number; sign?: string }>()
|
||||
let isDiff = false
|
||||
|
||||
return {
|
||||
name: "unified-diff",
|
||||
preprocess(input) {
|
||||
kinds.clear()
|
||||
meta.clear()
|
||||
isDiff = false
|
||||
|
||||
const ls = input.split(/\r?\n/)
|
||||
const out: Array<string> = []
|
||||
let oldNo = 0
|
||||
let newNo = 0
|
||||
let inHunk = false
|
||||
|
||||
for (let i = 0; i < ls.length; i++) {
|
||||
const s = ls[i]
|
||||
|
||||
const m = s.match(/^@@\s*-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s*@@/)
|
||||
if (m) {
|
||||
isDiff = true
|
||||
inHunk = true
|
||||
oldNo = parseInt(m[1], 10)
|
||||
newNo = parseInt(m[3], 10)
|
||||
continue
|
||||
}
|
||||
|
||||
if (
|
||||
/^diff --git /.test(s) ||
|
||||
/^Index: /.test(s) ||
|
||||
/^--- /.test(s) ||
|
||||
/^\+\+\+ /.test(s) ||
|
||||
/^[=]{3,}$/.test(s) ||
|
||||
/^\*{3,}$/.test(s) ||
|
||||
/^\\ No newline at end of file$/.test(s)
|
||||
) {
|
||||
isDiff = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (!inHunk) {
|
||||
out.push(s)
|
||||
continue
|
||||
}
|
||||
|
||||
if (/^\+/.test(s)) {
|
||||
out.push(s)
|
||||
const ln = out.length
|
||||
kinds.set(ln, "add")
|
||||
meta.set(ln, { new: newNo, sign: "+" })
|
||||
newNo++
|
||||
continue
|
||||
}
|
||||
|
||||
if (/^-/.test(s)) {
|
||||
out.push(s)
|
||||
const ln = out.length
|
||||
kinds.set(ln, "remove")
|
||||
meta.set(ln, { old: oldNo, sign: "-" })
|
||||
oldNo++
|
||||
continue
|
||||
}
|
||||
|
||||
if (/^ /.test(s)) {
|
||||
out.push(s)
|
||||
const ln = out.length
|
||||
kinds.set(ln, "context")
|
||||
meta.set(ln, { old: oldNo, new: newNo })
|
||||
oldNo++
|
||||
newNo++
|
||||
continue
|
||||
}
|
||||
|
||||
// fallback in hunks
|
||||
out.push(s)
|
||||
}
|
||||
|
||||
return out.join("\n").trimEnd()
|
||||
},
|
||||
code(node) {
|
||||
if (isDiff) this.addClassToHast(node, "code-diff")
|
||||
},
|
||||
pre(node) {
|
||||
if (isDiff) this.addClassToHast(node, "code-diff")
|
||||
},
|
||||
line(node, line) {
|
||||
if (!isDiff) return
|
||||
const kind = kinds.get(line)
|
||||
if (!kind) return
|
||||
|
||||
const m = meta.get(line) || {}
|
||||
|
||||
this.addClassToHast(node, "diff-line")
|
||||
this.addClassToHast(node, `diff-${kind}`)
|
||||
node.properties = node.properties || {}
|
||||
;(node.properties as any)["data-diff"] = kind
|
||||
if (m.old != undefined) (node.properties as any)["data-old"] = String(m.old)
|
||||
if (m.new != undefined) (node.properties as any)["data-new"] = String(m.new)
|
||||
|
||||
const oldSpan = {
|
||||
type: "element",
|
||||
tagName: "span",
|
||||
properties: { className: ["diff-oldln"] },
|
||||
children: [{ type: "text", value: m.old != undefined ? String(m.old) : " " }],
|
||||
}
|
||||
const newSpan = {
|
||||
type: "element",
|
||||
tagName: "span",
|
||||
properties: { className: ["diff-newln"] },
|
||||
children: [{ type: "text", value: m.new != undefined ? String(m.new) : " " }],
|
||||
}
|
||||
|
||||
if (kind === "add" || kind === "remove" || kind === "context") {
|
||||
const first = (node.children && (node.children as any[])[0]) as any
|
||||
if (first && first.type === "element" && first.children && first.children.length > 0) {
|
||||
const t = first.children[0]
|
||||
if (t && t.type === "text" && typeof t.value === "string" && t.value.length > 0) {
|
||||
const ch = t.value[0]
|
||||
if (ch === "+" || ch === "-" || ch === " ") t.value = t.value.slice(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const signSpan = {
|
||||
type: "element",
|
||||
tagName: "span",
|
||||
properties: { className: ["diff-sign"] },
|
||||
children: [{ type: "text", value: (m as any).sign || " " }],
|
||||
}
|
||||
|
||||
// @ts-expect-error hast typing across versions
|
||||
node.children = [oldSpan, newSpan, signSpan, ...(node.children || [])]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function transformerDiffGroups(): ShikiTransformer {
|
||||
let group = -1
|
||||
let inGroup = false
|
||||
return {
|
||||
name: "diff-groups",
|
||||
pre() {
|
||||
group = -1
|
||||
inGroup = false
|
||||
},
|
||||
line(node) {
|
||||
const props = (node.properties || {}) as any
|
||||
const kind = props["data-diff"] as string | undefined
|
||||
if (kind === "add" || kind === "remove") {
|
||||
if (!inGroup) {
|
||||
group += 1
|
||||
inGroup = true
|
||||
}
|
||||
;(node.properties as any)["data-chgrp"] = String(group)
|
||||
} else {
|
||||
inGroup = false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function applyDiffFolding(
|
||||
root: HTMLElement,
|
||||
context = 3,
|
||||
options?: { expanded?: string[]; onExpand?: (key: string) => void; side?: "left" | "right" },
|
||||
) {
|
||||
if (!root.classList.contains("code-diff")) return
|
||||
|
||||
// Cleanup: unwrap previous collapsed blocks and remove toggles
|
||||
const blocks = Array.from(root.querySelectorAll<HTMLElement>(".diff-collapsed-block"))
|
||||
for (const block of blocks) {
|
||||
const p = block.parentNode
|
||||
if (!p) {
|
||||
block.remove()
|
||||
continue
|
||||
}
|
||||
while (block.firstChild) p.insertBefore(block.firstChild, block)
|
||||
block.remove()
|
||||
}
|
||||
const toggles = Array.from(root.querySelectorAll<HTMLElement>(".diff-collapsed"))
|
||||
for (const t of toggles) t.remove()
|
||||
|
||||
const lines = Array.from(root.querySelectorAll<HTMLElement>(".diff-line"))
|
||||
if (lines.length === 0) return
|
||||
|
||||
const n = lines.length
|
||||
const isChange = lines.map((l) => l.dataset["diff"] === "add" || l.dataset["diff"] === "remove")
|
||||
const isContext = lines.map((l) => l.dataset["diff"] === "context")
|
||||
if (!isChange.some(Boolean)) return
|
||||
|
||||
const visible = new Array(n).fill(false) as boolean[]
|
||||
for (let i = 0; i < n; i++) if (isChange[i]) visible[i] = true
|
||||
for (let i = 0; i < n; i++) {
|
||||
if (isChange[i]) {
|
||||
const s = Math.max(0, i - context)
|
||||
const e = Math.min(n - 1, i + context)
|
||||
for (let j = s; j <= e; j++) if (isContext[j]) visible[j] = true
|
||||
}
|
||||
}
|
||||
|
||||
type Range = { start: number; end: number }
|
||||
const ranges: Range[] = []
|
||||
let i = 0
|
||||
while (i < n) {
|
||||
if (!visible[i] && isContext[i]) {
|
||||
let j = i
|
||||
while (j + 1 < n && !visible[j + 1] && isContext[j + 1]) j++
|
||||
ranges.push({ start: i, end: j })
|
||||
i = j + 1
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
for (const r of ranges) {
|
||||
const start = lines[r.start]
|
||||
const end = lines[r.end]
|
||||
const count = r.end - r.start + 1
|
||||
const minCollapse = 20
|
||||
if (count < minCollapse) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Wrap the entire collapsed chunk (including trailing newline) so it takes no space
|
||||
const block = document.createElement("span")
|
||||
block.className = "diff-collapsed-block"
|
||||
start.parentElement?.insertBefore(block, start)
|
||||
|
||||
let cur: Node | undefined = start
|
||||
while (cur) {
|
||||
const next: Node | undefined = cur.nextSibling || undefined
|
||||
block.appendChild(cur)
|
||||
if (cur === end) {
|
||||
// Also move the newline after the last line into the block
|
||||
if (next && next.nodeType === Node.TEXT_NODE && (next.textContent || "").startsWith("\n")) {
|
||||
block.appendChild(next)
|
||||
}
|
||||
break
|
||||
}
|
||||
cur = next
|
||||
}
|
||||
|
||||
block.style.display = "none"
|
||||
const row = document.createElement("span")
|
||||
row.className = "line diff-collapsed"
|
||||
row.setAttribute("data-kind", "collapsed")
|
||||
row.setAttribute("data-count", String(count))
|
||||
row.setAttribute("tabindex", "0")
|
||||
row.setAttribute("role", "button")
|
||||
|
||||
const oldln = document.createElement("span")
|
||||
oldln.className = "diff-oldln"
|
||||
oldln.textContent = " "
|
||||
|
||||
const newln = document.createElement("span")
|
||||
newln.className = "diff-newln"
|
||||
newln.textContent = " "
|
||||
|
||||
const sign = document.createElement("span")
|
||||
sign.className = "diff-sign"
|
||||
sign.textContent = "…"
|
||||
|
||||
const label = document.createElement("span")
|
||||
label.textContent = `show ${count} unchanged line${count > 1 ? "s" : ""}`
|
||||
|
||||
const key = `o${start.dataset["old"] || ""}-${end.dataset["old"] || ""}:n${start.dataset["new"] || ""}-${end.dataset["new"] || ""}`
|
||||
|
||||
const show = (record = true) => {
|
||||
if (record) options?.onExpand?.(key)
|
||||
const p = block.parentNode
|
||||
if (p) {
|
||||
while (block.firstChild) p.insertBefore(block.firstChild, block)
|
||||
block.remove()
|
||||
}
|
||||
row.remove()
|
||||
}
|
||||
|
||||
row.addEventListener("click", () => show(true))
|
||||
row.addEventListener("keydown", (ev) => {
|
||||
if (ev.key === "Enter" || ev.key === " ") {
|
||||
ev.preventDefault()
|
||||
show(true)
|
||||
}
|
||||
})
|
||||
|
||||
block.parentElement?.insertBefore(row, block)
|
||||
if (!options?.side || options.side === "left") row.appendChild(oldln)
|
||||
if (!options?.side || options.side === "right") row.appendChild(newln)
|
||||
row.appendChild(sign)
|
||||
row.appendChild(label)
|
||||
|
||||
if (options?.expanded && options.expanded.includes(key)) {
|
||||
show(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applySplitDiff(container: HTMLElement) {
|
||||
const pres = Array.from(container.querySelectorAll<HTMLPreElement>("pre"))
|
||||
if (pres.length === 0) return
|
||||
const originalPre = pres[0]
|
||||
const originalCode = originalPre.querySelector("code") as HTMLElement | undefined
|
||||
if (!originalCode || !originalCode.classList.contains("code-diff")) return
|
||||
|
||||
// Rebuild split each time to match current content
|
||||
const existing = container.querySelector<HTMLElement>(".diff-split")
|
||||
if (existing) existing.remove()
|
||||
|
||||
const grid = document.createElement("div")
|
||||
grid.className = "diff-split grid grid-cols-2 gap-x-6"
|
||||
|
||||
const makeColumn = () => {
|
||||
const pre = document.createElement("pre")
|
||||
pre.className = originalPre.className
|
||||
const code = document.createElement("code")
|
||||
code.className = originalCode.className
|
||||
pre.appendChild(code)
|
||||
return { pre, code }
|
||||
}
|
||||
|
||||
const left = makeColumn()
|
||||
const right = makeColumn()
|
||||
|
||||
// Helpers
|
||||
const cloneSide = (line: HTMLElement, side: "old" | "new"): HTMLElement => {
|
||||
const clone = line.cloneNode(true) as HTMLElement
|
||||
const oldln = clone.querySelector(".diff-oldln")
|
||||
const newln = clone.querySelector(".diff-newln")
|
||||
if (side === "old") {
|
||||
if (newln) newln.remove()
|
||||
} else {
|
||||
if (oldln) oldln.remove()
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
const blankLine = (side: "old" | "new", kind: "add" | "remove"): HTMLElement => {
|
||||
const span = document.createElement("span")
|
||||
span.className = "line diff-line diff-blank"
|
||||
span.setAttribute("data-diff", kind)
|
||||
const ln = document.createElement("span")
|
||||
ln.className = side === "old" ? "diff-oldln" : "diff-newln"
|
||||
ln.textContent = " "
|
||||
span.appendChild(ln)
|
||||
return span
|
||||
}
|
||||
|
||||
const lines = Array.from(originalCode.querySelectorAll<HTMLElement>(".diff-line"))
|
||||
let i = 0
|
||||
while (i < lines.length) {
|
||||
const cur = lines[i]
|
||||
const kind = cur.dataset["diff"]
|
||||
|
||||
if (kind === "context") {
|
||||
left.code.appendChild(cloneSide(cur, "old"))
|
||||
left.code.appendChild(document.createTextNode("\n"))
|
||||
right.code.appendChild(cloneSide(cur, "new"))
|
||||
right.code.appendChild(document.createTextNode("\n"))
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if (kind === "remove") {
|
||||
// Batch consecutive removes and following adds, then pair
|
||||
const removes: HTMLElement[] = []
|
||||
const adds: HTMLElement[] = []
|
||||
let j = i
|
||||
while (j < lines.length && lines[j].dataset["diff"] === "remove") {
|
||||
removes.push(lines[j])
|
||||
j++
|
||||
}
|
||||
let k = j
|
||||
while (k < lines.length && lines[k].dataset["diff"] === "add") {
|
||||
adds.push(lines[k])
|
||||
k++
|
||||
}
|
||||
|
||||
const pairs = Math.min(removes.length, adds.length)
|
||||
for (let p = 0; p < pairs; p++) {
|
||||
left.code.appendChild(cloneSide(removes[p], "old"))
|
||||
left.code.appendChild(document.createTextNode("\n"))
|
||||
right.code.appendChild(cloneSide(adds[p], "new"))
|
||||
right.code.appendChild(document.createTextNode("\n"))
|
||||
}
|
||||
for (let p = pairs; p < removes.length; p++) {
|
||||
left.code.appendChild(cloneSide(removes[p], "old"))
|
||||
left.code.appendChild(document.createTextNode("\n"))
|
||||
right.code.appendChild(blankLine("new", "remove"))
|
||||
right.code.appendChild(document.createTextNode("\n"))
|
||||
}
|
||||
for (let p = pairs; p < adds.length; p++) {
|
||||
left.code.appendChild(blankLine("old", "add"))
|
||||
left.code.appendChild(document.createTextNode("\n"))
|
||||
right.code.appendChild(cloneSide(adds[p], "new"))
|
||||
right.code.appendChild(document.createTextNode("\n"))
|
||||
}
|
||||
|
||||
i = k
|
||||
continue
|
||||
}
|
||||
|
||||
if (kind === "add") {
|
||||
// Run of adds not preceded by removes
|
||||
const adds: HTMLElement[] = []
|
||||
let j = i
|
||||
while (j < lines.length && lines[j].dataset["diff"] === "add") {
|
||||
adds.push(lines[j])
|
||||
j++
|
||||
}
|
||||
for (let p = 0; p < adds.length; p++) {
|
||||
left.code.appendChild(blankLine("old", "add"))
|
||||
left.code.appendChild(document.createTextNode("\n"))
|
||||
right.code.appendChild(cloneSide(adds[p], "new"))
|
||||
right.code.appendChild(document.createTextNode("\n"))
|
||||
}
|
||||
i = j
|
||||
continue
|
||||
}
|
||||
|
||||
// Any other kind: mirror as context
|
||||
left.code.appendChild(cloneSide(cur, "old"))
|
||||
left.code.appendChild(document.createTextNode("\n"))
|
||||
right.code.appendChild(cloneSide(cur, "new"))
|
||||
right.code.appendChild(document.createTextNode("\n"))
|
||||
i++
|
||||
}
|
||||
|
||||
grid.appendChild(left.pre)
|
||||
grid.appendChild(right.pre)
|
||||
container.appendChild(grid)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Button, Icon, IconButton, Select, SelectDialog } from "@opencode-ai/ui"
|
||||
import { Button, Icon, IconButton, Select, SelectDialog, Tooltip } from "@opencode-ai/ui"
|
||||
import { useFilteredList } from "@opencode-ai/ui/hooks"
|
||||
import { createEffect, on, Component, Show, For, onMount, onCleanup } from "solid-js"
|
||||
import { createEffect, on, Component, Show, For, onMount, onCleanup, Switch, Match } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { FileIcon } from "@/ui"
|
||||
import { getDirectory, getFilename } from "@/utils"
|
||||
@@ -174,10 +174,8 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
|
||||
const addPart = (part: ContentPart) => {
|
||||
const cursorPosition = getCursorPosition(editorRef)
|
||||
const rawText = session.prompt
|
||||
.current()
|
||||
.map((p) => p.content)
|
||||
.join("")
|
||||
const prompt = session.prompt.current()
|
||||
const rawText = prompt.map((p) => p.content).join("")
|
||||
const textBeforeCursor = rawText.substring(0, cursorPosition)
|
||||
const atMatch = textBeforeCursor.match(/@(\S*)$/)
|
||||
|
||||
@@ -203,7 +201,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
parts: nextParts,
|
||||
inserted,
|
||||
cursorPositionAfter,
|
||||
} = session.prompt.current().reduce(
|
||||
} = prompt.reduce(
|
||||
(acc, item) => {
|
||||
if (acc.inserted) {
|
||||
acc.parts.push({ ...item, start: acc.runningIndex, end: acc.runningIndex + item.content.length })
|
||||
@@ -262,7 +260,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
)
|
||||
|
||||
if (!inserted) {
|
||||
const baseParts = session.prompt.current().filter((item) => !(item.type === "text" && item.content === ""))
|
||||
const baseParts = prompt.filter((item) => !(item.type === "text" && item.content === ""))
|
||||
const runningIndex = baseParts.reduce((sum, p) => sum + p.content.length, 0)
|
||||
const appendedAcc = { parts: [...baseParts] as ContentPart[], runningIndex }
|
||||
if (part.type === "text") {
|
||||
@@ -316,10 +314,8 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
|
||||
const handleSubmit = async (event: Event) => {
|
||||
event.preventDefault()
|
||||
const text = session.prompt
|
||||
.current()
|
||||
.map((part) => part.content)
|
||||
.join("")
|
||||
const prompt = session.prompt.current()
|
||||
const text = prompt.map((part) => part.content).join("")
|
||||
if (text.trim().length === 0) {
|
||||
if (session.working()) abort()
|
||||
return
|
||||
@@ -329,18 +325,17 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
if (!existing) {
|
||||
const created = await sdk.client.session.create()
|
||||
existing = created.data ?? undefined
|
||||
if (existing) navigate(`/session/${existing.id}`)
|
||||
}
|
||||
if (!existing) return
|
||||
|
||||
navigate(`/session/${existing.id}`)
|
||||
if (!session.id) {
|
||||
// session.layout.setOpenedTabs(
|
||||
// session.layout.copyTabs("", session.id)
|
||||
}
|
||||
session.layout.setActiveTab(undefined)
|
||||
const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path))
|
||||
// if (!session.id) {
|
||||
// session.layout.setOpenedTabs(
|
||||
// session.layout.copyTabs("", session.id)
|
||||
// }
|
||||
|
||||
const attachments = session.prompt.current().filter((part) => part.type === "file")
|
||||
const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path))
|
||||
const attachments = prompt.filter((part) => part.type === "file")
|
||||
|
||||
// const activeFile = local.context.active()
|
||||
// if (activeFile) {
|
||||
@@ -381,9 +376,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
}
|
||||
})
|
||||
|
||||
session.layout.setActiveTab(undefined)
|
||||
session.messages.setActive(undefined)
|
||||
session.prompt.set(DEFAULT_PROMPT, 0)
|
||||
|
||||
await sdk.client.session.prompt({
|
||||
sdk.client.session.prompt({
|
||||
path: { id: existing.id },
|
||||
body: {
|
||||
agent: local.agent.current()!.name,
|
||||
@@ -519,12 +516,33 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
)}
|
||||
</SelectDialog>
|
||||
</div>
|
||||
<IconButton
|
||||
type="submit"
|
||||
disabled={!session.prompt.dirty() && !session.working()}
|
||||
icon={session.working() ? "stop" : "arrow-up"}
|
||||
variant="primary"
|
||||
/>
|
||||
<Tooltip
|
||||
placement="top"
|
||||
value={
|
||||
<Switch>
|
||||
<Match when={session.working()}>
|
||||
<div class="flex items-center gap-2">
|
||||
<span>Stop</span>
|
||||
<span class="text-icon-base text-12-medium text-[10px]!">ESC</span>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<div class="flex items-center gap-2">
|
||||
<span>Send</span>
|
||||
<Icon name="enter" size="small" class="text-icon-base" />
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
type="submit"
|
||||
disabled={!session.prompt.dirty() && !session.working()}
|
||||
icon={session.working() ? "stop" : "arrow-up"}
|
||||
variant="primary"
|
||||
class="rounded-full"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,558 +0,0 @@
|
||||
{
|
||||
"colors": {
|
||||
"actionBar.toggledBackground": "var(--surface-raised-base)",
|
||||
"activityBarBadge.background": "var(--surface-brand-base)",
|
||||
"checkbox.border": "var(--border-base)",
|
||||
"editor.background": "transparent",
|
||||
"editor.foreground": "var(--text-base)",
|
||||
"editor.inactiveSelectionBackground": "var(--surface-raised-base)",
|
||||
"editor.selectionHighlightBackground": "var(--border-active)",
|
||||
"editorIndentGuide.activeBackground1": "var(--border-weak-base)",
|
||||
"editorIndentGuide.background1": "var(--border-weak-base)",
|
||||
"input.placeholderForeground": "var(--text-weak)",
|
||||
"list.activeSelectionIconForeground": "var(--text-base)",
|
||||
"list.dropBackground": "var(--surface-raised-base)",
|
||||
"menu.background": "var(--surface-base)",
|
||||
"menu.border": "var(--border-base)",
|
||||
"menu.foreground": "var(--text-base)",
|
||||
"menu.selectionBackground": "var(--surface-interactive-base)",
|
||||
"menu.separatorBackground": "var(--border-base)",
|
||||
"ports.iconRunningProcessForeground": "var(--icon-success-base)",
|
||||
"sideBarSectionHeader.background": "transparent",
|
||||
"sideBarSectionHeader.border": "var(--border-weak-base)",
|
||||
"sideBarTitle.foreground": "var(--text-weak)",
|
||||
"statusBarItem.remoteBackground": "var(--surface-success-base)",
|
||||
"statusBarItem.remoteForeground": "var(--text-base)",
|
||||
"tab.lastPinnedBorder": "var(--border-weak-base)",
|
||||
"tab.selectedBackground": "var(--surface-raised-base)",
|
||||
"tab.selectedForeground": "var(--text-weak)",
|
||||
"terminal.inactiveSelectionBackground": "var(--surface-raised-base)",
|
||||
"widget.border": "var(--border-base)"
|
||||
},
|
||||
"displayName": "opencode",
|
||||
"name": "opencode",
|
||||
"semanticHighlighting": true,
|
||||
"semanticTokenColors": {
|
||||
"customLiteral": "var(--syntax-function)",
|
||||
"newOperator": "var(--syntax-operator)",
|
||||
"numberLiteral": "var(--syntax-number)",
|
||||
"stringLiteral": "var(--syntax-string)"
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": [
|
||||
"meta.embedded",
|
||||
"source.groovy.embedded",
|
||||
"string meta.image.inline.markdown",
|
||||
"variable.legacy.builtin.python"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--text-base)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "emphasis",
|
||||
"settings": {
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "strong",
|
||||
"settings": {
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "header",
|
||||
"settings": {
|
||||
"foreground": "var(--markdown-heading)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "comment",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-comment)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.language",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"constant.numeric",
|
||||
"variable.other.enummember",
|
||||
"keyword.operator.plus.exponent",
|
||||
"keyword.operator.minus.exponent"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-number)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.regexp",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.tag",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.tag.css", "entity.name.tag.less"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.other.attribute-name",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-variable)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"entity.other.attribute-name.class.css",
|
||||
"source.css entity.other.attribute-name.class",
|
||||
"entity.other.attribute-name.id.css",
|
||||
"entity.other.attribute-name.parent-selector.css",
|
||||
"entity.other.attribute-name.parent.less",
|
||||
"source.css entity.other.attribute-name.pseudo-class",
|
||||
"entity.other.attribute-name.pseudo-element.css",
|
||||
"source.css.less entity.other.attribute-name.id",
|
||||
"entity.other.attribute-name.scss"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "invalid",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-critical)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.underline",
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.bold",
|
||||
"settings": {
|
||||
"fontStyle": "bold",
|
||||
"foreground": "var(--markdown-strong)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.heading",
|
||||
"settings": {
|
||||
"fontStyle": "bold",
|
||||
"foreground": "var(--theme-markdown-heading)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.italic",
|
||||
"settings": {
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.strikethrough",
|
||||
"settings": {
|
||||
"fontStyle": "strikethrough"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.inserted",
|
||||
"settings": {
|
||||
"foreground": "var(--text-diff-add-base)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.deleted",
|
||||
"settings": {
|
||||
"foreground": "var(--text-diff-delete-base)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.changed",
|
||||
"settings": {
|
||||
"foreground": "var(--text-base)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "punctuation.definition.quote.begin.markdown",
|
||||
"settings": {
|
||||
"foreground": "var(--markdown-block-quote)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "punctuation.definition.list.begin.markdown",
|
||||
"settings": {
|
||||
"foreground": "var(--markdown-list-enumeration)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.inline.raw",
|
||||
"settings": {
|
||||
"foreground": "var(--markdown-code)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "punctuation.definition.tag",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-punctuation)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.preprocessor", "entity.name.function.preprocessor"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor.string",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-string)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor.numeric",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-number)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.structure.dictionary.key.python",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-variable)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.diff.header",
|
||||
"settings": {
|
||||
"foreground": "var(--text-weak)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.type",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["storage.modifier", "keyword.operator.noexcept"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string", "meta.embedded.assembly"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-string)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.tag",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-string)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.value",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-string)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.regexp",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"punctuation.definition.template-expression.begin",
|
||||
"punctuation.definition.template-expression.end",
|
||||
"punctuation.section.embedded"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.template.expression"],
|
||||
"settings": {
|
||||
"foreground": "var(--text-base)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"support.type.vendored.property-name",
|
||||
"support.type.property-name",
|
||||
"source.css variable",
|
||||
"source.coffee.embedded"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-variable)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.control",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.operator",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"keyword.operator.new",
|
||||
"keyword.operator.expression",
|
||||
"keyword.operator.cast",
|
||||
"keyword.operator.sizeof",
|
||||
"keyword.operator.alignof",
|
||||
"keyword.operator.typeid",
|
||||
"keyword.operator.alignas",
|
||||
"keyword.operator.instanceof",
|
||||
"keyword.operator.logical.python",
|
||||
"keyword.operator.wordlike"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.other.unit",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-number)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["punctuation.section.embedded.begin.php", "punctuation.section.embedded.end.php"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.function.git-rebase",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-variable)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.sha.git-rebase",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-number)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["storage.modifier.import.java", "variable.language.wildcard.java", "storage.modifier.package.java"],
|
||||
"settings": {
|
||||
"foreground": "var(--text-base)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.language",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"entity.name.function",
|
||||
"support.function",
|
||||
"support.constant.handlebars",
|
||||
"source.powershell variable.other.member",
|
||||
"entity.name.operator.custom-literal"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-function)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"support.class",
|
||||
"support.type",
|
||||
"entity.name.type",
|
||||
"entity.name.namespace",
|
||||
"entity.other.attribute",
|
||||
"entity.name.scope-resolution",
|
||||
"entity.name.class",
|
||||
"storage.type.numeric.go",
|
||||
"storage.type.byte.go",
|
||||
"storage.type.boolean.go",
|
||||
"storage.type.string.go",
|
||||
"storage.type.uintptr.go",
|
||||
"storage.type.error.go",
|
||||
"storage.type.rune.go",
|
||||
"storage.type.cs",
|
||||
"storage.type.generic.cs",
|
||||
"storage.type.modifier.cs",
|
||||
"storage.type.variable.cs",
|
||||
"storage.type.annotation.java",
|
||||
"storage.type.generic.java",
|
||||
"storage.type.java",
|
||||
"storage.type.object.array.java",
|
||||
"storage.type.primitive.array.java",
|
||||
"storage.type.primitive.java",
|
||||
"storage.type.token.java",
|
||||
"storage.type.groovy",
|
||||
"storage.type.annotation.groovy",
|
||||
"storage.type.parameters.groovy",
|
||||
"storage.type.generic.groovy",
|
||||
"storage.type.object.array.groovy",
|
||||
"storage.type.primitive.array.groovy",
|
||||
"storage.type.primitive.groovy"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-type)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"meta.type.cast.expr",
|
||||
"meta.type.new.expr",
|
||||
"support.constant.math",
|
||||
"support.constant.dom",
|
||||
"support.constant.json",
|
||||
"entity.other.inherited-class",
|
||||
"punctuation.separator.namespace.ruby"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-type)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"keyword.control",
|
||||
"source.cpp keyword.operator.new",
|
||||
"keyword.operator.delete",
|
||||
"keyword.other.using",
|
||||
"keyword.other.directive.using",
|
||||
"keyword.other.operator",
|
||||
"entity.name.operator"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"variable",
|
||||
"meta.definition.variable.name",
|
||||
"support.variable",
|
||||
"entity.name.variable",
|
||||
"constant.other.placeholder"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-variable)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["variable.other.constant", "variable.other.enummember"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-variable)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.object-literal.key"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-variable)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"support.constant.property-value",
|
||||
"support.constant.font-name",
|
||||
"support.constant.media-type",
|
||||
"support.constant.media",
|
||||
"constant.other.color.rgb-value",
|
||||
"constant.other.rgb-value",
|
||||
"support.constant.color"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-string)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"punctuation.definition.group.regexp",
|
||||
"punctuation.definition.group.assertion.regexp",
|
||||
"punctuation.definition.character-class.regexp",
|
||||
"punctuation.character.set.begin.regexp",
|
||||
"punctuation.character.set.end.regexp",
|
||||
"keyword.operator.negation.regexp",
|
||||
"support.other.parenthesis.regexp"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-string)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"constant.character.character-class.regexp",
|
||||
"constant.other.character-class.set.regexp",
|
||||
"constant.other.character-class.regexp",
|
||||
"constant.character.set.regexp"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["keyword.operator.or.regexp", "keyword.control.anchor.regexp"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.operator.quantifier.regexp",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.character", "constant.other.option"],
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-keyword)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.character.escape",
|
||||
"settings": {
|
||||
"foreground": "var(--syntax-operator)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.label",
|
||||
"settings": {
|
||||
"foreground": "var(--text-weak)"
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "dark"
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import type { FileContent, FileNode, Model, Provider, File as FileStatus } from
|
||||
import { createSimpleContext } from "./helper"
|
||||
import { useSDK } from "./sdk"
|
||||
import { useSync } from "./sync"
|
||||
import { makePersisted } from "@solid-primitives/storage"
|
||||
|
||||
export type LocalFile = FileNode &
|
||||
Partial<{
|
||||
@@ -456,11 +457,60 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
}
|
||||
})()
|
||||
|
||||
const layout = (() => {
|
||||
const [store, setStore] = makePersisted(
|
||||
createStore({
|
||||
sidebar: {
|
||||
opened: true,
|
||||
width: 240,
|
||||
},
|
||||
review: {
|
||||
state: "closed" as "open" | "closed" | "tab",
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "default-layout",
|
||||
},
|
||||
)
|
||||
|
||||
return {
|
||||
sidebar: {
|
||||
opened: createMemo(() => store.sidebar.opened),
|
||||
open() {
|
||||
setStore("sidebar", "opened", true)
|
||||
},
|
||||
close() {
|
||||
setStore("sidebar", "opened", false)
|
||||
},
|
||||
toggle() {
|
||||
setStore("sidebar", "opened", (x) => !x)
|
||||
},
|
||||
width: createMemo(() => store.sidebar.width),
|
||||
resize(width: number) {
|
||||
setStore("sidebar", "width", width)
|
||||
},
|
||||
},
|
||||
review: {
|
||||
state: createMemo(() => store.review?.state ?? "closed"),
|
||||
open() {
|
||||
setStore("review", "state", "open")
|
||||
},
|
||||
close() {
|
||||
setStore("review", "state", "closed")
|
||||
},
|
||||
tab() {
|
||||
setStore("review", "state", "tab")
|
||||
},
|
||||
},
|
||||
}
|
||||
})()
|
||||
|
||||
const result = {
|
||||
model,
|
||||
agent,
|
||||
file,
|
||||
context,
|
||||
layout,
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
@@ -80,6 +80,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
const model = createMemo(() =>
|
||||
last() ? sync.data.provider.find((x) => x.id === last().providerID)?.models[last().modelID] : undefined,
|
||||
)
|
||||
const diffs = createMemo(() => (props.sessionId ? (sync.data.session_diff[props.sessionId] ?? []) : []))
|
||||
|
||||
const tokens = createMemo(() => {
|
||||
if (!last()) return
|
||||
@@ -98,6 +99,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
id: props.sessionId,
|
||||
info,
|
||||
working,
|
||||
diffs,
|
||||
prompt: {
|
||||
current: createMemo(() => store.prompt),
|
||||
cursor: createMemo(() => store.cursorPosition),
|
||||
@@ -139,8 +141,10 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
if (tab.startsWith("file://")) {
|
||||
await local.file.open(tab.replace("file://", ""))
|
||||
}
|
||||
if (!store.tabs.opened.includes(tab)) {
|
||||
setStore("tabs", "opened", [...store.tabs.opened, tab])
|
||||
if (tab !== "review") {
|
||||
if (!store.tabs.opened.includes(tab)) {
|
||||
setStore("tabs", "opened", [...store.tabs.opened, tab])
|
||||
}
|
||||
}
|
||||
setStore("tabs", "active", tab)
|
||||
},
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
import type { Message, Agent, Provider, Session, Part, Config, Path, File, FileNode, Project } from "@opencode-ai/sdk"
|
||||
import type {
|
||||
Message,
|
||||
Agent,
|
||||
Provider,
|
||||
Session,
|
||||
Part,
|
||||
Config,
|
||||
Path,
|
||||
File,
|
||||
FileNode,
|
||||
Project,
|
||||
FileDiff,
|
||||
Todo,
|
||||
} from "@opencode-ai/sdk"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { createMemo } from "solid-js"
|
||||
import { Binary } from "@/utils/binary"
|
||||
@@ -16,8 +29,13 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
config: Config
|
||||
path: Path
|
||||
session: Session[]
|
||||
session_diff: {
|
||||
[sessionID: string]: FileDiff[]
|
||||
}
|
||||
todo: {
|
||||
[sessionID: string]: Todo[]
|
||||
}
|
||||
limit: number
|
||||
more: boolean
|
||||
message: {
|
||||
[sessionID: string]: Message[]
|
||||
}
|
||||
@@ -34,8 +52,9 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
agent: [],
|
||||
provider: [],
|
||||
session: [],
|
||||
session_diff: {},
|
||||
todo: {},
|
||||
limit: 10,
|
||||
more: false,
|
||||
message: {},
|
||||
part: {},
|
||||
node: [],
|
||||
@@ -60,6 +79,12 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
)
|
||||
break
|
||||
}
|
||||
case "session.diff":
|
||||
setStore("session_diff", event.properties.sessionID, event.properties.diff)
|
||||
break
|
||||
case "todo.updated":
|
||||
setStore("todo", event.properties.sessionID, event.properties.todos)
|
||||
break
|
||||
case "message.updated": {
|
||||
const messages = store.message[event.properties.info.sessionID]
|
||||
if (!messages) {
|
||||
@@ -116,7 +141,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
.sort((a, b) => a.id.localeCompare(b.id))
|
||||
.slice(0, store.limit)
|
||||
setStore("session", sessions)
|
||||
setStore("more", sessions.length === store.limit)
|
||||
}),
|
||||
config: () => sdk.client.config.get().then((x) => setStore("config", x.data!)),
|
||||
changes: () => sdk.client.file.status().then((x) => setStore("changes", x.data!)),
|
||||
@@ -161,22 +185,19 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
if (match.found) return store.session[match.index]
|
||||
return undefined
|
||||
},
|
||||
async sync(sessionID: string, isRetry = false) {
|
||||
const [session, messages] = await Promise.all([
|
||||
sdk.client.session.get({ path: { id: sessionID } }),
|
||||
sdk.client.session.messages({ path: { id: sessionID } }),
|
||||
async sync(sessionID: string, _isRetry = false) {
|
||||
const [session, messages, todo, diff] = await Promise.all([
|
||||
sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }),
|
||||
sdk.client.session.messages({ path: { id: sessionID }, query: { limit: 100 } }),
|
||||
sdk.client.session.todo({ path: { id: sessionID } }),
|
||||
sdk.client.session.diff({ path: { id: sessionID } }),
|
||||
])
|
||||
|
||||
// If no messages and this might be a new session, retry after a delay
|
||||
if (!isRetry && messages.data!.length === 0) {
|
||||
setTimeout(() => this.sync(sessionID, true), 500)
|
||||
return
|
||||
}
|
||||
|
||||
setStore(
|
||||
produce((draft) => {
|
||||
const match = Binary.search(draft.session, sessionID, (s) => s.id)
|
||||
draft.session[match.index] = session.data!
|
||||
if (match.found) draft.session[match.index] = session.data!
|
||||
if (!match.found) draft.session.splice(match.index, 0, session.data!)
|
||||
draft.todo[sessionID] = todo.data ?? []
|
||||
draft.message[sessionID] = messages
|
||||
.data!.map((x) => x.info)
|
||||
.slice()
|
||||
@@ -187,6 +208,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
.map(sanitizePart)
|
||||
.sort((a, b) => a.id.localeCompare(b.id))
|
||||
}
|
||||
draft.session_diff[sessionID] = diff.data ?? []
|
||||
}),
|
||||
)
|
||||
},
|
||||
@@ -194,6 +216,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
setStore("limit", (x) => x + count)
|
||||
await load.session()
|
||||
},
|
||||
more: createMemo(() => store.session.length === store.limit),
|
||||
},
|
||||
load,
|
||||
absolute,
|
||||
|
||||
@@ -3,7 +3,7 @@ import "@/index.css"
|
||||
import { render } from "solid-js/web"
|
||||
import { Router, Route } from "@solidjs/router"
|
||||
import { MetaProvider } from "@solidjs/meta"
|
||||
import { Fonts, ShikiProvider, MarkedProvider } from "@opencode-ai/ui"
|
||||
import { Fonts, MarkedProvider } from "@opencode-ai/ui"
|
||||
import { SDKProvider } from "./context/sdk"
|
||||
import { SyncProvider } from "./context/sync"
|
||||
import { LocalProvider } from "./context/local"
|
||||
@@ -29,24 +29,22 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
|
||||
|
||||
render(
|
||||
() => (
|
||||
<ShikiProvider>
|
||||
<MarkedProvider>
|
||||
<SDKProvider url={url}>
|
||||
<SyncProvider>
|
||||
<LocalProvider>
|
||||
<MetaProvider>
|
||||
<Fonts />
|
||||
<Router root={Layout}>
|
||||
<Route path={["/", "/session"]} component={SessionLayout}>
|
||||
<Route path="/:id?" component={Session} />
|
||||
</Route>
|
||||
</Router>
|
||||
</MetaProvider>
|
||||
</LocalProvider>
|
||||
</SyncProvider>
|
||||
</SDKProvider>
|
||||
</MarkedProvider>
|
||||
</ShikiProvider>
|
||||
<MarkedProvider>
|
||||
<SDKProvider url={url}>
|
||||
<SyncProvider>
|
||||
<LocalProvider>
|
||||
<MetaProvider>
|
||||
<Fonts />
|
||||
<Router root={Layout}>
|
||||
<Route path={["/", "/session"]} component={SessionLayout}>
|
||||
<Route path="/:id?" component={Session} />
|
||||
</Route>
|
||||
</Router>
|
||||
</MetaProvider>
|
||||
</LocalProvider>
|
||||
</SyncProvider>
|
||||
</SDKProvider>
|
||||
</MarkedProvider>
|
||||
),
|
||||
root!,
|
||||
)
|
||||
|
||||
@@ -1,30 +1,42 @@
|
||||
import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui"
|
||||
import { Button, Tooltip, DiffChanges, IconButton } from "@opencode-ai/ui"
|
||||
import { createMemo, For, ParentProps, Show } from "solid-js"
|
||||
import { getFilename } from "@/utils"
|
||||
import { DateTime } from "luxon"
|
||||
import { useSync } from "@/context/sync"
|
||||
import { VList } from "virtua/solid"
|
||||
import { A, useParams } from "@solidjs/router"
|
||||
import { useLocal } from "@/context/local"
|
||||
|
||||
export default function Layout(props: ParentProps) {
|
||||
const params = useParams()
|
||||
const sync = useSync()
|
||||
const local = useLocal()
|
||||
|
||||
return (
|
||||
<div class="relative h-screen flex flex-col">
|
||||
<header class="hidden h-12 shrink-0 bg-background-strong border-b border-border-weak-base"></header>
|
||||
<div class="h-[calc(100vh-0rem)] flex">
|
||||
<div class="w-70 shrink-0 bg-background-weak border-r border-border-weak-base flex flex-col items-start">
|
||||
<div class="h-10 shrink-0 flex items-center self-stretch px-5 border-b border-border-weak-base">
|
||||
<span class="text-14-regular overflow-hidden text-ellipsis">{getFilename(sync.data.path.directory)}</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-start gap-4 self-stretch flex-1 py-4 px-3 overflow-hidden">
|
||||
<A href="/session" class="w-full">
|
||||
<Button class="w-full" size="large" icon="edit-small-2">
|
||||
<div
|
||||
classList={{
|
||||
"@container w-14 pb-4 shrink-0 bg-background-weak": true,
|
||||
"flex flex-col items-start self-stretch justify-between": true,
|
||||
"border-r border-border-weak-base": true,
|
||||
"w-70": local.layout.sidebar.opened(),
|
||||
}}
|
||||
>
|
||||
<div class="flex flex-col justify-center items-start gap-4 self-stretch py-2 overflow-hidden mx-auto @[4rem]:mx-0">
|
||||
<div class="h-8 shrink-0 flex items-center self-stretch px-3">
|
||||
<Tooltip placement="right" value="Collapse sidebar">
|
||||
<IconButton icon="layout-left" variant="ghost" size="large" onClick={local.layout.sidebar.toggle} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="w-full px-3">
|
||||
<Button as={A} href="/session" class="hidden @[4rem]:flex w-full" size="large" icon="edit-small-2">
|
||||
New Session
|
||||
</Button>
|
||||
</A>
|
||||
<div class="w-full h-full overflow-y-auto no-scrollbar flex flex-col flex-1">
|
||||
<Tooltip placement="right" value="New session">
|
||||
<IconButton as={A} href="/session" icon="edit-small-2" size="large" class="@[4rem]:hidden" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="hidden @[4rem]:flex size-full overflow-y-auto no-scrollbar flex-col flex-1 px-3">
|
||||
<nav class="w-full">
|
||||
<For each={sync.data.session}>
|
||||
{(session) => {
|
||||
@@ -33,7 +45,7 @@ export default function Layout(props: ParentProps) {
|
||||
<A
|
||||
data-active={session.id === params.id}
|
||||
href={`/session/${session.id}`}
|
||||
class="group/session focus:outline-none"
|
||||
class="group/session focus:outline-none cursor-default"
|
||||
>
|
||||
<Tooltip placement="right" value={session.title}>
|
||||
<div
|
||||
@@ -68,7 +80,7 @@ export default function Layout(props: ParentProps) {
|
||||
}}
|
||||
</For>
|
||||
</nav>
|
||||
<Show when={sync.data.more}>
|
||||
<Show when={sync.session.more()}>
|
||||
<button
|
||||
class="shrink-0 self-start p-3 text-12-medium text-text-weak hover:text-text-strong"
|
||||
onClick={() => sync.session.fetch()}
|
||||
@@ -78,6 +90,29 @@ export default function Layout(props: ParentProps) {
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-start shrink-0 px-3 py-1 mx-auto @[4rem]:mx-0">
|
||||
<Button
|
||||
as={"a"}
|
||||
href="https://opencode.ai/desktop-feedback"
|
||||
target="_blank"
|
||||
class="hidden @[4rem]:flex w-full text-12-medium text-text-base stroke-[1.5px]"
|
||||
variant="ghost"
|
||||
icon="speech-bubble"
|
||||
>
|
||||
Share feedback
|
||||
</Button>
|
||||
<Tooltip placement="right" value="Share feedback">
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://opencode.ai/desktop-feedback"
|
||||
target="_blank"
|
||||
icon="speech-bubble"
|
||||
variant="ghost"
|
||||
size="large"
|
||||
class="@[4rem]:hidden stroke-[1.5px]"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<main class="size-full overflow-x-hidden">{props.children}</main>
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
Code,
|
||||
Tooltip,
|
||||
ProgressCircle,
|
||||
Button,
|
||||
} from "@opencode-ai/ui"
|
||||
import { FileIcon } from "@/ui"
|
||||
import { MessageProgress } from "@/components/message-progress"
|
||||
@@ -221,9 +222,9 @@ export default function Page() {
|
||||
</Switch>
|
||||
<IconButton
|
||||
icon="close"
|
||||
class="mt-0.5 opacity-0 text-text-muted/60 group-data-[selected]/tab:opacity-100
|
||||
group-data-[selected]/tab:text-text group-data-[selected]/tab:hover:bg-border-subtle
|
||||
hover:opacity-100 group-hover/tab:opacity-100"
|
||||
class="mt-0.5 opacity-0 group-data-[selected]/tab:opacity-100
|
||||
hover:bg-transparent
|
||||
hover:opacity-100 group-hover/tab:opacity-100"
|
||||
variant="ghost"
|
||||
onClick={() => props.onTabClose(props.tab)}
|
||||
/>
|
||||
@@ -289,105 +290,79 @@ export default function Page() {
|
||||
<div class="text-14-regular text-text-weak text-left w-7">{session.usage.context() ?? 0}%</div>
|
||||
</Tooltip>
|
||||
</Tabs.Trigger>
|
||||
{/* <Tabs.Trigger value="review">Review</Tabs.Trigger> */}
|
||||
<Show when={local.layout.review.state() === "tab" && session.diffs().length}>
|
||||
<Tabs.Trigger value="review" class="flex gap-3 items-center group/tab pr-1">
|
||||
<Show when={session.diffs()}>
|
||||
<DiffChanges changes={session.diffs()} variant="bars" />
|
||||
</Show>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div>Review</div>
|
||||
<Show when={session.info()?.summary?.files}>
|
||||
<div class="text-12-medium text-text-strong h-4 px-2 flex flex-col items-center justify-center rounded-full bg-surface-base">
|
||||
{session.info()?.summary?.files ?? 0}
|
||||
</div>
|
||||
</Show>
|
||||
<IconButton
|
||||
icon="close"
|
||||
class="mt-0.5 -ml-1 opacity-0 group-data-[selected]/tab:opacity-100
|
||||
hover:bg-transparent hover:opacity-100 group-hover/tab:opacity-100"
|
||||
variant="ghost"
|
||||
onClick={local.layout.review.close}
|
||||
/>
|
||||
</div>
|
||||
</Tabs.Trigger>
|
||||
</Show>
|
||||
<SortableProvider ids={session.layout.tabs.opened ?? []}>
|
||||
<For each={session.layout.tabs.opened ?? []}>
|
||||
{(tab) => <SortableTab tab={tab} onTabClick={handleTabClick} onTabClose={session.layout.closeTab} />}
|
||||
</For>
|
||||
</SortableProvider>
|
||||
<div class="bg-background-base h-full flex items-center justify-center border-b border-border-weak-base px-3">
|
||||
<IconButton
|
||||
icon="plus-small"
|
||||
variant="ghost"
|
||||
iconSize="large"
|
||||
onClick={() => setStore("fileSelectOpen", true)}
|
||||
/>
|
||||
<Tooltip value="Open file" class="flex items-center">
|
||||
<IconButton
|
||||
icon="plus-small"
|
||||
variant="ghost"
|
||||
iconSize="large"
|
||||
onClick={() => setStore("fileSelectOpen", true)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
<Tabs.Content value="chat" class="@container select-text flex flex-col flex-1 min-h-0 overflow-y-hidden">
|
||||
<div class="relative px-6 pt-12 max-w-2xl w-full mx-auto flex flex-col flex-1 min-h-0">
|
||||
<Show
|
||||
when={session.id}
|
||||
fallback={
|
||||
<div class="flex flex-col pb-45 justify-end items-start gap-4 flex-[1_0_0] self-stretch">
|
||||
<div class="text-20-medium text-text-weaker">New session</div>
|
||||
<div class="flex justify-center items-center gap-3">
|
||||
<Icon name="folder" size="small" />
|
||||
<div class="text-12-medium text-text-weak">
|
||||
{getDirectory(sync.data.path.directory)}
|
||||
<span class="text-text-strong">{getFilename(sync.data.path.directory)}</span>
|
||||
</div>
|
||||
<div
|
||||
classList={{
|
||||
"w-full grid flex-1 min-h-0": true,
|
||||
"grid-cols-2": local.layout.review.state() === "open",
|
||||
}}
|
||||
>
|
||||
<div class="relative px-6 py-2 w-full flex flex-col gap-6 flex-1 min-h-0 max-w-2xl mx-auto">
|
||||
<Switch>
|
||||
<Match when={session.id}>
|
||||
<div class="h-8 flex shrink-0 self-stretch items-center justify-end">
|
||||
<Show when={local.layout.review.state() === "closed" && session.diffs().length}>
|
||||
<Button icon="layout-right" onClick={local.layout.review.open}>
|
||||
Review
|
||||
</Button>
|
||||
</Show>
|
||||
</div>
|
||||
<div class="flex justify-center items-center gap-3">
|
||||
<Icon name="pencil-line" size="small" />
|
||||
<div class="text-12-medium text-text-weak">
|
||||
Last modified
|
||||
<span class="text-text-strong">
|
||||
{DateTime.fromMillis(sync.data.project.time.created).toRelative()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{(_) => {
|
||||
return (
|
||||
<div class="pt-3 flex flex-col flex-1 min-h-0">
|
||||
<div class="flex-1 min-h-0">
|
||||
<Show when={session.messages.user().length > 1}>
|
||||
<ul
|
||||
role="list"
|
||||
class="absolute right-full mr-8 hidden w-60 shrink-0 @7xl:flex flex-col items-start gap-1"
|
||||
>
|
||||
<For each={session.messages.user()}>
|
||||
{(message) => {
|
||||
const assistantMessages = createMemo(() => {
|
||||
if (!session.id) return []
|
||||
return sync.data.message[session.id]?.filter(
|
||||
(m) => m.role === "assistant" && m.parentID == message.id,
|
||||
) as AssistantMessageType[]
|
||||
})
|
||||
const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error)
|
||||
const working = createMemo(() => !message.summary?.body && !error())
|
||||
|
||||
return (
|
||||
<li class="group/li flex items-center self-stretch">
|
||||
<button
|
||||
class="flex items-center self-stretch w-full gap-x-2 py-1 cursor-default"
|
||||
onClick={() => session.messages.setActive(message.id)}
|
||||
>
|
||||
<Switch>
|
||||
<Match when={working()}>
|
||||
<Spinner class="text-text-base shrink-0 w-[18px] aspect-square" />
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
|
||||
</Match>
|
||||
</Switch>
|
||||
<div
|
||||
data-active={session.messages.active()?.id === message.id}
|
||||
classList={{
|
||||
"text-14-regular text-text-weak whitespace-nowrap truncate min-w-0": true,
|
||||
"text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true,
|
||||
}}
|
||||
>
|
||||
<Show when={message.summary?.title} fallback="New message">
|
||||
{message.summary?.title}
|
||||
</Show>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</ul>
|
||||
</Show>
|
||||
<div ref={messageScrollElement} class="grow min-w-0 h-full overflow-y-auto no-scrollbar">
|
||||
<div
|
||||
classList={{
|
||||
"flex-1 min-h-0 pb-20": true,
|
||||
"flex items-start justify-start": local.layout.review.state() === "open",
|
||||
}}
|
||||
>
|
||||
<Show when={session.messages.user().length > 1}>
|
||||
<ul
|
||||
role="list"
|
||||
classList={{
|
||||
"mr-8 shrink-0 flex flex-col items-start": true,
|
||||
"absolute right-full w-60 @7xl:gap-2": true, // local.layout.review.state() !== "open",
|
||||
"": local.layout.review.state() === "open",
|
||||
}}
|
||||
>
|
||||
<For each={session.messages.user()}>
|
||||
{(message) => {
|
||||
const isActive = createMemo(() => session.messages.active()?.id === message.id)
|
||||
const [titled, setTitled] = createSignal(!!message.summary?.title)
|
||||
const assistantMessages = createMemo(() => {
|
||||
if (!session.id) return []
|
||||
return sync.data.message[session.id]?.filter(
|
||||
@@ -395,186 +370,415 @@ export default function Page() {
|
||||
) as AssistantMessageType[]
|
||||
})
|
||||
const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error)
|
||||
const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error())
|
||||
const [detailsExpanded, setDetailsExpanded] = createSignal(false)
|
||||
const parts = createMemo(() => sync.data.part[message.id])
|
||||
const hasToolPart = createMemo(() =>
|
||||
assistantMessages()
|
||||
?.flatMap((m) => sync.data.part[m.id])
|
||||
.some((p) => p?.type === "tool"),
|
||||
)
|
||||
const working = createMemo(() => !message.summary?.body && !error())
|
||||
|
||||
// allowing time for the animations to finish
|
||||
createEffect(() => {
|
||||
const title = message.summary?.title
|
||||
setTimeout(() => setTitled(!!title), 10_000)
|
||||
})
|
||||
createEffect(() => {
|
||||
const summary = message.summary?.body
|
||||
const complete = !!summary || !!error()
|
||||
setTimeout(() => setCompleted(complete), 1200)
|
||||
})
|
||||
const handleClick = () => session.messages.setActive(message.id)
|
||||
|
||||
return (
|
||||
<Show when={isActive()}>
|
||||
<div
|
||||
data-message={message.id}
|
||||
class="flex flex-col items-start self-stretch gap-8 pb-50"
|
||||
<li
|
||||
classList={{
|
||||
"group/li flex items-center self-stretch justify-end": true,
|
||||
"@7xl:justify-start": local.layout.review.state() !== "open",
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
placement="right"
|
||||
gutter={8}
|
||||
value={
|
||||
<div class="flex items-center gap-2">
|
||||
<DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
|
||||
{message.summary?.title}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{/* Title */}
|
||||
<div class="py-2 flex flex-col items-start gap-2 self-stretch sticky top-0 bg-background-stronger z-10">
|
||||
<div class="w-full text-14-medium text-text-strong">
|
||||
<Show
|
||||
when={titled()}
|
||||
fallback={
|
||||
<Typewriter
|
||||
as="h1"
|
||||
text={message.summary?.title}
|
||||
class="overflow-hidden text-ellipsis min-w-0 text-nowrap"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<h1 class="overflow-hidden text-ellipsis min-w-0 text-nowrap">
|
||||
{message.summary?.title}
|
||||
</h1>
|
||||
</Show>
|
||||
</div>
|
||||
<button
|
||||
data-active={session.messages.active()?.id === message.id}
|
||||
onClick={handleClick}
|
||||
classList={{
|
||||
"group/tick flex items-center justify-start h-2 w-8 -mr-3": true,
|
||||
"data-[active=true]:[&>div]:bg-icon-strong-base data-[active=true]:[&>div]:w-full": true,
|
||||
"@7xl:hidden": local.layout.review.state() !== "open",
|
||||
}}
|
||||
>
|
||||
<div class="h-px w-5 bg-icon-base group-hover/tick:w-full group-hover/tick:bg-icon-strong-base" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<button
|
||||
classList={{
|
||||
"hidden items-center self-stretch w-full gap-x-2 cursor-default": true,
|
||||
"@7xl:flex": local.layout.review.state() !== "open",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Switch>
|
||||
<Match when={working()}>
|
||||
<Spinner class="text-text-base shrink-0 w-[18px] aspect-square" />
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
|
||||
</Match>
|
||||
</Switch>
|
||||
<div
|
||||
data-active={session.messages.active()?.id === message.id}
|
||||
classList={{
|
||||
"text-14-regular text-text-weak whitespace-nowrap truncate min-w-0": true,
|
||||
"text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true,
|
||||
}}
|
||||
>
|
||||
<Show when={message.summary?.title} fallback="New message">
|
||||
{message.summary?.title}
|
||||
</Show>
|
||||
</div>
|
||||
<div class="-mt-8">
|
||||
<Message message={message} parts={parts()} />
|
||||
</div>
|
||||
{/* Summary */}
|
||||
<Show when={completed()}>
|
||||
<div class="w-full flex flex-col gap-6 items-start self-stretch">
|
||||
<div class="flex flex-col items-start gap-1 self-stretch">
|
||||
<h2 class="text-12-medium text-text-weak">
|
||||
<Switch>
|
||||
<Match when={message.summary?.diffs?.length}>Summary</Match>
|
||||
<Match when={true}>Response</Match>
|
||||
</Switch>
|
||||
</h2>
|
||||
<Show when={message.summary?.body}>
|
||||
{(summary) => (
|
||||
<Markdown
|
||||
classList={{
|
||||
"text-14-regular": !!message.summary?.diffs?.length,
|
||||
"[&>*]:fade-up-text": !message.summary?.diffs?.length,
|
||||
}}
|
||||
text={summary()}
|
||||
/>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
<Accordion class="w-full" multiple>
|
||||
<For each={message.summary?.diffs ?? []}>
|
||||
{(diff) => (
|
||||
<Accordion.Item value={diff.file}>
|
||||
<Accordion.Header>
|
||||
<Accordion.Trigger>
|
||||
<div class="flex items-center justify-between w-full gap-5">
|
||||
<div class="grow flex items-center gap-5 min-w-0">
|
||||
<FileIcon
|
||||
node={{ path: diff.file, type: "file" }}
|
||||
class="shrink-0 size-4"
|
||||
/>
|
||||
<div class="flex grow min-w-0">
|
||||
<Show when={diff.file.includes("/")}>
|
||||
<span class="text-text-base truncate-start">
|
||||
{getDirectory(diff.file)}‎
|
||||
</span>
|
||||
</Show>
|
||||
<span class="text-text-strong shrink-0">
|
||||
{getFilename(diff.file)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shrink-0 flex gap-4 items-center justify-end">
|
||||
<DiffChanges changes={diff} />
|
||||
<Icon name="chevron-grabber-vertical" size="small" />
|
||||
</div>
|
||||
</div>
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content class="max-h-[300px] overflow-y-auto no-scrollbar">
|
||||
<Diff
|
||||
before={{
|
||||
name: diff.file!,
|
||||
contents: diff.before!,
|
||||
}}
|
||||
after={{
|
||||
name: diff.file!,
|
||||
contents: diff.after!,
|
||||
}}
|
||||
/>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)}
|
||||
</For>
|
||||
</Accordion>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={error() && !detailsExpanded()}>
|
||||
<Card variant="error" class="text-text-on-critical-base">
|
||||
{error()?.data?.message as string}
|
||||
</Card>
|
||||
</Show>
|
||||
{/* Response */}
|
||||
<div class="w-full">
|
||||
<Switch>
|
||||
<Match when={!completed()}>
|
||||
<MessageProgress assistantMessages={assistantMessages} done={!working()} />
|
||||
</Match>
|
||||
<Match when={completed() && hasToolPart()}>
|
||||
<Collapsible
|
||||
variant="ghost"
|
||||
open={detailsExpanded()}
|
||||
onOpenChange={setDetailsExpanded}
|
||||
>
|
||||
<Collapsible.Trigger class="text-text-weak hover:text-text-strong">
|
||||
<div class="flex items-center gap-1 self-stretch">
|
||||
<div class="text-12-medium">
|
||||
<Switch>
|
||||
<Match when={detailsExpanded()}>Hide details</Match>
|
||||
<Match when={!detailsExpanded()}>Show details</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
<Collapsible.Arrow />
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
<div class="w-full flex flex-col items-start self-stretch gap-3">
|
||||
<For each={assistantMessages()}>
|
||||
{(assistantMessage) => {
|
||||
const parts = createMemo(() => sync.data.part[assistantMessage.id])
|
||||
return <Message message={assistantMessage} parts={parts()} />
|
||||
}}
|
||||
</For>
|
||||
<Show when={error()}>
|
||||
<Card variant="error" class="text-text-on-critical-base">
|
||||
{error()?.data?.message as string}
|
||||
</Card>
|
||||
</Show>
|
||||
</div>
|
||||
</Collapsible.Content>
|
||||
</Collapsible>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</ul>
|
||||
</Show>
|
||||
<div ref={messageScrollElement} class="grow w-full min-w-0 h-full overflow-y-auto no-scrollbar">
|
||||
<For each={session.messages.user()}>
|
||||
{(message) => {
|
||||
const isActive = createMemo(() => session.messages.active()?.id === message.id)
|
||||
const [titled, setTitled] = createSignal(!!message.summary?.title)
|
||||
const assistantMessages = createMemo(() => {
|
||||
if (!session.id) return []
|
||||
return sync.data.message[session.id]?.filter(
|
||||
(m) => m.role === "assistant" && m.parentID == message.id,
|
||||
) as AssistantMessageType[]
|
||||
})
|
||||
const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error)
|
||||
const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error())
|
||||
const [detailsExpanded, setDetailsExpanded] = createSignal(false)
|
||||
const parts = createMemo(() => sync.data.part[message.id])
|
||||
const hasToolPart = createMemo(() =>
|
||||
assistantMessages()
|
||||
?.flatMap((m) => sync.data.part[m.id])
|
||||
.some((p) => p?.type === "tool"),
|
||||
)
|
||||
const working = createMemo(() => !message.summary?.body && !error())
|
||||
|
||||
// allowing time for the animations to finish
|
||||
createEffect(() => {
|
||||
const title = message.summary?.title
|
||||
setTimeout(() => setTitled(!!title), 10_000)
|
||||
})
|
||||
createEffect(() => {
|
||||
const summary = message.summary?.body
|
||||
const complete = !!summary || !!error()
|
||||
setTimeout(() => setCompleted(complete), 1200)
|
||||
})
|
||||
|
||||
return (
|
||||
<Show when={isActive()}>
|
||||
<div
|
||||
data-message={message.id}
|
||||
class="flex flex-col items-start self-stretch gap-8 pb-20"
|
||||
>
|
||||
{/* Title */}
|
||||
<div class="flex flex-col items-start gap-2 self-stretch sticky top-0 bg-background-stronger z-10 pb-1">
|
||||
<div class="w-full text-14-medium text-text-strong">
|
||||
<Show
|
||||
when={titled()}
|
||||
fallback={
|
||||
<Typewriter
|
||||
as="h1"
|
||||
text={message.summary?.title}
|
||||
class="overflow-hidden text-ellipsis min-w-0 text-nowrap"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<h1 class="overflow-hidden text-ellipsis min-w-0 text-nowrap">
|
||||
{message.summary?.title}
|
||||
</h1>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
<div class="-mt-9">
|
||||
<Message message={message} parts={parts()} />
|
||||
</div>
|
||||
{/* Summary */}
|
||||
<Show when={completed()}>
|
||||
<div class="w-full flex flex-col gap-6 items-start self-stretch">
|
||||
<div class="flex flex-col items-start gap-1 self-stretch">
|
||||
<h2 class="text-12-medium text-text-weak">
|
||||
<Switch>
|
||||
<Match when={message.summary?.diffs?.length}>Summary</Match>
|
||||
<Match when={true}>Response</Match>
|
||||
</Switch>
|
||||
</h2>
|
||||
<Show when={message.summary?.body}>
|
||||
{(summary) => (
|
||||
<Markdown
|
||||
classList={{
|
||||
"text-14-regular": !!message.summary?.diffs?.length,
|
||||
"[&>*]:fade-up-text": !message.summary?.diffs?.length,
|
||||
}}
|
||||
text={summary()}
|
||||
/>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
<Accordion class="w-full" multiple>
|
||||
<For each={message.summary?.diffs ?? []}>
|
||||
{(diff) => (
|
||||
<Accordion.Item value={diff.file}>
|
||||
<Accordion.Header>
|
||||
<Accordion.Trigger>
|
||||
<div class="flex items-center justify-between w-full gap-5">
|
||||
<div class="grow flex items-center gap-5 min-w-0">
|
||||
<FileIcon
|
||||
node={{ path: diff.file, type: "file" }}
|
||||
class="shrink-0 size-4"
|
||||
/>
|
||||
<div class="flex grow min-w-0">
|
||||
<Show when={diff.file.includes("/")}>
|
||||
<span class="text-text-base truncate-start">
|
||||
{getDirectory(diff.file)}‎
|
||||
</span>
|
||||
</Show>
|
||||
<span class="text-text-strong shrink-0">
|
||||
{getFilename(diff.file)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shrink-0 flex gap-4 items-center justify-end">
|
||||
<DiffChanges changes={diff} />
|
||||
<Icon name="chevron-grabber-vertical" size="small" />
|
||||
</div>
|
||||
</div>
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content class="max-h-[360px] overflow-y-auto no-scrollbar">
|
||||
<Diff
|
||||
before={{
|
||||
name: diff.file!,
|
||||
contents: diff.before!,
|
||||
}}
|
||||
after={{
|
||||
name: diff.file!,
|
||||
contents: diff.after!,
|
||||
}}
|
||||
/>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)}
|
||||
</For>
|
||||
</Accordion>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={error() && !detailsExpanded()}>
|
||||
<Card variant="error" class="text-text-on-critical-base">
|
||||
{error()?.data?.message as string}
|
||||
</Card>
|
||||
</Show>
|
||||
{/* Response */}
|
||||
<div class="w-full">
|
||||
<Switch>
|
||||
<Match when={!completed()}>
|
||||
<MessageProgress assistantMessages={assistantMessages} done={!working()} />
|
||||
</Match>
|
||||
<Match when={completed() && hasToolPart()}>
|
||||
<Collapsible
|
||||
variant="ghost"
|
||||
open={detailsExpanded()}
|
||||
onOpenChange={setDetailsExpanded}
|
||||
>
|
||||
<Collapsible.Trigger class="text-text-weak hover:text-text-strong">
|
||||
<div class="flex items-center gap-1 self-stretch">
|
||||
<div class="text-12-medium">
|
||||
<Switch>
|
||||
<Match when={detailsExpanded()}>Hide details</Match>
|
||||
<Match when={!detailsExpanded()}>Show details</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
<Collapsible.Arrow />
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
<div class="w-full flex flex-col items-start self-stretch gap-3">
|
||||
<For each={assistantMessages()}>
|
||||
{(assistantMessage) => {
|
||||
const parts = createMemo(() => sync.data.part[assistantMessage.id])
|
||||
return <Message message={assistantMessage} parts={parts()} />
|
||||
}}
|
||||
</For>
|
||||
<Show when={error()}>
|
||||
<Card variant="error" class="text-text-on-critical-base">
|
||||
{error()?.data?.message as string}
|
||||
</Card>
|
||||
</Show>
|
||||
</div>
|
||||
</Collapsible.Content>
|
||||
</Collapsible>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<div class="size-full flex flex-col pb-45 justify-end items-start gap-4 flex-[1_0_0] self-stretch">
|
||||
<div class="text-20-medium text-text-weaker">New session</div>
|
||||
<div class="flex justify-center items-center gap-3">
|
||||
<Icon name="folder" size="small" />
|
||||
<div class="text-12-medium text-text-weak">
|
||||
{getDirectory(sync.data.path.directory)}
|
||||
<span class="text-text-strong">{getFilename(sync.data.path.directory)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center items-center gap-3">
|
||||
<Icon name="pencil-line" size="small" />
|
||||
<div class="text-12-medium text-text-weak">
|
||||
Last modified
|
||||
<span class="text-text-strong">
|
||||
{DateTime.fromMillis(sync.data.project.time.created).toRelative()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Match>
|
||||
</Switch>
|
||||
<div class="absolute inset-x-0 px-6 max-w-2xl flex flex-col justify-center items-center z-50 mx-auto bottom-8">
|
||||
<PromptInput
|
||||
ref={(el) => {
|
||||
inputRef = el
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={local.layout.review.state() === "open"}>
|
||||
<div
|
||||
classList={{
|
||||
"relative px-6 py-2 w-full flex flex-col gap-6 flex-1 min-h-0 border-l border-border-weak-base": true,
|
||||
}}
|
||||
>
|
||||
<div class="h-8 w-full flex items-center justify-between shrink-0 self-stretch">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<Tooltip value="Close">
|
||||
<IconButton icon="align-right" variant="ghost" onClick={local.layout.review.close} />
|
||||
</Tooltip>
|
||||
<Tooltip value="Open in tab">
|
||||
<IconButton
|
||||
icon="expand"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
local.layout.review.tab()
|
||||
session.layout.setActiveTab("review")
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-14-medium text-text-strong">All changes</div>
|
||||
<div class="h-full pb-40 overflow-y-auto no-scrollbar">
|
||||
<Accordion class="w-full" multiple>
|
||||
<For each={session.diffs()}>
|
||||
{(diff) => (
|
||||
<Accordion.Item value={diff.file} defaultOpen>
|
||||
<Accordion.Header>
|
||||
<Accordion.Trigger>
|
||||
<div class="flex items-center justify-between w-full gap-5">
|
||||
<div class="grow flex items-center gap-5 min-w-0">
|
||||
<FileIcon node={{ path: diff.file, type: "file" }} class="shrink-0 size-4" />
|
||||
<div class="flex grow min-w-0">
|
||||
<Show when={diff.file.includes("/")}>
|
||||
<span class="text-text-base truncate-start">
|
||||
{getDirectory(diff.file)}‎
|
||||
</span>
|
||||
</Show>
|
||||
<span class="text-text-strong shrink-0">{getFilename(diff.file)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shrink-0 flex gap-4 items-center justify-end">
|
||||
<DiffChanges changes={diff} />
|
||||
<Icon name="chevron-grabber-vertical" size="small" />
|
||||
</div>
|
||||
</div>
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
<Diff
|
||||
before={{
|
||||
name: diff.file!,
|
||||
contents: diff.before!,
|
||||
}}
|
||||
after={{
|
||||
name: diff.file!,
|
||||
contents: diff.after!,
|
||||
}}
|
||||
/>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)}
|
||||
</For>
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
{/* <Tabs.Content value="review" class="select-text"></Tabs.Content> */}
|
||||
<Show when={local.layout.review.state() === "tab" && session.diffs().length}>
|
||||
<Tabs.Content value="review" class="select-text">
|
||||
<div
|
||||
classList={{
|
||||
"relative px-6 py-2 w-full flex flex-col gap-6 flex-1 min-h-0": true,
|
||||
}}
|
||||
>
|
||||
<div class="h-8 w-full flex items-center justify-between shrink-0 self-stretch sticky top-0 bg-background-stronger z-100">
|
||||
<div class="flex items-center gap-x-3"></div>
|
||||
</div>
|
||||
<div class="text-14-medium text-text-strong">All changes</div>
|
||||
<div class="h-full pb-40 overflow-y-auto no-scrollbar">
|
||||
<Accordion class="w-full" multiple>
|
||||
<For each={session.diffs()}>
|
||||
{(diff) => (
|
||||
<Accordion.Item value={diff.file} defaultOpen>
|
||||
<Accordion.Header>
|
||||
<Accordion.Trigger>
|
||||
<div class="flex items-center justify-between w-full gap-5">
|
||||
<div class="grow flex items-center gap-5 min-w-0">
|
||||
<FileIcon node={{ path: diff.file, type: "file" }} class="shrink-0 size-4" />
|
||||
<div class="flex grow min-w-0">
|
||||
<Show when={diff.file.includes("/")}>
|
||||
<span class="text-text-base truncate-start">{getDirectory(diff.file)}‎</span>
|
||||
</Show>
|
||||
<span class="text-text-strong shrink-0">{getFilename(diff.file)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shrink-0 flex gap-4 items-center justify-end">
|
||||
<DiffChanges changes={diff} />
|
||||
<Icon name="chevron-grabber-vertical" size="small" />
|
||||
</div>
|
||||
</div>
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
<Diff
|
||||
diffStyle="split"
|
||||
before={{
|
||||
name: diff.file!,
|
||||
contents: diff.before!,
|
||||
}}
|
||||
after={{
|
||||
name: diff.file!,
|
||||
contents: diff.after!,
|
||||
}}
|
||||
/>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)}
|
||||
</For>
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
</Show>
|
||||
<For each={session.layout.tabs.opened}>
|
||||
{(tab) => {
|
||||
const [file] = createResource(
|
||||
@@ -587,14 +791,14 @@ export default function Page() {
|
||||
},
|
||||
)
|
||||
return (
|
||||
<Tabs.Content value={tab} class="select-text">
|
||||
<Tabs.Content value={tab} class="select-text mt-3">
|
||||
<Switch>
|
||||
<Match when={file()}>
|
||||
{(f) => (
|
||||
<Code
|
||||
file={{ name: f().path, contents: f().content?.content ?? "" }}
|
||||
overflow="scroll"
|
||||
class="pt-3 pb-40"
|
||||
class="pb-40"
|
||||
/>
|
||||
)}
|
||||
</Match>
|
||||
@@ -625,13 +829,15 @@ export default function Page() {
|
||||
</Show>
|
||||
</DragOverlay>
|
||||
</DragDropProvider>
|
||||
<div class="absolute inset-x-0 px-6 max-w-2xl flex flex-col justify-center items-center z-50 mx-auto bottom-8">
|
||||
<PromptInput
|
||||
ref={(el) => {
|
||||
inputRef = el
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Show when={session.layout.tabs.active}>
|
||||
<div class="absolute inset-x-0 px-6 max-w-2xl flex flex-col justify-center items-center z-50 mx-auto bottom-8">
|
||||
<PromptInput
|
||||
ref={(el) => {
|
||||
inputRef = el
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<div class="hidden shrink-0 w-56 p-2 h-full overflow-y-auto">
|
||||
{/* <FileTree path="" onFileClick={ handleTabClick} /> */}
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user