Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b957b5d1c | ||
|
|
31c7a0157c | ||
|
|
e728b94bca | ||
|
|
49040c0130 | ||
|
|
0d05238ee6 | ||
|
|
9b8a7da1e6 | ||
|
|
61fd21182c | ||
|
|
487c2b5e76 | ||
|
|
0e4703b227 | ||
|
|
84e0232bd5 | ||
|
|
35fbb011b2 | ||
|
|
6527a123f0 | ||
|
|
0377cfd37c | ||
|
|
edc933d816 | ||
|
|
0d608f6014 | ||
|
|
69a45ef7d7 | ||
|
|
1056b36eae | ||
|
|
35c737ac68 | ||
|
|
725a2c2e95 | ||
|
|
c724d2392f | ||
|
|
f5230d1f02 | ||
|
|
078111bd96 | ||
|
|
736f8882f5 | ||
|
|
37cf365927 | ||
|
|
b939470302 | ||
|
|
ef4b2baedc | ||
|
|
64d28ea457 | ||
|
|
2520780846 | ||
|
|
986c60353e | ||
|
|
5fc26c958a | ||
|
|
c1cf9cda6a | ||
|
|
10d376eab2 | ||
|
|
53fc8a861b | ||
|
|
1d8330331c | ||
|
|
7a03c7fe38 | ||
|
|
09bd32169c | ||
|
|
7ec32f834e | ||
|
|
205492c7e8 | ||
|
|
4c2e888709 | ||
|
|
c78fd097d1 | ||
|
|
340966195b | ||
|
|
92604b391b | ||
|
|
0c51feb9c2 | ||
|
|
d0b4169a6b | ||
|
|
1fc6c6fb2a | ||
|
|
14f9b95557 | ||
|
|
d3bf1fa1fa | ||
|
|
a8836c5615 | ||
|
|
779a27693a | ||
|
|
829d86840a | ||
|
|
e225294dd4 | ||
|
|
a673e3650d | ||
|
|
ff462dfd7a | ||
|
|
73443585e5 | ||
|
|
609ab069a9 | ||
|
|
ec3579d7cb | ||
|
|
f80a3fea31 | ||
|
|
43a8d1b1ae | ||
|
|
09fa84ccfc | ||
|
|
b981f0a205 | ||
|
|
767038afc3 | ||
|
|
a7774115c5 | ||
|
|
288bc88e40 | ||
|
|
6d36dbf9de | ||
|
|
4ab4baf3a4 | ||
|
|
90f05eb9c2 | ||
|
|
b63b6d04c6 | ||
|
|
8addaa7e08 | ||
|
|
a96bf8e62d | ||
|
|
c8bda598f5 | ||
|
|
c857cff585 | ||
|
|
fd9d2db755 | ||
|
|
b19fd14f80 | ||
|
|
a0f469095c | ||
|
|
0ccb26df94 | ||
|
|
71fd5966ad | ||
|
|
c02230de4f | ||
|
|
aa2e2c76c0 | ||
|
|
7c2d4ee79a | ||
|
|
e3a2728fa3 | ||
|
|
18260b037b | ||
|
|
ad83dd3ad9 | ||
|
|
6f37315cd1 | ||
|
|
d81dce6a82 | ||
|
|
0bd11e970b | ||
|
|
7e29e1dd23 | ||
|
|
491a2adf8d | ||
|
|
c07d6487a8 | ||
|
|
9990e84d37 | ||
|
|
0b86adbe99 | ||
|
|
834a2c09d5 | ||
|
|
f13c17e654 | ||
|
|
a0611d92e4 | ||
|
|
0b001c3e80 | ||
|
|
53b7cb62c4 | ||
|
|
c5e096c76a | ||
|
|
e1fc4a756b | ||
|
|
e5bc4cbbcf | ||
|
|
459d5ec19b | ||
|
|
8baa222621 | ||
|
|
ce1397cc34 | ||
|
|
dc7c5ced4c | ||
|
|
b8e8fe7e31 | ||
|
|
890085758f | ||
|
|
85f15893bc | ||
|
|
98be75b17c | ||
|
|
b5cc27b8ea | ||
|
|
05937b52cc | ||
|
|
62b82570e1 | ||
|
|
4bf75c0b44 | ||
|
|
a8a06c4983 | ||
|
|
b0b7fd143b | ||
|
|
140498eb4f | ||
|
|
ca5126e24d | ||
|
|
fb2b3e567c | ||
|
|
c672a1963b | ||
|
|
54bff6b120 | ||
|
|
ab3f198fab | ||
|
|
0057ef6336 | ||
|
|
4f604b3839 | ||
|
|
a20489584e | ||
|
|
a6b066bd47 | ||
|
|
37fdcac05a | ||
|
|
299bf1dca8 | ||
|
|
d685aa38ef | ||
|
|
995b23787c | ||
|
|
ed8e663e13 | ||
|
|
38cee3b848 | ||
|
|
6d116d4b54 | ||
|
|
7c4f111b34 | ||
|
|
f2fac29270 | ||
|
|
12892f0e12 | ||
|
|
9714a3558e | ||
|
|
e49a1d1f39 | ||
|
|
528565510d | ||
|
|
36cfda933d | ||
|
|
ecf5040966 | ||
|
|
7d56603c26 | ||
|
|
02b7cc8313 | ||
|
|
c9a52c9a85 | ||
|
|
dea668b0ea | ||
|
|
1bc3e92376 | ||
|
|
3f5acc3dff | ||
|
|
0588011476 | ||
|
|
bba72c82ae | ||
|
|
e95181a551 | ||
|
|
74e8c2e50f | ||
|
|
cdabafa264 | ||
|
|
0a92af60a0 | ||
|
|
c7808a4b01 | ||
|
|
7f978e07ff | ||
|
|
a4ae1bb9eb | ||
|
|
96a39803cc | ||
|
|
16f8f20b31 | ||
|
|
06b1684ddb | ||
|
|
c6e830c954 | ||
|
|
fc78c28df6 | ||
|
|
930a1bf358 | ||
|
|
6cf7f18cc9 | ||
|
|
3f59570ee6 | ||
|
|
304e956b5d | ||
|
|
538eaa42aa | ||
|
|
67c41fd389 | ||
|
|
83ea19770a | ||
|
|
3ace8543b2 | ||
|
|
eb855e1e31 | ||
|
|
5e53f054c6 | ||
|
|
5d5e184329 | ||
|
|
2fbb49ac30 | ||
|
|
c56b407e1d | ||
|
|
bdaa0e8b8c | ||
|
|
4e549b1c05 | ||
|
|
7be8e16c33 | ||
|
|
d1588f93a1 | ||
|
|
576696a370 | ||
|
|
2c6f9043e8 | ||
|
|
9f771ef0ae | ||
|
|
356715f67d | ||
|
|
540421267a | ||
|
|
e253398936 | ||
|
|
ee87e1f139 | ||
|
|
8887616457 | ||
|
|
905c034885 | ||
|
|
92f7c4943f | ||
|
|
10bde356b1 | ||
|
|
f7cc46cd9f | ||
|
|
d9ffe07391 | ||
|
|
c0702ed8bd | ||
|
|
b927b9dca6 | ||
|
|
4b7231be68 | ||
|
|
70a6fe96ea | ||
|
|
6e5971dff2 | ||
|
|
d48d6b3577 | ||
|
|
4b1668c3ef | ||
|
|
d85eb1b880 | ||
|
|
9637d70407 | ||
|
|
cfbbdc2e14 | ||
|
|
feb65201f6 | ||
|
|
f1f07a56d8 | ||
|
|
0fe313bd87 | ||
|
|
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 | ||
|
|
bb6acc0ec6 | ||
|
|
5a84b9f467 | ||
|
|
c7031dfd77 | ||
|
|
e136a40771 | ||
|
|
ef25650ced | ||
|
|
6555a33eff | ||
|
|
247ce44776 | ||
|
|
4e7bfaab8b | ||
|
|
8b26a1f9bd | ||
|
|
2a9b6a85de | ||
|
|
c9ae89a38b | ||
|
|
e316050bf5 | ||
|
|
306f45f04a | ||
|
|
e006e3355c | ||
|
|
d7e31f76c4 | ||
|
|
d425723249 | ||
|
|
c59ec71918 | ||
|
|
05ae99a09b | ||
|
|
6e22b45905 | ||
|
|
c664f92829 | ||
|
|
f95333aaa4 | ||
|
|
ef0b5e3dcb | ||
|
|
b7262b8527 | ||
|
|
1f44c7f750 | ||
|
|
7dba570195 | ||
|
|
3d04ba26a3 | ||
|
|
3660e2c481 | ||
|
|
06ca45189b | ||
|
|
674febcf60 | ||
|
|
582d9a9622 | ||
|
|
d525fbf829 | ||
|
|
69a499f807 | ||
|
|
37e564139f | ||
|
|
ee8b81269b | ||
|
|
53998a2fed | ||
|
|
af7b9e77d1 | ||
|
|
77c65b18b5 | ||
|
|
c9dfe6d964 | ||
|
|
03f7f18260 | ||
|
|
2db76fc6dd | ||
|
|
7269c2316d | ||
|
|
1e0596bc46 | ||
|
|
3ebec2435a | ||
|
|
b90c0b5fac | ||
|
|
3b1ab444fd | ||
|
|
234db24f1f | ||
|
|
04546c0873 | ||
|
|
f51bd91af4 | ||
|
|
ebca25462e | ||
|
|
01b9148c04 | ||
|
|
d3e080894c | ||
|
|
ee9aa24a55 | ||
|
|
16e2bded5b | ||
|
|
9fb49ab87b | ||
|
|
8d6a03cc89 | ||
|
|
71b04ffa99 | ||
|
|
678ca757c9 | ||
|
|
272349b8da | ||
|
|
7088bfabd7 | ||
|
|
fe94bb8e50 | ||
|
|
ba8bc1b8b4 | ||
|
|
8a9a474df6 | ||
|
|
52e2b40610 | ||
|
|
ee1ff8cc07 | ||
|
|
434c0ff0d7 | ||
|
|
7a7060ef15 | ||
|
|
f9af9fc221 | ||
|
|
1bf1b93404 | ||
|
|
bc6f4aed2b | ||
|
|
dbdbfb8543 | ||
|
|
521803aaa3 | ||
|
|
2af3f19397 | ||
|
|
9275665868 | ||
|
|
09bb819064 | ||
|
|
6f0028644e | ||
|
|
aec44abcf6 | ||
|
|
b41e573886 | ||
|
|
737ddab300 | ||
|
|
90fc3ddb02 | ||
|
|
15d7eebb92 | ||
|
|
33301c94df | ||
|
|
d341d26e37 | ||
|
|
d49b1b25d1 | ||
|
|
25eb100210 | ||
|
|
9886353715 | ||
|
|
f501501791 | ||
|
|
c103052f93 | ||
|
|
68039d4c71 | ||
|
|
d3566d3b1a | ||
|
|
b275e18d28 | ||
|
|
af9a1797b5 | ||
|
|
29b3e40ddb | ||
|
|
c49f5939a2 | ||
|
|
63862b1609 | ||
|
|
1cf1e88b52 | ||
|
|
d06afd87e5 | ||
|
|
9fb6e81007 | ||
|
|
3ac82227f1 | ||
|
|
c1f9249c84 | ||
|
|
9bb66946db | ||
|
|
adcdbbddc7 | ||
|
|
662435c5bb | ||
|
|
36c1a05eaa | ||
|
|
5708e3bf1e | ||
|
|
0da1ed3fc8 | ||
|
|
d5179c8b63 | ||
|
|
bd0a4f7bbe | ||
|
|
3d43214075 | ||
|
|
178a14ce3e | ||
|
|
8e1010dc3f | ||
|
|
9c82f1f5e9 | ||
|
|
e5a651eef7 | ||
|
|
d26605aa56 | ||
|
|
5cc0d337b1 | ||
|
|
902763b47d | ||
|
|
55d07a139c | ||
|
|
05232ead93 | ||
|
|
7652a96064 | ||
|
|
901aae09f7 | ||
|
|
f95799f17c | ||
|
|
99a6c5e44d | ||
|
|
07bb75f086 | ||
|
|
66eb846e6f | ||
|
|
34f11c699e | ||
|
|
7a32fec008 | ||
|
|
37a6b5177e | ||
|
|
573ffe186b | ||
|
|
0f7ff3fcb1 | ||
|
|
2c3aa330b9 | ||
|
|
47b2fb79dc | ||
|
|
6deaf54bb3 | ||
|
|
d549cd3213 | ||
|
|
93e52f7ecf | ||
|
|
88f12b0822 | ||
|
|
54af7f9e18 | ||
|
|
be685e95a3 | ||
|
|
dc2ab75fca | ||
|
|
f1324e886f | ||
|
|
c47fde2ca4 | ||
|
|
f42e1c6375 | ||
|
|
f68374ad22 | ||
|
|
5e86c9b791 | ||
|
|
94658c31c5 | ||
|
|
9fd672a1cb | ||
|
|
10523c4372 | ||
|
|
d1cd7d0344 | ||
|
|
06ac1be226 | ||
|
|
05489bc843 | ||
|
|
3f02eecf22 | ||
|
|
f5ca78ed7b | ||
|
|
894cbaa51e | ||
|
|
8b70b89fde | ||
|
|
f9dbc586dc | ||
|
|
ffeef63ca1 | ||
|
|
4da58294d9 | ||
|
|
fa2e88f49b | ||
|
|
28e765ef0a | ||
|
|
bfbcb5f200 | ||
|
|
89492b3002 | ||
|
|
2663415d47 | ||
|
|
51be67cc14 | ||
|
|
92a1943771 | ||
|
|
1e15fc273a | ||
|
|
104a895a71 | ||
|
|
f98e730405 | ||
|
|
b12bef05d3 | ||
|
|
2f1d001cc5 | ||
|
|
65d0b3ed6d | ||
|
|
22a34d7958 | ||
|
|
cb4401ec92 | ||
|
|
febf467b03 | ||
|
|
d55a2fd56c | ||
|
|
40f577e5e7 | ||
|
|
9e49870118 | ||
|
|
fe38e3ab02 | ||
|
|
0170577743 | ||
|
|
7de6ea5922 | ||
|
|
2fe7d13e69 | ||
|
|
1bc3c98ae7 | ||
|
|
55787f2caa | ||
|
|
7df61a74a0 | ||
|
|
4f23110880 | ||
|
|
041353f4ff | ||
|
|
c72f8b17c6 | ||
|
|
eb304f4115 | ||
|
|
5565f14ef5 | ||
|
|
10a4455c6f | ||
|
|
5ded6d6ad7 | ||
|
|
849a38c30c | ||
|
|
68050ab802 | ||
|
|
91d01fd4cc | ||
|
|
9beb0f8512 | ||
|
|
d4cb47eadc | ||
|
|
261ff416a9 | ||
|
|
d0a70cb217 | ||
|
|
20fc56d020 | ||
|
|
a57ae3ec93 | ||
|
|
30f9fa12d9 | ||
|
|
d473d4ffc8 | ||
|
|
af50596529 | ||
|
|
3823d8d50e | ||
|
|
7a926b32ce | ||
|
|
a5ede68241 | ||
|
|
60dc38050d | ||
|
|
31d0caee38 | ||
|
|
2a7ab45605 | ||
|
|
019054dd1e | ||
|
|
a018a15f32 | ||
|
|
e630d680dd | ||
|
|
9e392f25a6 | ||
|
|
2cc4e6ad7c | ||
|
|
70d8d1ab1e | ||
|
|
342aa27e03 | ||
|
|
e1aed0cd01 |
@@ -5,15 +5,17 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version-file: package.json
|
||||||
|
|
||||||
- name: Cache ~/.bun
|
- name: Cache ~/.bun
|
||||||
id: cache-bun
|
id: cache-bun
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.bun
|
path: ~/.bun
|
||||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lockb', 'bun.lock') }}
|
key: ${{ runner.os }}-bun-${{ hashFiles('package.json') }}-${{ hashFiles('bun.lockb', 'bun.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-bun-
|
${{ runner.os }}-bun-${{ hashFiles('package.json') }}-
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install
|
run: bun install
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
issues: write
|
issues: write
|
||||||
steps:
|
steps:
|
||||||
- name: Add opentui label
|
- name: Auto-label and assign issues
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -20,21 +20,36 @@ jobs:
|
|||||||
const title = issue.title;
|
const title = issue.title;
|
||||||
const description = issue.body || '';
|
const description = issue.body || '';
|
||||||
|
|
||||||
// Check for version patterns like v1.0.x or 1.0.x
|
// Check for "opencode web" keyword
|
||||||
const versionPattern = /\b[v]?1\.0\.[x\d]\b/i;
|
const webPattern = /(opencode web)/i;
|
||||||
|
const isWebRelated = webPattern.test(title) || webPattern.test(description);
|
||||||
|
|
||||||
if (versionPattern.test(title) || versionPattern.test(description)) {
|
// Check for version patterns like v1.0.x or 1.0.x
|
||||||
|
const versionPattern = /[v]?1\.0\./i;
|
||||||
|
const isVersionRelated = versionPattern.test(title) || versionPattern.test(description);
|
||||||
|
|
||||||
|
if (isWebRelated) {
|
||||||
|
// Add web label
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
labels: ['web']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assign to adamdotdevin
|
||||||
|
await github.rest.issues.addAssignees({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
assignees: ['adamdotdevin']
|
||||||
|
});
|
||||||
|
} else if (isVersionRelated) {
|
||||||
|
// Only add opentui if NOT web-related
|
||||||
await github.rest.issues.addLabels({
|
await github.rest.issues.addLabels({
|
||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
labels: ['opentui']
|
labels: ['opentui']
|
||||||
});
|
});
|
||||||
|
|
||||||
await github.rest.issues.addAssignees({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: issue.number,
|
|
||||||
assignees: ['thdxr']
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,4 +26,4 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
|
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
|
||||||
with:
|
with:
|
||||||
model: opencode/kimi-k2
|
model: opencode/glm-4.6
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ on:
|
|||||||
- major
|
- major
|
||||||
- minor
|
- minor
|
||||||
- patch
|
- patch
|
||||||
|
version:
|
||||||
|
description: "Override version (optional)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
|
||||||
@@ -62,6 +66,7 @@ jobs:
|
|||||||
./script/publish.ts
|
./script/publish.ts
|
||||||
env:
|
env:
|
||||||
OPENCODE_BUMP: ${{ inputs.bump }}
|
OPENCODE_BUMP: ${{ inputs.bump }}
|
||||||
|
OPENCODE_VERSION: ${{ inputs.version }}
|
||||||
OPENCODE_CHANNEL: latest
|
OPENCODE_CHANNEL: latest
|
||||||
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
- opentui
|
- fix-build
|
||||||
- v0
|
- v0
|
||||||
|
|
||||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: "sync-zed-extension"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
zed:
|
||||||
|
name: Release Zed Extension
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: ./.github/actions/setup-bun
|
||||||
|
|
||||||
|
- name: Get version tag
|
||||||
|
id: get_tag
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "release" ]; then
|
||||||
|
TAG="${{ github.event.release.tag_name }}"
|
||||||
|
else
|
||||||
|
TAG=$(git tag --list 'v[0-9]*.*' --sort=-version:refname | head -n 1)
|
||||||
|
fi
|
||||||
|
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||||
|
echo "Using tag: ${TAG}"
|
||||||
|
|
||||||
|
- name: Sync Zed extension
|
||||||
|
run: |
|
||||||
|
./script/sync-zed.ts ${{ steps.get_tag.outputs.tag }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||||
@@ -5,8 +5,11 @@ node_modules
|
|||||||
.env
|
.env
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
|
*~
|
||||||
openapi.json
|
openapi.json
|
||||||
playground
|
playground
|
||||||
tmp
|
tmp
|
||||||
dist
|
dist
|
||||||
.turbo
|
.turbo
|
||||||
|
**/.serena
|
||||||
|
.serena/
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ For anything in the packages/app use the ignore: prefix.
|
|||||||
prefer to explain WHY something was done from an end user perspective instead of
|
prefer to explain WHY something was done from an end user perspective instead of
|
||||||
WHAT was done.
|
WHAT was done.
|
||||||
|
|
||||||
do not do generic messages like "improvied agent experience" be very specific
|
do not do generic messages like "improved agent experience" be very specific
|
||||||
about what user facing changes were made
|
about what user facing changes were made
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://opencode.ai/config.json",
|
||||||
|
"plugin": ["opencode-openai-codex-auth"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://opencode.ai/theme.json",
|
||||||
|
"defs": {
|
||||||
|
"nord0": "#2E3440",
|
||||||
|
"nord1": "#3B4252",
|
||||||
|
"nord2": "#434C5E",
|
||||||
|
"nord3": "#4C566A",
|
||||||
|
"nord4": "#D8DEE9",
|
||||||
|
"nord5": "#E5E9F0",
|
||||||
|
"nord6": "#ECEFF4",
|
||||||
|
"nord7": "#8FBCBB",
|
||||||
|
"nord8": "#88C0D0",
|
||||||
|
"nord9": "#81A1C1",
|
||||||
|
"nord10": "#5E81AC",
|
||||||
|
"nord11": "#BF616A",
|
||||||
|
"nord12": "#D08770",
|
||||||
|
"nord13": "#EBCB8B",
|
||||||
|
"nord14": "#A3BE8C",
|
||||||
|
"nord15": "#B48EAD"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"primary": {
|
||||||
|
"dark": "nord8",
|
||||||
|
"light": "nord10"
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"dark": "nord9",
|
||||||
|
"light": "nord9"
|
||||||
|
},
|
||||||
|
"accent": {
|
||||||
|
"dark": "nord7",
|
||||||
|
"light": "nord7"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"dark": "nord11",
|
||||||
|
"light": "nord11"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"dark": "nord12",
|
||||||
|
"light": "nord12"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"dark": "nord14",
|
||||||
|
"light": "nord14"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"dark": "nord8",
|
||||||
|
"light": "nord10"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"dark": "nord4",
|
||||||
|
"light": "nord0"
|
||||||
|
},
|
||||||
|
"textMuted": {
|
||||||
|
"dark": "nord3",
|
||||||
|
"light": "nord1"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"dark": "nord0",
|
||||||
|
"light": "nord6"
|
||||||
|
},
|
||||||
|
"backgroundPanel": {
|
||||||
|
"dark": "nord1",
|
||||||
|
"light": "nord5"
|
||||||
|
},
|
||||||
|
"backgroundElement": {
|
||||||
|
"dark": "nord1",
|
||||||
|
"light": "nord4"
|
||||||
|
},
|
||||||
|
"border": {
|
||||||
|
"dark": "nord2",
|
||||||
|
"light": "nord3"
|
||||||
|
},
|
||||||
|
"borderActive": {
|
||||||
|
"dark": "nord3",
|
||||||
|
"light": "nord2"
|
||||||
|
},
|
||||||
|
"borderSubtle": {
|
||||||
|
"dark": "nord2",
|
||||||
|
"light": "nord3"
|
||||||
|
},
|
||||||
|
"diffAdded": {
|
||||||
|
"dark": "nord14",
|
||||||
|
"light": "nord14"
|
||||||
|
},
|
||||||
|
"diffRemoved": {
|
||||||
|
"dark": "nord11",
|
||||||
|
"light": "nord11"
|
||||||
|
},
|
||||||
|
"diffContext": {
|
||||||
|
"dark": "nord3",
|
||||||
|
"light": "nord3"
|
||||||
|
},
|
||||||
|
"diffHunkHeader": {
|
||||||
|
"dark": "nord3",
|
||||||
|
"light": "nord3"
|
||||||
|
},
|
||||||
|
"diffHighlightAdded": {
|
||||||
|
"dark": "nord14",
|
||||||
|
"light": "nord14"
|
||||||
|
},
|
||||||
|
"diffHighlightRemoved": {
|
||||||
|
"dark": "nord11",
|
||||||
|
"light": "nord11"
|
||||||
|
},
|
||||||
|
"diffAddedBg": {
|
||||||
|
"dark": "#3B4252",
|
||||||
|
"light": "#E5E9F0"
|
||||||
|
},
|
||||||
|
"diffRemovedBg": {
|
||||||
|
"dark": "#3B4252",
|
||||||
|
"light": "#E5E9F0"
|
||||||
|
},
|
||||||
|
"diffContextBg": {
|
||||||
|
"dark": "nord1",
|
||||||
|
"light": "nord5"
|
||||||
|
},
|
||||||
|
"diffLineNumber": {
|
||||||
|
"dark": "nord2",
|
||||||
|
"light": "nord4"
|
||||||
|
},
|
||||||
|
"diffAddedLineNumberBg": {
|
||||||
|
"dark": "#3B4252",
|
||||||
|
"light": "#E5E9F0"
|
||||||
|
},
|
||||||
|
"diffRemovedLineNumberBg": {
|
||||||
|
"dark": "#3B4252",
|
||||||
|
"light": "#E5E9F0"
|
||||||
|
},
|
||||||
|
"markdownText": {
|
||||||
|
"dark": "nord4",
|
||||||
|
"light": "nord0"
|
||||||
|
},
|
||||||
|
"markdownHeading": {
|
||||||
|
"dark": "nord8",
|
||||||
|
"light": "nord10"
|
||||||
|
},
|
||||||
|
"markdownLink": {
|
||||||
|
"dark": "nord9",
|
||||||
|
"light": "nord9"
|
||||||
|
},
|
||||||
|
"markdownLinkText": {
|
||||||
|
"dark": "nord7",
|
||||||
|
"light": "nord7"
|
||||||
|
},
|
||||||
|
"markdownCode": {
|
||||||
|
"dark": "nord14",
|
||||||
|
"light": "nord14"
|
||||||
|
},
|
||||||
|
"markdownBlockQuote": {
|
||||||
|
"dark": "nord3",
|
||||||
|
"light": "nord3"
|
||||||
|
},
|
||||||
|
"markdownEmph": {
|
||||||
|
"dark": "nord12",
|
||||||
|
"light": "nord12"
|
||||||
|
},
|
||||||
|
"markdownStrong": {
|
||||||
|
"dark": "nord13",
|
||||||
|
"light": "nord13"
|
||||||
|
},
|
||||||
|
"markdownHorizontalRule": {
|
||||||
|
"dark": "nord3",
|
||||||
|
"light": "nord3"
|
||||||
|
},
|
||||||
|
"markdownListItem": {
|
||||||
|
"dark": "nord8",
|
||||||
|
"light": "nord10"
|
||||||
|
},
|
||||||
|
"markdownListEnumeration": {
|
||||||
|
"dark": "nord7",
|
||||||
|
"light": "nord7"
|
||||||
|
},
|
||||||
|
"markdownImage": {
|
||||||
|
"dark": "nord9",
|
||||||
|
"light": "nord9"
|
||||||
|
},
|
||||||
|
"markdownImageText": {
|
||||||
|
"dark": "nord7",
|
||||||
|
"light": "nord7"
|
||||||
|
},
|
||||||
|
"markdownCodeBlock": {
|
||||||
|
"dark": "nord4",
|
||||||
|
"light": "nord0"
|
||||||
|
},
|
||||||
|
"syntaxComment": {
|
||||||
|
"dark": "nord3",
|
||||||
|
"light": "nord3"
|
||||||
|
},
|
||||||
|
"syntaxKeyword": {
|
||||||
|
"dark": "nord9",
|
||||||
|
"light": "nord9"
|
||||||
|
},
|
||||||
|
"syntaxFunction": {
|
||||||
|
"dark": "nord8",
|
||||||
|
"light": "nord8"
|
||||||
|
},
|
||||||
|
"syntaxVariable": {
|
||||||
|
"dark": "nord7",
|
||||||
|
"light": "nord7"
|
||||||
|
},
|
||||||
|
"syntaxString": {
|
||||||
|
"dark": "nord14",
|
||||||
|
"light": "nord14"
|
||||||
|
},
|
||||||
|
"syntaxNumber": {
|
||||||
|
"dark": "nord15",
|
||||||
|
"light": "nord15"
|
||||||
|
},
|
||||||
|
"syntaxType": {
|
||||||
|
"dark": "nord7",
|
||||||
|
"light": "nord7"
|
||||||
|
},
|
||||||
|
"syntaxOperator": {
|
||||||
|
"dark": "nord9",
|
||||||
|
"light": "nord9"
|
||||||
|
},
|
||||||
|
"syntaxPunctuation": {
|
||||||
|
"dark": "nord4",
|
||||||
|
"light": "nord0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,31 +17,31 @@
|
|||||||
|
|
||||||
## Tool Calling
|
## Tool Calling
|
||||||
|
|
||||||
- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. Here is an example illustrating how to execute 3 parallel file reads in this chat environnement:
|
- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. Here is an example illustrating how to execute 3 parallel file reads in this chat environment:
|
||||||
|
|
||||||
json
|
json
|
||||||
{
|
{
|
||||||
"recipient_name": "multi_tool_use.parallel",
|
"recipient_name": "multi_tool_use.parallel",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"tool_uses": [
|
"tool_uses": [
|
||||||
{
|
{
|
||||||
"recipient_name": "functions.read",
|
"recipient_name": "functions.read",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"filePath": "path/to/file.tsx"
|
"filePath": "path/to/file.tsx"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"recipient_name": "functions.read",
|
"recipient_name": "functions.read",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"filePath": "path/to/file.ts"
|
"filePath": "path/to/file.ts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"recipient_name": "functions.read",
|
"recipient_name": "functions.read",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"filePath": "path/to/file.md"
|
"filePath": "path/to/file.md"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -26,7 +26,7 @@ Want to take on an issue? Leave a comment and a maintainer may assign it to you
|
|||||||
|
|
||||||
## Developing OpenCode
|
## Developing OpenCode
|
||||||
|
|
||||||
- Requirements: Bun 1.3+, Go 1.24.x.
|
- Requirements: Bun 1.3+
|
||||||
- Install dependencies and start the dev server from the repo root:
|
- Install dependencies and start the dev server from the repo root:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -36,11 +36,11 @@ Want to take on an issue? Leave a comment and a maintainer may assign it to you
|
|||||||
|
|
||||||
- Core pieces:
|
- Core pieces:
|
||||||
- `packages/opencode`: OpenCode core business logic & server.
|
- `packages/opencode`: OpenCode core business logic & server.
|
||||||
- `packages/tui`: The TUI code, written in Go (will be removed soon in favor of [opentui](https://github.com/sst/opentui))
|
- `packages/opencode/src/cli/cmd/tui/`: The TUI code, written in SolidJS with [opentui](https://github.com/sst/opentui)
|
||||||
- `packages/plugin`: Source for `@opencode-ai/plugin`
|
- `packages/plugin`: Source for `@opencode-ai/plugin`
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> After touching `packages/opencode/src/server/server.ts`, the OpenCode team must regenerate the Stainless SDK before any client updates merge.
|
> After touching `packages/opencode/src/server/server.ts`, run "./packages/sdk/js/script/build.ts" to regenerate the JS sdk.
|
||||||
|
|
||||||
## Pull Request Expectations
|
## Pull Request Expectations
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ curl -fsSL https://opencode.ai/install | bash
|
|||||||
npm i -g opencode-ai@latest # or bun/pnpm/yarn
|
npm i -g opencode-ai@latest # or bun/pnpm/yarn
|
||||||
scoop bucket add extras; scoop install extras/opencode # Windows
|
scoop bucket add extras; scoop install extras/opencode # Windows
|
||||||
choco install opencode # Windows
|
choco install opencode # Windows
|
||||||
brew install sst/tap/opencode # macOS and Linux
|
brew install opencode # macOS and Linux
|
||||||
paru -S opencode-bin # Arch Linux
|
paru -S opencode-bin # Arch Linux
|
||||||
|
mise use --pin -g ubi:sst/opencode # Any OS
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
|
|||||||
@@ -126,3 +126,18 @@
|
|||||||
| 2025-10-30 | 613,746 (+7,487) | 542,064 (+0) | 1,155,810 (+7,487) |
|
| 2025-10-30 | 613,746 (+7,487) | 542,064 (+0) | 1,155,810 (+7,487) |
|
||||||
| 2025-10-30 | 617,846 (+4,100) | 555,026 (+12,962) | 1,172,872 (+17,062) |
|
| 2025-10-30 | 617,846 (+4,100) | 555,026 (+12,962) | 1,172,872 (+17,062) |
|
||||||
| 2025-10-31 | 626,612 (+8,766) | 564,579 (+9,553) | 1,191,191 (+18,319) |
|
| 2025-10-31 | 626,612 (+8,766) | 564,579 (+9,553) | 1,191,191 (+18,319) |
|
||||||
|
| 2025-11-01 | 636,100 (+9,488) | 581,806 (+17,227) | 1,217,906 (+26,715) |
|
||||||
|
| 2025-11-02 | 644,067 (+7,967) | 590,004 (+8,198) | 1,234,071 (+16,165) |
|
||||||
|
| 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) |
|
||||||
|
| 2025-11-09 | 713,462 (+7,427) | 660,459 (+6,970) | 1,373,921 (+14,397) |
|
||||||
|
| 2025-11-10 | 722,288 (+8,826) | 668,225 (+7,766) | 1,390,513 (+16,592) |
|
||||||
|
| 2025-11-11 | 729,769 (+7,481) | 677,501 (+9,276) | 1,407,270 (+16,757) |
|
||||||
|
| 2025-11-12 | 740,180 (+10,411) | 686,454 (+8,953) | 1,426,634 (+19,364) |
|
||||||
|
| 2025-11-13 | 749,905 (+9,725) | 696,157 (+9,703) | 1,446,062 (+19,428) |
|
||||||
|
| 2025-11-14 | 759,928 (+10,023) | 705,237 (+9,080) | 1,465,165 (+19,103) |
|
||||||
|
| 2025-11-15 | 765,955 (+6,027) | 712,870 (+7,633) | 1,478,825 (+13,660) |
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
[install]
|
[install]
|
||||||
exact = true
|
exact = true
|
||||||
|
|||||||
+5
-1
@@ -152,6 +152,9 @@ try {
|
|||||||
return session.id.slice(-8)
|
return session.id.slice(-8)
|
||||||
})()
|
})()
|
||||||
console.log("opencode session", session.id)
|
console.log("opencode session", session.id)
|
||||||
|
if (shareId) {
|
||||||
|
console.log("Share link:", `${useShareUrl()}/s/${shareId}`)
|
||||||
|
}
|
||||||
|
|
||||||
// Handle 3 cases
|
// Handle 3 cases
|
||||||
// 1. Issue
|
// 1. Issue
|
||||||
@@ -730,12 +733,13 @@ async function updateComment(body: string) {
|
|||||||
async function createPR(base: string, branch: string, title: string, body: string) {
|
async function createPR(base: string, branch: string, title: string, body: string) {
|
||||||
console.log("Creating pull request...")
|
console.log("Creating pull request...")
|
||||||
const { repo } = useContext()
|
const { repo } = useContext()
|
||||||
|
const truncatedTitle = title.length > 256 ? title.slice(0, 253) + "..." : title
|
||||||
const pr = await octoRest.rest.pulls.create({
|
const pr = await octoRest.rest.pulls.create({
|
||||||
owner: repo.owner,
|
owner: repo.owner,
|
||||||
repo: repo.repo,
|
repo: repo.repo,
|
||||||
head: branch,
|
head: branch,
|
||||||
base,
|
base,
|
||||||
title,
|
title: truncatedTitle,
|
||||||
body,
|
body,
|
||||||
})
|
})
|
||||||
return pr.data.number
|
return pr.data.number
|
||||||
|
|||||||
Vendored
+1
-1
@@ -6,4 +6,4 @@
|
|||||||
/// <reference path="../sst-env.d.ts" />
|
/// <reference path="../sst-env.d.ts" />
|
||||||
|
|
||||||
import "sst"
|
import "sst"
|
||||||
export {}
|
export {}
|
||||||
|
|||||||
+12
-2
@@ -97,7 +97,8 @@ export const stripeWebhook = new stripe.WebhookEndpoint("StripeWebhookEndpoint",
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const ZEN_MODELS = new sst.Secret("ZEN_MODELS")
|
const ZEN_MODELS1 = new sst.Secret("ZEN_MODELS1")
|
||||||
|
const ZEN_MODELS2 = new sst.Secret("ZEN_MODELS2")
|
||||||
const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
|
const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
|
||||||
const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
|
const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
|
||||||
properties: { value: auth.url.apply((url) => url!) },
|
properties: { value: auth.url.apply((url) => url!) },
|
||||||
@@ -105,6 +106,7 @@ const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
|
|||||||
const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", {
|
const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", {
|
||||||
properties: { value: stripeWebhook.secret },
|
properties: { value: stripeWebhook.secret },
|
||||||
})
|
})
|
||||||
|
const gatewayKv = new sst.cloudflare.Kv("GatewayKv")
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// CONSOLE
|
// CONSOLE
|
||||||
@@ -130,10 +132,18 @@ new sst.cloudflare.x.SolidStart("Console", {
|
|||||||
AUTH_API_URL,
|
AUTH_API_URL,
|
||||||
STRIPE_WEBHOOK_SECRET,
|
STRIPE_WEBHOOK_SECRET,
|
||||||
STRIPE_SECRET_KEY,
|
STRIPE_SECRET_KEY,
|
||||||
ZEN_MODELS,
|
ZEN_MODELS1,
|
||||||
|
ZEN_MODELS2,
|
||||||
EMAILOCTOPUS_API_KEY,
|
EMAILOCTOPUS_API_KEY,
|
||||||
AWS_SES_ACCESS_KEY_ID,
|
AWS_SES_ACCESS_KEY_ID,
|
||||||
AWS_SES_SECRET_ACCESS_KEY,
|
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: {
|
environment: {
|
||||||
//VITE_DOCS_URL: web.url.apply((url) => url!),
|
//VITE_DOCS_URL: web.url.apply((url) => url!),
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"keep": {
|
"keep": {
|
||||||
"days": true,
|
"days": true,
|
||||||
"amount": 14
|
"amount": 14
|
||||||
},
|
},
|
||||||
"auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json",
|
"auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"date": 1759827172859,
|
"date": 1759827172859,
|
||||||
"name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log",
|
"name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log",
|
||||||
"hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16"
|
"hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hashType": "sha256"
|
"hashType": "sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://opencode.ai/config.json",
|
|
||||||
"plugin": ["opencode-openai-codex-auth"],
|
|
||||||
"mcp": {
|
|
||||||
"weather": {
|
|
||||||
"type": "local",
|
|
||||||
"command": ["bun", "x", "@h1deya/mcp-server-weather"]
|
|
||||||
},
|
|
||||||
"context7": {
|
|
||||||
"type": "remote",
|
|
||||||
"url": "https://mcp.context7.com/mcp",
|
|
||||||
"headers": {
|
|
||||||
"CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-4
@@ -4,7 +4,7 @@
|
|||||||
"description": "AI-powered development tool",
|
"description": "AI-powered development tool",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "bun@1.3.0",
|
"packageManager": "bun@1.3.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
|
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
|
||||||
"typecheck": "bun turbo typecheck",
|
"typecheck": "bun turbo typecheck",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"@tsconfig/bun": "1.0.9",
|
"@tsconfig/bun": "1.0.9",
|
||||||
"@cloudflare/workers-types": "4.20251008.0",
|
"@cloudflare/workers-types": "4.20251008.0",
|
||||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||||
"@pierre/precision-diffs": "0.4.1",
|
"@pierre/precision-diffs": "0.4.4",
|
||||||
"@solidjs/meta": "0.29.4",
|
"@solidjs/meta": "0.29.4",
|
||||||
"@tailwindcss/vite": "4.1.11",
|
"@tailwindcss/vite": "4.1.11",
|
||||||
"diff": "8.0.2",
|
"diff": "8.0.2",
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"husky": "9.1.7",
|
"husky": "9.1.7",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"sst": "3.17.19",
|
"sst": "3.17.23",
|
||||||
"turbo": "2.5.6"
|
"turbo": "2.5.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"printWidth": 100
|
"printWidth": 120
|
||||||
},
|
},
|
||||||
"trustedDependencies": [
|
"trustedDependencies": [
|
||||||
"esbuild",
|
"esbuild",
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ app.config.timestamp_*.js
|
|||||||
# Temp
|
# Temp
|
||||||
gitignore
|
gitignore
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
public/sitemap.xml
|
||||||
|
|
||||||
# System Files
|
# System Files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
"typecheck": "tsgo --noEmit",
|
"typecheck": "tsgo --noEmit",
|
||||||
"dev": "vinxi dev --host 0.0.0.0",
|
"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",
|
"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",
|
"start": "vinxi start",
|
||||||
"version": "1.0.2"
|
"version": "1.0.67"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ibm/plex": "6.4.1",
|
"@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,7 +12,7 @@ export default function App() {
|
|||||||
root={(props) => (
|
root={(props) => (
|
||||||
<MetaProvider>
|
<MetaProvider>
|
||||||
<Title>opencode</Title>
|
<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>
|
<Suspense>{props.children}</Suspense>
|
||||||
</MetaProvider>
|
</MetaProvider>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -77,4 +77,4 @@
|
|||||||
background-color: var(--color-accent-alpha);
|
background-color: var(--color-accent-alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { createAsync } from "@solidjs/router"
|
import { createAsync } from "@solidjs/router"
|
||||||
import { createMemo } from "solid-js"
|
import { createMemo } from "solid-js"
|
||||||
import { github } from "~/lib/github"
|
import { github } from "~/lib/github"
|
||||||
|
import { config } from "~/config"
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
const githubData = createAsync(() => github())
|
const githubData = createAsync(() => github())
|
||||||
@@ -10,13 +11,13 @@ export function Footer() {
|
|||||||
notation: "compact",
|
notation: "compact",
|
||||||
compactDisplay: "short",
|
compactDisplay: "short",
|
||||||
}).format(githubData()!.stars!)
|
}).format(githubData()!.stars!)
|
||||||
: "25K",
|
: config.github.starsFormatted.compact,
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer data-component="footer">
|
<footer data-component="footer">
|
||||||
<div data-slot="cell">
|
<div data-slot="cell">
|
||||||
<a href="https://github.com/sst/opencode" target="_blank">
|
<a href={config.github.repoUrl} target="_blank">
|
||||||
GitHub <span>[{starCount()}]</span>
|
GitHub <span>[{starCount()}]</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -27,7 +28,7 @@ export function Footer() {
|
|||||||
<a href="/discord">Discord</a>
|
<a href="/discord">Discord</a>
|
||||||
</div>
|
</div>
|
||||||
<div data-slot="cell">
|
<div data-slot="cell">
|
||||||
<a href="https://x.com/opencode">X</a>
|
<a href={config.social.twitter}>X</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { createMemo, Match, Show, Switch } from "solid-js"
|
|||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { github } from "~/lib/github"
|
import { github } from "~/lib/github"
|
||||||
import { createEffect, onCleanup } from "solid-js"
|
import { createEffect, onCleanup } from "solid-js"
|
||||||
|
import { config } from "~/config"
|
||||||
import "./header-context-menu.css"
|
import "./header-context-menu.css"
|
||||||
|
|
||||||
const isDarkMode = () => window.matchMedia("(prefers-color-scheme: dark)").matches
|
const isDarkMode = () => window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
@@ -42,7 +43,7 @@ export function Header(props: { zen?: boolean }) {
|
|||||||
notation: "compact",
|
notation: "compact",
|
||||||
compactDisplay: "short",
|
compactDisplay: "short",
|
||||||
}).format(githubData()?.stars!)
|
}).format(githubData()?.stars!)
|
||||||
: "29K",
|
: config.github.starsFormatted.compact,
|
||||||
)
|
)
|
||||||
|
|
||||||
const [store, setStore] = createStore({
|
const [store, setStore] = createStore({
|
||||||
@@ -148,7 +149,7 @@ export function Header(props: { zen?: boolean }) {
|
|||||||
<nav data-component="nav-desktop">
|
<nav data-component="nav-desktop">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/sst/opencode" target="_blank">
|
<a href={config.github.repoUrl} target="_blank">
|
||||||
GitHub <span>[{starCount()}]</span>
|
GitHub <span>[{starCount()}]</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -222,7 +223,7 @@ export function Header(props: { zen?: boolean }) {
|
|||||||
<A href="/">Home</A>
|
<A href="/">Home</A>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/sst/opencode" target="_blank">
|
<a href={config.github.repoUrl} target="_blank">
|
||||||
GitHub <span>[{starCount()}]</span>
|
GitHub <span>[{starCount()}]</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -63,4 +63,4 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Application-wide constants and configuration
|
||||||
|
*/
|
||||||
|
export const config = {
|
||||||
|
// Base URL
|
||||||
|
baseUrl: "https://opencode.ai",
|
||||||
|
|
||||||
|
// GitHub
|
||||||
|
github: {
|
||||||
|
repoUrl: "https://github.com/sst/opencode",
|
||||||
|
starsFormatted: {
|
||||||
|
compact: "30K",
|
||||||
|
full: "30,000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Social links
|
||||||
|
social: {
|
||||||
|
twitter: "https://x.com/opencode",
|
||||||
|
discord: "https://discord.gg/opencode",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Static stats (used on landing page)
|
||||||
|
stats: {
|
||||||
|
contributors: "250",
|
||||||
|
commits: "3,500",
|
||||||
|
monthlyUsers: "300,000",
|
||||||
|
},
|
||||||
|
} as const
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { query } from "@solidjs/router"
|
import { query } from "@solidjs/router"
|
||||||
|
import { config } from "~/config"
|
||||||
|
|
||||||
export const github = query(async () => {
|
export const github = query(async () => {
|
||||||
"use server"
|
"use server"
|
||||||
@@ -6,11 +7,12 @@ export const github = query(async () => {
|
|||||||
"User-Agent":
|
"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",
|
"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/")
|
||||||
try {
|
try {
|
||||||
const [meta, releases, contributors] = await Promise.all([
|
const [meta, releases, contributors] = await Promise.all([
|
||||||
fetch("https://api.github.com/repos/sst/opencode", { headers }).then((res) => res.json()),
|
fetch(apiBaseUrl, { headers }).then((res) => res.json()),
|
||||||
fetch("https://api.github.com/repos/sst/opencode/releases", { headers }).then((res) => res.json()),
|
fetch(`${apiBaseUrl}/releases`, { headers }).then((res) => res.json()),
|
||||||
fetch("https://api.github.com/repos/sst/opencode/contributors?per_page=1", { headers }),
|
fetch(`${apiBaseUrl}/contributors?per_page=1`, { headers }),
|
||||||
])
|
])
|
||||||
const [release] = releases
|
const [release] = releases
|
||||||
const contributorCount = Number.parseInt(
|
const contributorCount = Number.parseInt(
|
||||||
|
|||||||
@@ -264,7 +264,7 @@
|
|||||||
[data-component="brand-content"] {
|
[data-component="brand-content"] {
|
||||||
padding: 4rem 5rem;
|
padding: 4rem 5rem;
|
||||||
|
|
||||||
h2 {
|
h1 {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--color-text-strong);
|
color: var(--color-text-strong);
|
||||||
@@ -299,7 +299,6 @@
|
|||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
|
|
||||||
&:hover:not(:disabled) {
|
&:hover:not(:disabled) {
|
||||||
background: var(--color-background-strong-hover);
|
background: var(--color-background-strong-hover);
|
||||||
}
|
}
|
||||||
@@ -385,23 +384,21 @@
|
|||||||
0 1px 2px -1px rgba(19, 16, 16, 0.12);
|
0 1px 2px -1px rgba(19, 16, 16, 0.12);
|
||||||
|
|
||||||
@media (max-width: 40rem) {
|
@media (max-width: 40rem) {
|
||||||
box-shadow:
|
box-shadow: 0 0 0 1px rgba(19, 16, 16, 0.16);
|
||||||
0 0 0 1px rgba(19, 16, 16, 0.16)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--color-background);
|
background: var(--color-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
transform: scale(0.98);
|
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) {
|
@media (max-width: 60rem) {
|
||||||
padding: 2rem 1.5rem;
|
padding: 2rem 1.5rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import "./index.css"
|
import "./index.css"
|
||||||
import { Title, Meta } from "@solidjs/meta"
|
import { Title, Meta, Link } from "@solidjs/meta"
|
||||||
import { Header } from "~/component/header"
|
import { Header } from "~/component/header"
|
||||||
|
import { config } from "~/config"
|
||||||
import { Footer } from "~/component/footer"
|
import { Footer } from "~/component/footer"
|
||||||
import { Legal } from "~/component/legal"
|
import { Legal } from "~/component/legal"
|
||||||
import previewLogoLight from "../../asset/brand/preview-opencode-logo-light.png"
|
import previewLogoLight from "../../asset/brand/preview-opencode-logo-light.png"
|
||||||
@@ -53,26 +54,21 @@ export default function Brand() {
|
|||||||
return (
|
return (
|
||||||
<main data-page="enterprise">
|
<main data-page="enterprise">
|
||||||
<Title>OpenCode | Brand</Title>
|
<Title>OpenCode | Brand</Title>
|
||||||
|
<Link rel="canonical" href={`${config.baseUrl}/brand`} />
|
||||||
<Meta name="description" content="OpenCode brand guidelines" />
|
<Meta name="description" content="OpenCode brand guidelines" />
|
||||||
<div data-component="container">
|
<div data-component="container">
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<div data-component="content">
|
<div data-component="content">
|
||||||
<section data-component="brand-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>
|
<p>Resources and assets to help you work with the OpenCode brand.</p>
|
||||||
<button
|
<button
|
||||||
data-component="download-button"
|
data-component="download-button"
|
||||||
onClick={() => downloadFile(brandAssets, "opencode-brand-assets.zip")}
|
onClick={() => downloadFile(brandAssets, "opencode-brand-assets.zip")}
|
||||||
>
|
>
|
||||||
Download all assets
|
Download all assets
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -88,13 +84,7 @@ export default function Brand() {
|
|||||||
<div data-component="actions">
|
<div data-component="actions">
|
||||||
<button onClick={() => downloadFile(logoLightPng, "opencode-logo-light.png")}>
|
<button onClick={() => downloadFile(logoLightPng, "opencode-logo-light.png")}>
|
||||||
PNG
|
PNG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -105,13 +95,7 @@ export default function Brand() {
|
|||||||
</button>
|
</button>
|
||||||
<button onClick={() => downloadFile(logoLightSvg, "opencode-logo-light.svg")}>
|
<button onClick={() => downloadFile(logoLightSvg, "opencode-logo-light.svg")}>
|
||||||
SVG
|
SVG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -127,13 +111,7 @@ export default function Brand() {
|
|||||||
<div data-component="actions">
|
<div data-component="actions">
|
||||||
<button onClick={() => downloadFile(logoDarkPng, "opencode-logo-dark.png")}>
|
<button onClick={() => downloadFile(logoDarkPng, "opencode-logo-dark.png")}>
|
||||||
PNG
|
PNG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -144,13 +122,7 @@ export default function Brand() {
|
|||||||
</button>
|
</button>
|
||||||
<button onClick={() => downloadFile(logoDarkSvg, "opencode-logo-dark.svg")}>
|
<button onClick={() => downloadFile(logoDarkSvg, "opencode-logo-dark.svg")}>
|
||||||
SVG
|
SVG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -164,17 +136,9 @@ export default function Brand() {
|
|||||||
<div>
|
<div>
|
||||||
<img src={previewWordmarkLight} alt="OpenCode brand guidelines" />
|
<img src={previewWordmarkLight} alt="OpenCode brand guidelines" />
|
||||||
<div data-component="actions">
|
<div data-component="actions">
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkLightPng, "opencode-wordmark-light.png")}>
|
||||||
onClick={() => downloadFile(wordmarkLightPng, "opencode-wordmark-light.png")}
|
|
||||||
>
|
|
||||||
PNG
|
PNG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -183,17 +147,9 @@ export default function Brand() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkLightSvg, "opencode-wordmark-light.svg")}>
|
||||||
onClick={() => downloadFile(wordmarkLightSvg, "opencode-wordmark-light.svg")}
|
|
||||||
>
|
|
||||||
SVG
|
SVG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -207,17 +163,9 @@ export default function Brand() {
|
|||||||
<div>
|
<div>
|
||||||
<img src={previewWordmarkDark} alt="OpenCode brand guidelines" />
|
<img src={previewWordmarkDark} alt="OpenCode brand guidelines" />
|
||||||
<div data-component="actions">
|
<div data-component="actions">
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkDarkPng, "opencode-wordmark-dark.png")}>
|
||||||
onClick={() => downloadFile(wordmarkDarkPng, "opencode-wordmark-dark.png")}
|
|
||||||
>
|
|
||||||
PNG
|
PNG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -226,17 +174,9 @@ export default function Brand() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkDarkSvg, "opencode-wordmark-dark.svg")}>
|
||||||
onClick={() => downloadFile(wordmarkDarkSvg, "opencode-wordmark-dark.svg")}
|
|
||||||
>
|
|
||||||
SVG
|
SVG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -250,19 +190,9 @@ export default function Brand() {
|
|||||||
<div>
|
<div>
|
||||||
<img src={previewWordmarkSimpleLight} alt="OpenCode brand guidelines" />
|
<img src={previewWordmarkSimpleLight} alt="OpenCode brand guidelines" />
|
||||||
<div data-component="actions">
|
<div data-component="actions">
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkSimpleLightPng, "opencode-wordmark-simple-light.png")}>
|
||||||
onClick={() =>
|
|
||||||
downloadFile(wordmarkSimpleLightPng, "opencode-wordmark-simple-light.png")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
PNG
|
PNG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -271,19 +201,9 @@ export default function Brand() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkSimpleLightSvg, "opencode-wordmark-simple-light.svg")}>
|
||||||
onClick={() =>
|
|
||||||
downloadFile(wordmarkSimpleLightSvg, "opencode-wordmark-simple-light.svg")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
SVG
|
SVG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -297,19 +217,9 @@ export default function Brand() {
|
|||||||
<div>
|
<div>
|
||||||
<img src={previewWordmarkSimpleDark} alt="OpenCode brand guidelines" />
|
<img src={previewWordmarkSimpleDark} alt="OpenCode brand guidelines" />
|
||||||
<div data-component="actions">
|
<div data-component="actions">
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkSimpleDarkPng, "opencode-wordmark-simple-dark.png")}>
|
||||||
onClick={() =>
|
|
||||||
downloadFile(wordmarkSimpleDarkPng, "opencode-wordmark-simple-dark.png")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
PNG
|
PNG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -318,19 +228,9 @@ export default function Brand() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button onClick={() => downloadFile(wordmarkSimpleDarkSvg, "opencode-wordmark-simple-dark.svg")}>
|
||||||
onClick={() =>
|
|
||||||
downloadFile(wordmarkSimpleDarkSvg, "opencode-wordmark-simple-dark.svg")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
SVG
|
SVG
|
||||||
<svg
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
d="M13.9583 10.6247L10 14.583L6.04167 10.6247M10 2.08301V13.958M16.25 17.9163H3.75"
|
||||||
stroke="currentColor"
|
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"] {
|
[data-component="enterprise-column-1"] {
|
||||||
h2 {
|
h1 {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--color-text-strong);
|
color: var(--color-text-strong);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import "./index.css"
|
import "./index.css"
|
||||||
import { Title, Meta } from "@solidjs/meta"
|
import { Title, Meta, Link } from "@solidjs/meta"
|
||||||
import { createSignal, Show } from "solid-js"
|
import { createSignal, Show } from "solid-js"
|
||||||
|
import { config } from "~/config"
|
||||||
import { Header } from "~/component/header"
|
import { Header } from "~/component/header"
|
||||||
import { Footer } from "~/component/footer"
|
import { Footer } from "~/component/footer"
|
||||||
import { Legal } from "~/component/legal"
|
import { Legal } from "~/component/legal"
|
||||||
@@ -54,6 +55,7 @@ export default function Enterprise() {
|
|||||||
return (
|
return (
|
||||||
<main data-page="enterprise">
|
<main data-page="enterprise">
|
||||||
<Title>OpenCode | Enterprise solutions for your organisation</Title>
|
<Title>OpenCode | Enterprise solutions for your organisation</Title>
|
||||||
|
<Link rel="canonical" href={`${config.baseUrl}/enterprise`} />
|
||||||
<Meta name="description" content="Contact OpenCode for enterprise solutions" />
|
<Meta name="description" content="Contact OpenCode for enterprise solutions" />
|
||||||
<div data-component="container">
|
<div data-component="container">
|
||||||
<Header />
|
<Header />
|
||||||
@@ -62,41 +64,28 @@ export default function Enterprise() {
|
|||||||
<section data-component="enterprise-content">
|
<section data-component="enterprise-content">
|
||||||
<div data-component="enterprise-columns">
|
<div data-component="enterprise-columns">
|
||||||
<div data-component="enterprise-column-1">
|
<div data-component="enterprise-column-1">
|
||||||
<h2>Your code is yours</h2>
|
<h1>Your code is yours</h1>
|
||||||
<p>
|
<p>
|
||||||
OpenCode operates securely inside your organization with no data or context stored
|
OpenCode operates securely inside your organization with no data or context stored and no licensing
|
||||||
and no licensing restrictions or ownership claims. Start a trial with your team,
|
restrictions or ownership claims. Start a trial with your team, then deploy it across your
|
||||||
then deploy it across your organization by integrating it with your SSO and
|
organization by integrating it with your SSO and internal AI gateway.
|
||||||
internal AI gateway.
|
|
||||||
</p>
|
</p>
|
||||||
<p>Let us know and how we can help.</p>
|
<p>Let us know and how we can help.</p>
|
||||||
|
|
||||||
<Show when={false}>
|
<Show when={false}>
|
||||||
<div data-component="testimonial">
|
<div data-component="testimonial">
|
||||||
<div data-component="quotation">
|
<div data-component="quotation">
|
||||||
<svg
|
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="20"
|
|
||||||
height="17"
|
|
||||||
viewBox="0 0 20 17"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M19.4118 0L16.5882 9.20833H20V17H12.2353V10.0938L16 0H19.4118ZM7.17647 0L4.35294 9.20833H7.76471V17H0V10.0938L3.76471 0H7.17647Z"
|
d="M19.4118 0L16.5882 9.20833H20V17H12.2353V10.0938L16 0H19.4118ZM7.17647 0L4.35294 9.20833H7.76471V17H0V10.0938L3.76471 0H7.17647Z"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
Thanks to OpenCode, we found a way to create software to track all our assets —
|
Thanks to OpenCode, we found a way to create software to track all our assets — even the imaginary
|
||||||
even the imaginary ones.
|
ones.
|
||||||
<div data-component="testimonial-logo">
|
<div data-component="testimonial-logo">
|
||||||
<svg
|
<svg width="80" height="79" viewBox="0 0 80 79" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="80"
|
|
||||||
height="79"
|
|
||||||
viewBox="0 0 80 79"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fill-rule="evenodd"
|
||||||
clip-rule="evenodd"
|
clip-rule="evenodd"
|
||||||
@@ -213,11 +202,7 @@ export default function Enterprise() {
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{showSuccess() && (
|
{showSuccess() && <div data-component="success-message">Message sent, we'll be in touch soon.</div>}
|
||||||
<div data-component="success-message">
|
|
||||||
Message sent, we'll be in touch soon.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -230,31 +215,29 @@ export default function Enterprise() {
|
|||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<Faq question="What is OpenCode Enterprise?">
|
<Faq question="What is OpenCode Enterprise?">
|
||||||
OpenCode Enterprise is for organizations that want to ensure that their code and
|
OpenCode Enterprise is for organizations that want to ensure that their code and data never leaves
|
||||||
data never leaves their infrastructure. It can do this by using a centralized
|
their infrastructure. It can do this by using a centralized config that integrates with your SSO and
|
||||||
config that integrates with your SSO and internal AI gateway.
|
internal AI gateway.
|
||||||
</Faq>
|
</Faq>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Faq question="How do I get started with OpenCode Enterprise?">
|
<Faq question="How do I get started with OpenCode Enterprise?">
|
||||||
Simply start with an internal trial with your team. OpenCode by default does not
|
Simply start with an internal trial with your team. OpenCode by default does not store your code or
|
||||||
store your code or context data, making it easy to get started. Then contact us to
|
context data, making it easy to get started. Then contact us to discuss pricing and implementation
|
||||||
discuss pricing and implementation options.
|
options.
|
||||||
</Faq>
|
</Faq>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Faq question="How does enterprise pricing work?">
|
<Faq question="How does enterprise pricing work?">
|
||||||
We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not
|
We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not charge for tokens
|
||||||
charge for tokens used. For further details, contact us for a custom quote based
|
used. For further details, contact us for a custom quote based on your organization's needs.
|
||||||
on your organization's needs.
|
|
||||||
</Faq>
|
</Faq>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Faq question="Is my data secure with OpenCode Enterprise?">
|
<Faq question="Is my data secure with OpenCode Enterprise?">
|
||||||
Yes. OpenCode does not store your code or context data. All processing happens
|
Yes. OpenCode does not store your code or context data. All processing happens locally or through
|
||||||
locally or through direct API calls to your AI provider. With central config and
|
direct API calls to your AI provider. With central config and SSO integration, your data remains
|
||||||
SSO integration, your data remains secure within your organization's
|
secure within your organization's infrastructure.
|
||||||
infrastructure.
|
|
||||||
</Faq>
|
</Faq>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ body {
|
|||||||
border-bottom: 1px solid var(--color-border-weak);
|
border-bottom: 1px solid var(--color-border-weak);
|
||||||
}
|
}
|
||||||
|
|
||||||
strong {
|
h1 {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: var(--color-text-strong);
|
color: var(--color-text-strong);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { Footer } from "~/component/footer"
|
|||||||
import { Legal } from "~/component/legal"
|
import { Legal } from "~/component/legal"
|
||||||
import { github } from "~/lib/github"
|
import { github } from "~/lib/github"
|
||||||
import { createMemo } from "solid-js"
|
import { createMemo } from "solid-js"
|
||||||
|
import { config } from "~/config"
|
||||||
|
|
||||||
function CopyStatus() {
|
function CopyStatus() {
|
||||||
return (
|
return (
|
||||||
@@ -43,6 +44,7 @@ export default function Home() {
|
|||||||
<main data-page="opencode">
|
<main data-page="opencode">
|
||||||
<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
|
<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
|
||||||
<Title>OpenCode | The AI coding agent built for the terminal</Title>
|
<Title>OpenCode | The AI coding agent built for the terminal</Title>
|
||||||
|
<Link rel="canonical" href={config.baseUrl} />
|
||||||
<Link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<Link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<Meta property="og:image" content="/social-share.png" />
|
<Meta property="og:image" content="/social-share.png" />
|
||||||
<Meta name="twitter:image" content="/social-share.png" />
|
<Meta name="twitter:image" content="/social-share.png" />
|
||||||
@@ -52,14 +54,10 @@ export default function Home() {
|
|||||||
<div data-component="content">
|
<div data-component="content">
|
||||||
<section data-component="hero">
|
<section data-component="hero">
|
||||||
<div data-slot="hero-copy">
|
<div data-slot="hero-copy">
|
||||||
<a
|
<a data-slot="releases" href={release()?.url ?? `${config.github.repoUrl}/releases`} target="_blank">
|
||||||
data-slot="releases"
|
|
||||||
href={release()?.url ?? "https://github.com/sst/opencode/releases"}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
What’s new in {release()?.name ?? "the latest release"}
|
What’s new in {release()?.name ?? "the latest release"}
|
||||||
</a>
|
</a>
|
||||||
<strong>The AI coding agent built for the terminal</strong>
|
<h1>The AI coding agent built for the terminal</h1>
|
||||||
<p>
|
<p>
|
||||||
OpenCode is fully open source, giving you control and freedom to use any provider, any model, and any
|
OpenCode is fully open source, giving you control and freedom to use any provider, any model, and any
|
||||||
editor.
|
editor.
|
||||||
@@ -219,9 +217,10 @@ export default function Home() {
|
|||||||
<div>
|
<div>
|
||||||
<span>[*]</span>
|
<span>[*]</span>
|
||||||
<p>
|
<p>
|
||||||
With over <strong>29,000</strong> GitHub stars, <strong>230</strong> contributors, and almost{" "}
|
With over <strong>{config.github.starsFormatted.full}</strong> GitHub stars,{" "}
|
||||||
<strong>3,500</strong> commits, OpenCode is used and trusted by over <strong>250,000</strong>{" "}
|
<strong>{config.stats.contributors}</strong> contributors, and almost{" "}
|
||||||
developers every month.
|
<strong>{config.stats.commits}</strong> commits, OpenCode is used and trusted by over{" "}
|
||||||
|
<strong>{config.stats.monthlyUsers}</strong> developers every month.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -274,7 +273,7 @@ export default function Home() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
<figure>Fig 1.</figure> <strong>29K</strong> GitHub Stars
|
<figure>Fig 1.</figure> <strong>{config.github.starsFormatted.compact}</strong> GitHub Stars
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -577,7 +576,7 @@ export default function Home() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
<figure>Fig 2.</figure> <strong>230</strong> Contributors
|
<figure>Fig 2.</figure> <strong>{config.stats.contributors}</strong> Contributors
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -619,7 +618,7 @@ export default function Home() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
<figure>Fig 3.</figure> <strong>250K</strong> Monthly Devs
|
<figure>Fig 3.</figure> <strong>{config.stats.monthlyUsers}</strong> Monthly Devs
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -688,11 +687,11 @@ export default function Home() {
|
|||||||
<li>
|
<li>
|
||||||
<Faq question="Is OpenCode open source?">
|
<Faq question="Is OpenCode open source?">
|
||||||
Yes, OpenCode is fully open source. The source code is public on{" "}
|
Yes, OpenCode is fully open source. The source code is public on{" "}
|
||||||
<a href="https://github.com/sst/opencode" target="_blank">
|
<a href={config.github.repoUrl} target="_blank">
|
||||||
GitHub
|
GitHub
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
under the{" "}
|
under the{" "}
|
||||||
<a href="https://github.com/sst/opencode?tab=MIT-1-ov-file#readme" target="_blank">
|
<a href={`${config.github.repoUrl}?tab=MIT-1-ov-file#readme`} target="_blank">
|
||||||
MIT License
|
MIT License
|
||||||
</a>
|
</a>
|
||||||
, meaning anyone can use, modify, or contribute to its development. Anyone from the community can file
|
, meaning anyone can use, modify, or contribute to its development. Anyone from the community can file
|
||||||
|
|||||||
@@ -13,146 +13,144 @@ export async function POST(input: APIEvent) {
|
|||||||
input.request.headers.get("stripe-signature")!,
|
input.request.headers.get("stripe-signature")!,
|
||||||
Resource.STRIPE_WEBHOOK_SECRET.value,
|
Resource.STRIPE_WEBHOOK_SECRET.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(body.type, JSON.stringify(body, null, 2))
|
console.log(body.type, JSON.stringify(body, null, 2))
|
||||||
if (body.type === "customer.updated") {
|
|
||||||
// check default payment method changed
|
|
||||||
const prevInvoiceSettings = body.data.previous_attributes?.invoice_settings ?? {}
|
|
||||||
if (!("default_payment_method" in prevInvoiceSettings)) return
|
|
||||||
|
|
||||||
const customerID = body.data.object.id
|
return (async () => {
|
||||||
const paymentMethodID = body.data.object.invoice_settings.default_payment_method as string
|
if (body.type === "customer.updated") {
|
||||||
|
// check default payment method changed
|
||||||
|
const prevInvoiceSettings = body.data.previous_attributes?.invoice_settings ?? {}
|
||||||
|
if (!("default_payment_method" in prevInvoiceSettings)) return "ignored"
|
||||||
|
|
||||||
if (!customerID) throw new Error("Customer ID not found")
|
const customerID = body.data.object.id
|
||||||
if (!paymentMethodID) throw new Error("Payment method ID not found")
|
const paymentMethodID = body.data.object.invoice_settings.default_payment_method as string
|
||||||
|
|
||||||
const paymentMethod = await Billing.stripe().paymentMethods.retrieve(paymentMethodID)
|
if (!customerID) throw new Error("Customer ID not found")
|
||||||
await Database.use(async (tx) => {
|
if (!paymentMethodID) throw new Error("Payment method ID not found")
|
||||||
await tx
|
|
||||||
.update(BillingTable)
|
|
||||||
.set({
|
|
||||||
paymentMethodID,
|
|
||||||
paymentMethodLast4: paymentMethod.card?.last4 ?? null,
|
|
||||||
paymentMethodType: paymentMethod.type,
|
|
||||||
})
|
|
||||||
.where(eq(BillingTable.customerID, customerID))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (body.type === "checkout.session.completed") {
|
|
||||||
const workspaceID = body.data.object.metadata?.workspaceID
|
|
||||||
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
|
|
||||||
const amount = body.data.object.amount_total
|
|
||||||
|
|
||||||
if (!workspaceID) throw new Error("Workspace ID not found")
|
const paymentMethod = await Billing.stripe().paymentMethods.retrieve(paymentMethodID)
|
||||||
if (!customerID) throw new Error("Customer ID not found")
|
await Database.use(async (tx) => {
|
||||||
if (!amount) throw new Error("Amount not found")
|
|
||||||
if (!paymentID) throw new Error("Payment ID not found")
|
|
||||||
if (!invoiceID) throw new Error("Invoice ID not found")
|
|
||||||
|
|
||||||
await Actor.provide("system", { workspaceID }, async () => {
|
|
||||||
const customer = await Billing.get()
|
|
||||||
if (customer?.customerID && customer.customerID !== customerID)
|
|
||||||
throw new Error("Customer ID mismatch")
|
|
||||||
|
|
||||||
// set customer metadata
|
|
||||||
if (!customer?.customerID) {
|
|
||||||
await Billing.stripe().customers.update(customerID, {
|
|
||||||
metadata: {
|
|
||||||
workspaceID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// get payment method for the payment intent
|
|
||||||
const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, {
|
|
||||||
expand: ["payment_method"],
|
|
||||||
})
|
|
||||||
const paymentMethod = paymentIntent.payment_method
|
|
||||||
if (!paymentMethod || typeof paymentMethod === "string")
|
|
||||||
throw new Error("Payment method not expanded")
|
|
||||||
|
|
||||||
const oldBillingInfo = await Database.use((tx) =>
|
|
||||||
tx
|
|
||||||
.select({
|
|
||||||
customerID: BillingTable.customerID,
|
|
||||||
})
|
|
||||||
.from(BillingTable)
|
|
||||||
.where(eq(BillingTable.workspaceID, workspaceID))
|
|
||||||
.then((rows) => rows[0]),
|
|
||||||
)
|
|
||||||
|
|
||||||
await Database.transaction(async (tx) => {
|
|
||||||
await tx
|
await tx
|
||||||
.update(BillingTable)
|
.update(BillingTable)
|
||||||
.set({
|
.set({
|
||||||
balance: sql`${BillingTable.balance} + ${centsToMicroCents(Billing.CHARGE_AMOUNT)}`,
|
paymentMethodID,
|
||||||
customerID,
|
|
||||||
paymentMethodID: paymentMethod.id,
|
|
||||||
paymentMethodLast4: paymentMethod.card?.last4 ?? null,
|
paymentMethodLast4: paymentMethod.card?.last4 ?? null,
|
||||||
paymentMethodType: paymentMethod.type,
|
paymentMethodType: paymentMethod.type,
|
||||||
// enable reload if first time enabling billing
|
|
||||||
...(oldBillingInfo?.customerID
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
reload: true,
|
|
||||||
reloadError: null,
|
|
||||||
timeReloadError: null,
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
.where(eq(BillingTable.workspaceID, workspaceID))
|
.where(eq(BillingTable.customerID, customerID))
|
||||||
await tx.insert(PaymentTable).values({
|
})
|
||||||
workspaceID,
|
}
|
||||||
id: Identifier.create("payment"),
|
if (body.type === "checkout.session.completed") {
|
||||||
amount: centsToMicroCents(Billing.CHARGE_AMOUNT),
|
const workspaceID = body.data.object.metadata?.workspaceID
|
||||||
paymentID,
|
const amountInCents = body.data.object.metadata?.amount && parseInt(body.data.object.metadata?.amount)
|
||||||
invoiceID,
|
const customerID = body.data.object.customer as string
|
||||||
customerID,
|
const paymentID = body.data.object.payment_intent as string
|
||||||
|
const invoiceID = body.data.object.invoice as string
|
||||||
|
|
||||||
|
if (!workspaceID) throw new Error("Workspace ID not found")
|
||||||
|
if (!customerID) throw new Error("Customer ID not found")
|
||||||
|
if (!amountInCents) throw new Error("Amount not found")
|
||||||
|
if (!paymentID) throw new Error("Payment ID not found")
|
||||||
|
if (!invoiceID) throw new Error("Invoice ID not found")
|
||||||
|
|
||||||
|
await Actor.provide("system", { workspaceID }, async () => {
|
||||||
|
const customer = await Billing.get()
|
||||||
|
if (customer?.customerID && customer.customerID !== customerID) throw new Error("Customer ID mismatch")
|
||||||
|
|
||||||
|
// set customer metadata
|
||||||
|
if (!customer?.customerID) {
|
||||||
|
await Billing.stripe().customers.update(customerID, {
|
||||||
|
metadata: {
|
||||||
|
workspaceID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// get payment method for the payment intent
|
||||||
|
const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, {
|
||||||
|
expand: ["payment_method"],
|
||||||
|
})
|
||||||
|
const paymentMethod = paymentIntent.payment_method
|
||||||
|
if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded")
|
||||||
|
|
||||||
|
await Database.transaction(async (tx) => {
|
||||||
|
await tx
|
||||||
|
.update(BillingTable)
|
||||||
|
.set({
|
||||||
|
balance: sql`${BillingTable.balance} + ${centsToMicroCents(amountInCents)}`,
|
||||||
|
customerID,
|
||||||
|
paymentMethodID: paymentMethod.id,
|
||||||
|
paymentMethodLast4: paymentMethod.card?.last4 ?? null,
|
||||||
|
paymentMethodType: paymentMethod.type,
|
||||||
|
// enable reload if first time enabling billing
|
||||||
|
...(customer?.customerID
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
reload: true,
|
||||||
|
reloadError: null,
|
||||||
|
timeReloadError: null,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.where(eq(BillingTable.workspaceID, workspaceID))
|
||||||
|
await tx.insert(PaymentTable).values({
|
||||||
|
workspaceID,
|
||||||
|
id: Identifier.create("payment"),
|
||||||
|
amount: centsToMicroCents(amountInCents),
|
||||||
|
paymentID,
|
||||||
|
invoiceID,
|
||||||
|
customerID,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
if (body.type === "charge.refunded") {
|
||||||
|
const customerID = body.data.object.customer as string
|
||||||
|
const paymentIntentID = body.data.object.payment_intent as string
|
||||||
|
if (!customerID) throw new Error("Customer ID not found")
|
||||||
|
if (!paymentIntentID) throw new Error("Payment ID not found")
|
||||||
|
|
||||||
|
const workspaceID = await Database.use((tx) =>
|
||||||
|
tx
|
||||||
|
.select({
|
||||||
|
workspaceID: BillingTable.workspaceID,
|
||||||
|
})
|
||||||
|
.from(BillingTable)
|
||||||
|
.where(eq(BillingTable.customerID, customerID))
|
||||||
|
.then((rows) => rows[0]?.workspaceID),
|
||||||
|
)
|
||||||
|
if (!workspaceID) throw new Error("Workspace ID not found")
|
||||||
|
|
||||||
|
const amount = await Database.use((tx) =>
|
||||||
|
tx
|
||||||
|
.select({
|
||||||
|
amount: PaymentTable.amount,
|
||||||
|
})
|
||||||
|
.from(PaymentTable)
|
||||||
|
.where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID)))
|
||||||
|
.then((rows) => rows[0]?.amount),
|
||||||
|
)
|
||||||
|
if (!amount) throw new Error("Payment not found")
|
||||||
|
|
||||||
|
await Database.transaction(async (tx) => {
|
||||||
|
await tx
|
||||||
|
.update(PaymentTable)
|
||||||
|
.set({
|
||||||
|
timeRefunded: new Date(body.created * 1000),
|
||||||
|
})
|
||||||
|
.where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID)))
|
||||||
|
|
||||||
|
await tx
|
||||||
|
.update(BillingTable)
|
||||||
|
.set({
|
||||||
|
balance: sql`${BillingTable.balance} - ${amount}`,
|
||||||
|
})
|
||||||
|
.where(eq(BillingTable.workspaceID, workspaceID))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
.then((message) => {
|
||||||
|
return Response.json({ message: message ?? "done" }, { status: 200 })
|
||||||
})
|
})
|
||||||
}
|
.catch((error: any) => {
|
||||||
if (body.type === "charge.refunded") {
|
return Response.json({ message: error.message }, { status: 500 })
|
||||||
const customerID = body.data.object.customer as string
|
|
||||||
const paymentIntentID = body.data.object.payment_intent as string
|
|
||||||
if (!customerID) throw new Error("Customer ID not found")
|
|
||||||
if (!paymentIntentID) throw new Error("Payment ID not found")
|
|
||||||
|
|
||||||
const workspaceID = await Database.use((tx) =>
|
|
||||||
tx
|
|
||||||
.select({
|
|
||||||
workspaceID: BillingTable.workspaceID,
|
|
||||||
})
|
|
||||||
.from(BillingTable)
|
|
||||||
.where(eq(BillingTable.customerID, customerID))
|
|
||||||
.then((rows) => rows[0]?.workspaceID),
|
|
||||||
)
|
|
||||||
if (!workspaceID) throw new Error("Workspace ID not found")
|
|
||||||
|
|
||||||
await Database.transaction(async (tx) => {
|
|
||||||
await tx
|
|
||||||
.update(PaymentTable)
|
|
||||||
.set({
|
|
||||||
timeRefunded: new Date(body.created * 1000),
|
|
||||||
})
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(PaymentTable.paymentID, paymentIntentID),
|
|
||||||
eq(PaymentTable.workspaceID, workspaceID),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
await tx
|
|
||||||
.update(BillingTable)
|
|
||||||
.set({
|
|
||||||
balance: sql`${BillingTable.balance} - ${centsToMicroCents(Billing.CHARGE_AMOUNT)}`,
|
|
||||||
})
|
|
||||||
.where(eq(BillingTable.workspaceID, workspaceID))
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
console.log("finished handling")
|
|
||||||
|
|
||||||
return Response.json("ok", { status: 200 })
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export default function Home() {
|
|||||||
<h3 data-component="title">homebrew</h3>
|
<h3 data-component="title">homebrew</h3>
|
||||||
<button data-copy data-slot="button">
|
<button data-copy data-slot="button">
|
||||||
<span>
|
<span>
|
||||||
brew install <strong>sst/tap/opencode</strong>
|
brew install <strong>opencode</strong>
|
||||||
</span>
|
</span>
|
||||||
<CopyStatus />
|
<CopyStatus />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -14,4 +14,4 @@
|
|||||||
color: var(--color-danger);
|
color: var(--color-danger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,4 +71,4 @@
|
|||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,4 +104,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const getUserEmail = query(async (workspaceID: string) => {
|
|||||||
|
|
||||||
export default function WorkspaceLayout(props: RouteSectionProps) {
|
export default function WorkspaceLayout(props: RouteSectionProps) {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const userEmail = createAsync(() => getUserEmail(params.id))
|
const userEmail = createAsync(() => getUserEmail(params.id!))
|
||||||
return (
|
return (
|
||||||
<main data-page="workspace">
|
<main data-page="workspace">
|
||||||
<Link rel="icon" type="image/svg+xml" href="/favicon-zen.svg" />
|
<Link rel="icon" type="image/svg+xml" href="/favicon-zen.svg" />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import "./[id].css"
|
|||||||
|
|
||||||
export default function WorkspaceLayout(props: RouteSectionProps) {
|
export default function WorkspaceLayout(props: RouteSectionProps) {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const userInfo = createAsync(() => querySessionInfo(params.id))
|
const userInfo = createAsync(() => querySessionInfo(params.id!))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main data-page="workspace">
|
<main data-page="workspace">
|
||||||
|
|||||||
@@ -71,6 +71,57 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-slot="add-balance-form-container"] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="add-balance-form"] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-3);
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[data-component="input"] {
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
color: var(--color-text);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
box-shadow: 0 0 0 3px var(--color-accent-alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="form-actions"] {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="form-error"] {
|
||||||
|
color: var(--color-danger);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
[data-slot="credit-card"] {
|
[data-slot="credit-card"] {
|
||||||
padding: var(--space-2) var(--space-4);
|
padding: var(--space-2) var(--space-4);
|
||||||
background-color: var(--color-bg-surface);
|
background-color: var(--color-bg-surface);
|
||||||
@@ -131,4 +182,4 @@
|
|||||||
padding: var(--space-4);
|
padding: var(--space-4);
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,86 @@
|
|||||||
import { action, useParams, useAction, createAsync, useSubmission } from "@solidjs/router"
|
import { action, useParams, useAction, createAsync, useSubmission, json } from "@solidjs/router"
|
||||||
import { createMemo, Match, Show, Switch } from "solid-js"
|
import { createMemo, Match, Show, Switch, createEffect } from "solid-js"
|
||||||
|
import { createStore } from "solid-js/store"
|
||||||
import { Billing } from "@opencode-ai/console-core/billing.js"
|
import { Billing } from "@opencode-ai/console-core/billing.js"
|
||||||
import { withActor } from "~/context/auth.withActor"
|
import { withActor } from "~/context/auth.withActor"
|
||||||
import { IconCreditCard, IconStripe } from "~/component/icon"
|
import { IconCreditCard, IconStripe } from "~/component/icon"
|
||||||
import styles from "./billing-section.module.css"
|
import styles from "./billing-section.module.css"
|
||||||
import { createCheckoutUrl, queryBillingInfo } from "../../common"
|
import { createCheckoutUrl, formatBalance, queryBillingInfo } from "../../common"
|
||||||
|
|
||||||
const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => {
|
const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => {
|
||||||
"use server"
|
"use server"
|
||||||
return withActor(() => Billing.generateSessionUrl({ returnUrl }), workspaceID)
|
return json(
|
||||||
|
await withActor(
|
||||||
|
() =>
|
||||||
|
Billing.generateSessionUrl({ returnUrl })
|
||||||
|
.then((data) => ({ error: undefined, data }))
|
||||||
|
.catch((e) => ({
|
||||||
|
error: e.message as string,
|
||||||
|
data: undefined,
|
||||||
|
})),
|
||||||
|
workspaceID,
|
||||||
|
),
|
||||||
|
{ revalidate: queryBillingInfo.key },
|
||||||
|
)
|
||||||
}, "sessionUrl")
|
}, "sessionUrl")
|
||||||
|
|
||||||
export function BillingSection() {
|
export function BillingSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
// ORIGINAL CODE - COMMENTED OUT FOR TESTING
|
// ORIGINAL CODE - COMMENTED OUT FOR TESTING
|
||||||
const balanceInfo = createAsync(() => queryBillingInfo(params.id))
|
const billingInfo = createAsync(() => queryBillingInfo(params.id!))
|
||||||
const createCheckoutUrlAction = useAction(createCheckoutUrl)
|
const checkoutAction = useAction(createCheckoutUrl)
|
||||||
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
|
const checkoutSubmission = useSubmission(createCheckoutUrl)
|
||||||
const createSessionUrlAction = useAction(createSessionUrl)
|
const sessionAction = useAction(createSessionUrl)
|
||||||
const createSessionUrlSubmission = useSubmission(createSessionUrl)
|
const sessionSubmission = useSubmission(createSessionUrl)
|
||||||
|
const [store, setStore] = createStore({
|
||||||
|
showAddBalanceForm: false,
|
||||||
|
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() {
|
||||||
|
const amount = parseInt(store.addBalanceAmount)
|
||||||
|
const baseUrl = window.location.href
|
||||||
|
|
||||||
|
const checkout = await checkoutAction(params.id!, amount, baseUrl, baseUrl)
|
||||||
|
if (checkout && checkout.data) {
|
||||||
|
setStore("checkoutRedirecting", true)
|
||||||
|
window.location.href = checkout.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onClickSession() {
|
||||||
|
const baseUrl = window.location.href
|
||||||
|
const sessionUrl = await sessionAction(params.id!, baseUrl)
|
||||||
|
if (sessionUrl && sessionUrl.data) {
|
||||||
|
setStore("sessionRedirecting", true)
|
||||||
|
window.location.href = sessionUrl.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAddBalanceForm() {
|
||||||
|
while (true) {
|
||||||
|
checkoutSubmission.clear()
|
||||||
|
if (!checkoutSubmission.result) break
|
||||||
|
}
|
||||||
|
setStore({
|
||||||
|
showAddBalanceForm: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideAddBalanceForm() {
|
||||||
|
setStore("showAddBalanceForm", false)
|
||||||
|
checkoutSubmission.clear()
|
||||||
|
}
|
||||||
|
|
||||||
// DUMMY DATA FOR TESTING - UNCOMMENT ONE OF THE SCENARIOS BELOW
|
// DUMMY DATA FOR TESTING - UNCOMMENT ONE OF THE SCENARIOS BELOW
|
||||||
|
|
||||||
@@ -72,97 +134,104 @@ export function BillingSection() {
|
|||||||
// timeReloadError: null as Date | null
|
// timeReloadError: null as Date | null
|
||||||
// })
|
// })
|
||||||
|
|
||||||
const balanceAmount = createMemo(() => {
|
|
||||||
return ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section class={styles.root}>
|
<section class={styles.root}>
|
||||||
<div data-slot="section-title">
|
<div data-slot="section-title">
|
||||||
<h2>Billing</h2>
|
<h2>Billing</h2>
|
||||||
<p>
|
<p>
|
||||||
Manage payments methods. <a href="mailto:contact@anoma.ly">Contact us</a> if you have any
|
Manage payments methods. <a href="mailto:contact@anoma.ly">Contact us</a> if you have any questions.
|
||||||
questions.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div data-slot="section-content">
|
<div data-slot="section-content">
|
||||||
<div data-slot="balance-display">
|
<div data-slot="balance-display">
|
||||||
<div data-slot="balance-amount">
|
<div data-slot="balance-amount">
|
||||||
<span data-slot="balance-value">
|
<span data-slot="balance-value">${balance()}</span>
|
||||||
${balanceAmount() === "-0.00" ? "0.00" : balanceAmount()}
|
|
||||||
</span>
|
|
||||||
<span data-slot="balance-label">Current Balance</span>
|
<span data-slot="balance-label">Current Balance</span>
|
||||||
</div>
|
</div>
|
||||||
<Show when={balanceInfo()?.customerID}>
|
<Show when={billingInfo()?.customerID}>
|
||||||
<div data-slot="balance-right-section">
|
<div data-slot="balance-right-section">
|
||||||
<button
|
<Show
|
||||||
data-color="primary"
|
when={!store.showAddBalanceForm}
|
||||||
disabled={createCheckoutUrlSubmission.pending}
|
fallback={
|
||||||
onClick={async () => {
|
<div data-slot="add-balance-form-container">
|
||||||
const baseUrl = window.location.href
|
<div data-slot="add-balance-form">
|
||||||
const checkoutUrl = await createCheckoutUrlAction(params.id, baseUrl, baseUrl)
|
<label>Add $</label>
|
||||||
if (checkoutUrl) {
|
<input
|
||||||
window.location.href = checkoutUrl
|
data-component="input"
|
||||||
}
|
type="number"
|
||||||
}}
|
min={billingInfo()?.reloadAmountMin.toString()}
|
||||||
|
step="1"
|
||||||
|
value={store.addBalanceAmount}
|
||||||
|
onInput={(e) => {
|
||||||
|
setStore("addBalanceAmount", e.currentTarget.value)
|
||||||
|
checkoutSubmission.clear()
|
||||||
|
}}
|
||||||
|
placeholder="Enter amount"
|
||||||
|
/>
|
||||||
|
<div data-slot="form-actions">
|
||||||
|
<button data-color="ghost" type="button" onClick={() => hideAddBalanceForm()}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
data-color="primary"
|
||||||
|
type="button"
|
||||||
|
disabled={!store.addBalanceAmount || checkoutSubmission.pending || store.checkoutRedirecting}
|
||||||
|
onClick={onClickCheckout}
|
||||||
|
>
|
||||||
|
{checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Add"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Show when={checkoutSubmission.result && (checkoutSubmission.result as any).error}>
|
||||||
|
{(err: any) => <div data-slot="form-error">{err()}</div>}
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{createCheckoutUrlSubmission.pending ? "Loading..." : "Add Balance"}
|
<button data-color="primary" onClick={() => showAddBalanceForm()}>
|
||||||
</button>
|
Add Balance
|
||||||
|
</button>
|
||||||
|
</Show>
|
||||||
<div data-slot="credit-card">
|
<div data-slot="credit-card">
|
||||||
<div data-slot="card-icon">
|
<div data-slot="card-icon">
|
||||||
<Switch fallback={<IconCreditCard style={{ width: "24px", height: "24px" }} />}>
|
<Switch fallback={<IconCreditCard style={{ width: "24px", height: "24px" }} />}>
|
||||||
<Match when={balanceInfo()?.paymentMethodType === "link"}>
|
<Match when={billingInfo()?.paymentMethodType === "link"}>
|
||||||
<IconStripe style={{ width: "24px", height: "24px" }} />
|
<IconStripe style={{ width: "24px", height: "24px" }} />
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
<div data-slot="card-details">
|
<div data-slot="card-details">
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={balanceInfo()?.paymentMethodType === "card"}>
|
<Match when={billingInfo()?.paymentMethodType === "card"}>
|
||||||
<Show
|
<Show when={billingInfo()?.paymentMethodLast4} fallback={<span data-slot="number">----</span>}>
|
||||||
when={balanceInfo()?.paymentMethodLast4}
|
|
||||||
fallback={<span data-slot="number">----</span>}
|
|
||||||
>
|
|
||||||
<span data-slot="secret">••••</span>
|
<span data-slot="secret">••••</span>
|
||||||
<span data-slot="number">{balanceInfo()?.paymentMethodLast4}</span>
|
<span data-slot="number">{billingInfo()?.paymentMethodLast4}</span>
|
||||||
</Show>
|
</Show>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={balanceInfo()?.paymentMethodType === "link"}>
|
<Match when={billingInfo()?.paymentMethodType === "link"}>
|
||||||
<span data-slot="type">Linked to Stripe</span>
|
<span data-slot="type">Linked to Stripe</span>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
data-color="ghost"
|
data-color="ghost"
|
||||||
disabled={createSessionUrlSubmission.pending}
|
disabled={sessionSubmission.pending || store.sessionRedirecting}
|
||||||
onClick={async () => {
|
onClick={onClickSession}
|
||||||
const baseUrl = window.location.href
|
|
||||||
const sessionUrl = await createSessionUrlAction(params.id, baseUrl)
|
|
||||||
if (sessionUrl) {
|
|
||||||
window.location.href = sessionUrl
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{createSessionUrlSubmission.pending ? "Loading..." : "Manage"}
|
{sessionSubmission.pending || store.sessionRedirecting ? "Loading..." : "Manage"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Show when={!balanceInfo()?.customerID}>
|
<Show when={!billingInfo()?.customerID}>
|
||||||
<button
|
<button
|
||||||
data-slot="enable-billing-button"
|
data-slot="enable-billing-button"
|
||||||
data-color="primary"
|
data-color="primary"
|
||||||
disabled={createCheckoutUrlSubmission.pending}
|
disabled={checkoutSubmission.pending || store.checkoutRedirecting}
|
||||||
onClick={async () => {
|
onClick={onClickCheckout}
|
||||||
const baseUrl = window.location.href
|
|
||||||
const checkoutUrl = await createCheckoutUrlAction(params.id, baseUrl, baseUrl)
|
|
||||||
if (checkoutUrl) {
|
|
||||||
window.location.href = checkoutUrl
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{createCheckoutUrlSubmission.pending ? "Loading..." : "Enable Billing"}
|
{checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Enable Billing"}
|
||||||
</button>
|
</button>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { queryBillingInfo, querySessionInfo } from "../../common"
|
|||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const userInfo = createAsync(() => querySessionInfo(params.id))
|
const userInfo = createAsync(() => querySessionInfo(params.id!))
|
||||||
const billingInfo = createAsync(() => queryBillingInfo(params.id))
|
const billingInfo = createAsync(() => queryBillingInfo(params.id!))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-page="workspace-[id]">
|
<div data-page="workspace-[id]">
|
||||||
|
|||||||
+1
-1
@@ -93,4 +93,4 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router"
|
import { json, action, useParams, createAsync, useSubmission } from "@solidjs/router"
|
||||||
import { createEffect, Show } from "solid-js"
|
import { createEffect, Show } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { withActor } from "~/context/auth.withActor"
|
import { withActor } from "~/context/auth.withActor"
|
||||||
import { Billing } from "@opencode-ai/console-core/billing.js"
|
import { Billing } from "@opencode-ai/console-core/billing.js"
|
||||||
import styles from "./monthly-limit-section.module.css"
|
import styles from "./monthly-limit-section.module.css"
|
||||||
|
import { queryBillingInfo } from "../../common"
|
||||||
const getBillingInfo = query(async (workspaceID: string) => {
|
|
||||||
"use server"
|
|
||||||
return withActor(async () => {
|
|
||||||
return await Billing.get()
|
|
||||||
}, workspaceID)
|
|
||||||
}, "billing.get")
|
|
||||||
|
|
||||||
const setMonthlyLimit = action(async (form: FormData) => {
|
const setMonthlyLimit = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
@@ -28,7 +22,7 @@ const setMonthlyLimit = action(async (form: FormData) => {
|
|||||||
.catch((e) => ({ error: e.message as string })),
|
.catch((e) => ({ error: e.message as string })),
|
||||||
workspaceID,
|
workspaceID,
|
||||||
),
|
),
|
||||||
{ revalidate: getBillingInfo.key },
|
{ revalidate: queryBillingInfo.key },
|
||||||
)
|
)
|
||||||
}, "billing.setMonthlyLimit")
|
}, "billing.setMonthlyLimit")
|
||||||
|
|
||||||
@@ -36,7 +30,7 @@ export function MonthlyLimitSection() {
|
|||||||
const params = useParams()
|
const params = useParams()
|
||||||
const submission = useSubmission(setMonthlyLimit)
|
const submission = useSubmission(setMonthlyLimit)
|
||||||
const [store, setStore] = createStore({ show: false })
|
const [store, setStore] = createStore({ show: false })
|
||||||
const balanceInfo = createAsync(() => getBillingInfo(params.id))
|
const billingInfo = createAsync(() => queryBillingInfo(params.id!))
|
||||||
|
|
||||||
let input: HTMLInputElement
|
let input: HTMLInputElement
|
||||||
|
|
||||||
@@ -68,13 +62,13 @@ export function MonthlyLimitSection() {
|
|||||||
<section class={styles.root}>
|
<section class={styles.root}>
|
||||||
<div data-slot="section-title">
|
<div data-slot="section-title">
|
||||||
<h2>Monthly Limit</h2>
|
<h2>Monthly Limit</h2>
|
||||||
<p>Set a monthly spending limit for your account.</p>
|
<p>Set a monthly usage limit for your account.</p>
|
||||||
</div>
|
</div>
|
||||||
<div data-slot="section-content">
|
<div data-slot="section-content">
|
||||||
<div data-slot="balance">
|
<div data-slot="balance">
|
||||||
<div data-slot="amount">
|
<div data-slot="amount">
|
||||||
{balanceInfo()?.monthlyLimit ? <span data-slot="currency">$</span> : null}
|
{billingInfo()?.monthlyLimit ? <span data-slot="currency">$</span> : null}
|
||||||
<span data-slot="value">{balanceInfo()?.monthlyLimit ?? "-"}</span>
|
<span data-slot="value">{billingInfo()?.monthlyLimit ?? "-"}</span>
|
||||||
</div>
|
</div>
|
||||||
<Show
|
<Show
|
||||||
when={!store.show}
|
when={!store.show}
|
||||||
@@ -106,15 +100,15 @@ export function MonthlyLimitSection() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<button data-color="primary" onClick={() => show()}>
|
<button data-color="primary" onClick={() => show()}>
|
||||||
{balanceInfo()?.monthlyLimit ? "Edit Limit" : "Set Limit"}
|
{billingInfo()?.monthlyLimit ? "Edit Limit" : "Set Limit"}
|
||||||
</button>
|
</button>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Show when={balanceInfo()?.monthlyLimit} fallback={<p data-slot="usage-status">No spending limit set.</p>}>
|
<Show when={billingInfo()?.monthlyLimit} fallback={<p data-slot="usage-status">No usage limit set.</p>}>
|
||||||
<p data-slot="usage-status">
|
<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 = balanceInfo()?.timeMonthlyUsageUpdated
|
const dateLastUsed = billingInfo()?.timeMonthlyUsageUpdated
|
||||||
if (!dateLastUsed) return "0"
|
if (!dateLastUsed) return "0"
|
||||||
|
|
||||||
const current = new Date().toLocaleDateString("en-US", {
|
const current = new Date().toLocaleDateString("en-US", {
|
||||||
@@ -128,7 +122,7 @@ export function MonthlyLimitSection() {
|
|||||||
timeZone: "UTC",
|
timeZone: "UTC",
|
||||||
})
|
})
|
||||||
if (current !== lastUsed) return "0"
|
if (current !== lastUsed) return "0"
|
||||||
return ((balanceInfo()?.monthlyUsage ?? 0) / 100000000).toFixed(2)
|
return ((billingInfo()?.monthlyUsage ?? 0) / 100000000).toFixed(2)
|
||||||
})()}
|
})()}
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const downloadReceipt = action(async (workspaceID: string, paymentID: string) =>
|
|||||||
|
|
||||||
export function PaymentSection() {
|
export function PaymentSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const payments = createAsync(() => getPaymentsInfo(params.id))
|
const payments = createAsync(() => getPaymentsInfo(params.id!))
|
||||||
const downloadReceiptAction = useAction(downloadReceipt)
|
const downloadReceiptAction = useAction(downloadReceipt)
|
||||||
|
|
||||||
// DUMMY DATA FOR TESTING
|
// DUMMY DATA FOR TESTING
|
||||||
@@ -89,7 +89,7 @@ export function PaymentSection() {
|
|||||||
<td data-slot="payment-receipt">
|
<td data-slot="payment-receipt">
|
||||||
<button
|
<button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const receiptUrl = await downloadReceiptAction(params.id, payment.paymentID!)
|
const receiptUrl = await downloadReceiptAction(params.id!, payment.paymentID!)
|
||||||
if (receiptUrl) {
|
if (receiptUrl) {
|
||||||
window.open(receiptUrl, "_blank")
|
window.open(receiptUrl, "_blank")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,206 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-slot="create-form"] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
padding: var(--space-4);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
margin-top: var(--space-4);
|
||||||
|
|
||||||
|
[data-slot="form-field"] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="field-label"] {
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="toggle-container"] {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[data-component="input"] {
|
||||||
|
flex: 1;
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
color: var(--color-text);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="input-row"] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--space-3);
|
||||||
|
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="input-field"] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-1);
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 1.2;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[data-component="input"] {
|
||||||
|
flex: 1;
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
color: var(--color-text);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
line-height: 1.5;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
box-shadow: 0 0 0 3px var(--color-accent-alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: var(--color-bg-surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="field-with-connector"] {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
|
||||||
|
[data-slot="field-connector"] {
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[data-component="input"] {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="form-actions"] {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-2);
|
||||||
|
margin-top: var(--space-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="form-error"] {
|
||||||
|
color: var(--color-danger);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-top: calc(var(--space-1) * -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="model-toggle-label"] {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: #ccc;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 0.125rem;
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + span {
|
||||||
|
background-color: #21ad0e;
|
||||||
|
border-color: #148605;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
transform: translateX(1rem) translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover span {
|
||||||
|
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked:hover + span {
|
||||||
|
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(input:disabled) {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:disabled + span {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[data-slot="reload-error"] {
|
[data-slot="reload-error"] {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -54,7 +254,8 @@
|
|||||||
gap: var(--space-2);
|
gap: var(--space-2);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router"
|
import { json, action, useParams, createAsync, useSubmission } from "@solidjs/router"
|
||||||
import { Show } from "solid-js"
|
import { createEffect, Show } from "solid-js"
|
||||||
|
import { createStore } from "solid-js/store"
|
||||||
import { withActor } from "~/context/auth.withActor"
|
import { withActor } from "~/context/auth.withActor"
|
||||||
import { Billing } from "@opencode-ai/console-core/billing.js"
|
import { Billing } from "@opencode-ai/console-core/billing.js"
|
||||||
import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js"
|
import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js"
|
||||||
import { BillingTable } from "@opencode-ai/console-core/schema/billing.sql.js"
|
import { BillingTable } from "@opencode-ai/console-core/schema/billing.sql.js"
|
||||||
import styles from "./reload-section.module.css"
|
import styles from "./reload-section.module.css"
|
||||||
|
import { queryBillingInfo } from "../../common"
|
||||||
|
|
||||||
const reload = action(async (form: FormData) => {
|
const reload = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const workspaceID = form.get("workspaceID")?.toString()
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: "Workspace ID is required" }
|
if (!workspaceID) return { error: "Workspace ID is required" }
|
||||||
return json(await withActor(() => Billing.reload(), workspaceID), {
|
return json(await withActor(() => Billing.reload(), workspaceID), {
|
||||||
revalidate: getBillingInfo.key,
|
revalidate: queryBillingInfo.key,
|
||||||
})
|
})
|
||||||
}, "billing.reload")
|
}, "billing.reload")
|
||||||
|
|
||||||
@@ -20,12 +22,27 @@ const setReload = action(async (form: FormData) => {
|
|||||||
const workspaceID = form.get("workspaceID")?.toString()
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: "Workspace ID is required" }
|
if (!workspaceID) return { error: "Workspace ID is required" }
|
||||||
const reloadValue = form.get("reload")?.toString() === "true"
|
const reloadValue = form.get("reload")?.toString() === "true"
|
||||||
|
const amountStr = form.get("reloadAmount")?.toString()
|
||||||
|
const triggerStr = form.get("reloadTrigger")?.toString()
|
||||||
|
|
||||||
|
const reloadAmount = amountStr && amountStr.trim() !== "" ? parseInt(amountStr) : null
|
||||||
|
const reloadTrigger = triggerStr && triggerStr.trim() !== "" ? parseInt(triggerStr) : null
|
||||||
|
|
||||||
|
if (reloadValue) {
|
||||||
|
if (reloadAmount === null || reloadAmount < Billing.RELOAD_AMOUNT_MIN)
|
||||||
|
return { error: `Reload amount must be at least $${Billing.RELOAD_AMOUNT_MIN}` }
|
||||||
|
if (reloadTrigger === null || reloadTrigger < Billing.RELOAD_TRIGGER_MIN)
|
||||||
|
return { error: `Balance trigger must be at least $${Billing.RELOAD_TRIGGER_MIN}` }
|
||||||
|
}
|
||||||
|
|
||||||
return json(
|
return json(
|
||||||
await Database.use((tx) =>
|
await Database.use((tx) =>
|
||||||
tx
|
tx
|
||||||
.update(BillingTable)
|
.update(BillingTable)
|
||||||
.set({
|
.set({
|
||||||
reload: reloadValue,
|
reload: reloadValue,
|
||||||
|
...(reloadAmount !== null ? { reloadAmount } : {}),
|
||||||
|
...(reloadTrigger !== null ? { reloadTrigger } : {}),
|
||||||
...(reloadValue
|
...(reloadValue
|
||||||
? {
|
? {
|
||||||
reloadError: null,
|
reloadError: null,
|
||||||
@@ -35,22 +52,43 @@ const setReload = action(async (form: FormData) => {
|
|||||||
})
|
})
|
||||||
.where(eq(BillingTable.workspaceID, workspaceID)),
|
.where(eq(BillingTable.workspaceID, workspaceID)),
|
||||||
),
|
),
|
||||||
{ revalidate: getBillingInfo.key },
|
{ revalidate: queryBillingInfo.key },
|
||||||
)
|
)
|
||||||
}, "billing.setReload")
|
}, "billing.setReload")
|
||||||
|
|
||||||
const getBillingInfo = query(async (workspaceID: string) => {
|
|
||||||
"use server"
|
|
||||||
return withActor(async () => {
|
|
||||||
return await Billing.get()
|
|
||||||
}, workspaceID)
|
|
||||||
}, "billing.get")
|
|
||||||
|
|
||||||
export function ReloadSection() {
|
export function ReloadSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const balanceInfo = createAsync(() => getBillingInfo(params.id))
|
const billingInfo = createAsync(() => queryBillingInfo(params.id!))
|
||||||
const setReloadSubmission = useSubmission(setReload)
|
const setReloadSubmission = useSubmission(setReload)
|
||||||
const reloadSubmission = useSubmission(reload)
|
const reloadSubmission = useSubmission(reload)
|
||||||
|
const [store, setStore] = createStore({
|
||||||
|
show: false,
|
||||||
|
reload: false,
|
||||||
|
reloadAmount: "",
|
||||||
|
reloadTrigger: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (!setReloadSubmission.pending && setReloadSubmission.result && !(setReloadSubmission.result as any).error) {
|
||||||
|
setStore("show", false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
while (true) {
|
||||||
|
setReloadSubmission.clear()
|
||||||
|
if (!setReloadSubmission.result) break
|
||||||
|
}
|
||||||
|
const info = billingInfo()!
|
||||||
|
setStore("show", true)
|
||||||
|
setStore("reload", info.reload ? true : true)
|
||||||
|
setStore("reloadAmount", info.reloadAmount.toString())
|
||||||
|
setStore("reloadTrigger", info.reloadTrigger.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
setStore("show", false)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section class={styles.root}>
|
<section class={styles.root}>
|
||||||
@@ -58,44 +96,102 @@ export function ReloadSection() {
|
|||||||
<h2>Auto Reload</h2>
|
<h2>Auto Reload</h2>
|
||||||
<div data-slot="title-row">
|
<div data-slot="title-row">
|
||||||
<Show
|
<Show
|
||||||
when={balanceInfo()?.reload}
|
when={billingInfo()?.reload}
|
||||||
fallback={
|
fallback={
|
||||||
<p>Auto reload is disabled. Enable to automatically reload when balance is low.</p>
|
<p>
|
||||||
|
Auto reload is <b>disabled</b>. Enable to automatically reload when balance is low.
|
||||||
|
</p>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
We'll automatically reload <b>$20</b> (+$1.23 processing fee) when it reaches{" "}
|
Auto reload is <b>enabled</b>. We'll reload <b>${billingInfo()?.reloadAmount}</b> (+$1.23 processing fee)
|
||||||
<b>$5</b>.
|
when balance reaches <b>${billingInfo()?.reloadTrigger}</b>.
|
||||||
</p>
|
</p>
|
||||||
</Show>
|
</Show>
|
||||||
<form action={setReload} method="post" data-slot="create-form">
|
<button data-color="primary" type="button" onClick={() => show()}>
|
||||||
<input type="hidden" name="workspaceID" value={params.id} />
|
{billingInfo()?.reload ? "Edit" : "Enable"}
|
||||||
<input type="hidden" name="reload" value={balanceInfo()?.reload ? "false" : "true"} />
|
</button>
|
||||||
<button data-color="primary" type="submit" disabled={setReloadSubmission.pending}>
|
|
||||||
<Show
|
|
||||||
when={balanceInfo()?.reload}
|
|
||||||
fallback={setReloadSubmission.pending ? "Enabling..." : "Enable"}
|
|
||||||
>
|
|
||||||
{setReloadSubmission.pending ? "Disabling..." : "Disable"}
|
|
||||||
</Show>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div data-slot="section-content">
|
<Show when={store.show}>
|
||||||
<Show when={balanceInfo()?.reload && balanceInfo()?.reloadError}>
|
<form action={setReload} method="post" data-slot="create-form">
|
||||||
|
<div data-slot="form-field">
|
||||||
|
<label>
|
||||||
|
<span data-slot="field-label">Enable Auto Reload</span>
|
||||||
|
<div data-slot="toggle-container">
|
||||||
|
<label data-slot="model-toggle-label">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="reload"
|
||||||
|
value="true"
|
||||||
|
checked={store.reload}
|
||||||
|
onChange={(e) => setStore("reload", e.currentTarget.checked)}
|
||||||
|
/>
|
||||||
|
<span></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-slot="input-row">
|
||||||
|
<div data-slot="input-field">
|
||||||
|
<p>Reload $</p>
|
||||||
|
<input
|
||||||
|
data-component="input"
|
||||||
|
name="reloadAmount"
|
||||||
|
type="number"
|
||||||
|
min={billingInfo()?.reloadAmountMin.toString()}
|
||||||
|
step="1"
|
||||||
|
value={store.reloadAmount}
|
||||||
|
onInput={(e) => setStore("reloadAmount", e.currentTarget.value)}
|
||||||
|
placeholder={billingInfo()?.reloadAmount.toString()}
|
||||||
|
disabled={!store.reload}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div data-slot="input-field">
|
||||||
|
<p>When balance reaches $</p>
|
||||||
|
<input
|
||||||
|
data-component="input"
|
||||||
|
name="reloadTrigger"
|
||||||
|
type="number"
|
||||||
|
min={billingInfo()?.reloadTriggerMin.toString()}
|
||||||
|
step="1"
|
||||||
|
value={store.reloadTrigger}
|
||||||
|
onInput={(e) => setStore("reloadTrigger", e.currentTarget.value)}
|
||||||
|
placeholder={billingInfo()?.reloadTrigger.toString()}
|
||||||
|
disabled={!store.reload}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={setReloadSubmission.result && (setReloadSubmission.result as any).error}>
|
||||||
|
{(err: any) => <div data-slot="form-error">{err()}</div>}
|
||||||
|
</Show>
|
||||||
|
<input type="hidden" name="workspaceID" value={params.id} />
|
||||||
|
<div data-slot="form-actions">
|
||||||
|
<button type="button" data-color="ghost" onClick={() => hide()}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button type="submit" data-color="primary" disabled={setReloadSubmission.pending}>
|
||||||
|
{setReloadSubmission.pending ? "Saving..." : "Save"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Show>
|
||||||
|
<Show when={billingInfo()?.reload && billingInfo()?.reloadError}>
|
||||||
|
<div data-slot="section-content">
|
||||||
<div data-slot="reload-error">
|
<div data-slot="reload-error">
|
||||||
<p>
|
<p>
|
||||||
Reload failed at{" "}
|
Reload failed at{" "}
|
||||||
{balanceInfo()?.timeReloadError!.toLocaleString("en-US", {
|
{billingInfo()?.timeReloadError!.toLocaleString("en-US", {
|
||||||
month: "short",
|
month: "short",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
hour: "numeric",
|
hour: "numeric",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
})}
|
})}
|
||||||
. Reason: {balanceInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment
|
. Reason: {billingInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment method and try
|
||||||
method and try again.
|
again.
|
||||||
</p>
|
</p>
|
||||||
<form action={reload} method="post" data-slot="create-form">
|
<form action={reload} method="post" data-slot="create-form">
|
||||||
<input type="hidden" name="workspaceID" value={params.id} />
|
<input type="hidden" name="workspaceID" value={params.id} />
|
||||||
@@ -104,8 +200,8 @@ export function ReloadSection() {
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</div>
|
||||||
</div>
|
</Show>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
|
import { Show, createMemo } from "solid-js"
|
||||||
|
import { createStore } from "solid-js/store"
|
||||||
|
import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router"
|
||||||
import { NewUserSection } from "./new-user-section"
|
import { NewUserSection } from "./new-user-section"
|
||||||
import { UsageSection } from "./usage-section"
|
import { UsageSection } from "./usage-section"
|
||||||
import { ModelSection } from "./model-section"
|
import { ModelSection } from "./model-section"
|
||||||
import { ProviderSection } from "./provider-section"
|
import { ProviderSection } from "./provider-section"
|
||||||
import { IconLogo } from "~/component/icon"
|
import { IconLogo } from "~/component/icon"
|
||||||
import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router"
|
import { querySessionInfo, queryBillingInfo, createCheckoutUrl, formatBalance } from "../common"
|
||||||
import { querySessionInfo, queryBillingInfo, createCheckoutUrl } from "../common"
|
|
||||||
import { Show, createMemo } from "solid-js"
|
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const userInfo = createAsync(() => querySessionInfo(params.id))
|
const userInfo = createAsync(() => querySessionInfo(params.id!))
|
||||||
const billingInfo = createAsync(() => queryBillingInfo(params.id))
|
const billingInfo = createAsync(() => queryBillingInfo(params.id!))
|
||||||
const createCheckoutUrlAction = useAction(createCheckoutUrl)
|
const checkoutAction = useAction(createCheckoutUrl)
|
||||||
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
|
const checkoutSubmission = useSubmission(createCheckoutUrl)
|
||||||
|
const [store, setStore] = createStore({
|
||||||
const balanceAmount = createMemo(() => {
|
checkoutRedirecting: false,
|
||||||
return ((billingInfo()?.balance ?? 0) / 100000000).toFixed(2)
|
|
||||||
})
|
})
|
||||||
|
const balance = createMemo(() => formatBalance(billingInfo()?.balance ?? 0))
|
||||||
|
|
||||||
|
async function onClickCheckout() {
|
||||||
|
const baseUrl = window.location.href
|
||||||
|
const checkout = await checkoutAction(params.id!, billingInfo()!.reloadAmount, baseUrl, baseUrl)
|
||||||
|
if (checkout && checkout.data) {
|
||||||
|
setStore("checkoutRedirecting", true)
|
||||||
|
window.location.href = checkout.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-page="workspace-[id]">
|
<div data-page="workspace-[id]">
|
||||||
@@ -38,21 +48,15 @@ export default function () {
|
|||||||
<button
|
<button
|
||||||
data-color="primary"
|
data-color="primary"
|
||||||
data-size="sm"
|
data-size="sm"
|
||||||
disabled={createCheckoutUrlSubmission.pending}
|
disabled={checkoutSubmission.pending || store.checkoutRedirecting}
|
||||||
onClick={async () => {
|
onClick={onClickCheckout}
|
||||||
const baseUrl = window.location.href
|
|
||||||
const checkoutUrl = await createCheckoutUrlAction(params.id, baseUrl, baseUrl)
|
|
||||||
if (checkoutUrl) {
|
|
||||||
window.location.href = checkoutUrl
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{createCheckoutUrlSubmission.pending ? "Loading..." : "Enable billing"}
|
{checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Enable billing"}
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span data-slot="balance">
|
<span data-slot="balance">
|
||||||
Current balance <b>${balanceAmount() === "-0.00" ? "0.00" : balanceAmount()}</b>
|
Current balance <b>${balance()}</b>
|
||||||
</span>
|
</span>
|
||||||
</Show>
|
</Show>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -171,7 +171,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 40rem) {
|
@media (max-width: 40rem) {
|
||||||
|
|
||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
padding: var(--space-2) var(--space-3);
|
padding: var(--space-2) var(--space-3);
|
||||||
@@ -181,8 +180,7 @@
|
|||||||
th {
|
th {
|
||||||
&:nth-child(3)
|
&:nth-child(3)
|
||||||
|
|
||||||
/* Date */
|
/* Date */ {
|
||||||
{
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,11 +188,10 @@
|
|||||||
td {
|
td {
|
||||||
&:nth-child(3)
|
&:nth-child(3)
|
||||||
|
|
||||||
/* Date */
|
/* Date */ {
|
||||||
{
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const listKeys = query(async (workspaceID: string) => {
|
|||||||
|
|
||||||
export function KeySection() {
|
export function KeySection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const keys = createAsync(() => listKeys(params.id))
|
const keys = createAsync(() => listKeys(params.id!))
|
||||||
const submission = useSubmission(createKey)
|
const submission = useSubmission(createKey)
|
||||||
const [store, setStore] = createStore({ show: false })
|
const [store, setStore] = createStore({ show: false })
|
||||||
|
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ const roleOptions = [
|
|||||||
|
|
||||||
export function MemberSection() {
|
export function MemberSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const data = createAsync(() => listMembers(params.id))
|
const data = createAsync(() => listMembers(params.id!))
|
||||||
const submission = useSubmission(inviteMember)
|
const submission = useSubmission(inviteMember)
|
||||||
const [store, setStore] = createStore({
|
const [store, setStore] = createStore({
|
||||||
show: false,
|
show: false,
|
||||||
@@ -328,7 +328,7 @@ export function MemberSection() {
|
|||||||
{(member) => (
|
{(member) => (
|
||||||
<MemberRow
|
<MemberRow
|
||||||
member={member}
|
member={member}
|
||||||
workspaceID={params.id}
|
workspaceID={params.id!}
|
||||||
actorID={data()!.actorID}
|
actorID={data()!.actorID}
|
||||||
actorRole={data()!.actorRole}
|
actorRole={data()!.actorRole}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -69,4 +69,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const getModelsInfo = query(async (workspaceID: string) => {
|
|||||||
return {
|
return {
|
||||||
all: Object.entries(ZenData.list().models)
|
all: Object.entries(ZenData.list().models)
|
||||||
.filter(([id, _model]) => !["claude-3-5-haiku"].includes(id))
|
.filter(([id, _model]) => !["claude-3-5-haiku"].includes(id))
|
||||||
.filter(([id, _model]) => !id.startsWith("an-"))
|
.filter(([id, _model]) => !id.startsWith("alpha-"))
|
||||||
.sort(([_idA, modelA], [_idB, modelB]) => modelA.name.localeCompare(modelB.name))
|
.sort(([_idA, modelA], [_idB, modelB]) => modelA.name.localeCompare(modelB.name))
|
||||||
.map(([id, model]) => ({ id, name: model.name })),
|
.map(([id, model]) => ({ id, name: model.name })),
|
||||||
disabled: await Model.listDisabled(),
|
disabled: await Model.listDisabled(),
|
||||||
@@ -52,8 +52,8 @@ const updateModel = action(async (form: FormData) => {
|
|||||||
|
|
||||||
export function ModelSection() {
|
export function ModelSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const modelsInfo = createAsync(() => getModelsInfo(params.id))
|
const modelsInfo = createAsync(() => getModelsInfo(params.id!))
|
||||||
const userInfo = createAsync(() => querySessionInfo(params.id))
|
const userInfo = createAsync(() => querySessionInfo(params.id!))
|
||||||
|
|
||||||
const modelsWithLab = createMemo(() => {
|
const modelsWithLab = createMemo(() => {
|
||||||
const info = modelsInfo()
|
const info = modelsInfo()
|
||||||
|
|||||||
@@ -140,4 +140,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ const listKeys = query(async (workspaceID: string) => {
|
|||||||
export function NewUserSection() {
|
export function NewUserSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const [copiedKey, setCopiedKey] = createSignal(false)
|
const [copiedKey, setCopiedKey] = createSignal(false)
|
||||||
const keys = createAsync(() => listKeys(params.id))
|
const keys = createAsync(() => listKeys(params.id!))
|
||||||
const usage = createAsync(() => getUsageInfo(params.id))
|
const usage = createAsync(() => getUsageInfo(params.id!))
|
||||||
const isNew = createMemo(() => {
|
const isNew = createMemo(() => {
|
||||||
const keysList = keys()
|
const keysList = keys()
|
||||||
const usageList = usage()
|
const usageList = usage()
|
||||||
|
|||||||
@@ -128,7 +128,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 40rem) {
|
@media (max-width: 40rem) {
|
||||||
|
|
||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
padding: var(--space-2) var(--space-3);
|
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" }
|
if (!provider) return { error: "Provider is required" }
|
||||||
const workspaceID = form.get("workspaceID")?.toString()
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: "Workspace ID is required" }
|
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")
|
}, "provider.remove")
|
||||||
|
|
||||||
const saveProvider = action(async (form: FormData) => {
|
const saveProvider = action(async (form: FormData) => {
|
||||||
@@ -52,7 +54,7 @@ const listProviders = query(async (workspaceID: string) => {
|
|||||||
|
|
||||||
function ProviderRow(props: { provider: Provider }) {
|
function ProviderRow(props: { provider: Provider }) {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const providers = createAsync(() => listProviders(params.id))
|
const providers = createAsync(() => listProviders(params.id!))
|
||||||
const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key)
|
const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key)
|
||||||
const removeSubmission = useSubmission(
|
const removeSubmission = useSubmission(
|
||||||
removeProvider,
|
removeProvider,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
>button {
|
> button {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
>button[type="reset"] {
|
> button[type="reset"] {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,4 +91,4 @@
|
|||||||
margin-top: calc(var(--space-1) * -1);
|
margin-top: calc(var(--space-1) * -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const updateWorkspace = action(async (form: FormData) => {
|
|||||||
|
|
||||||
export function SettingsSection() {
|
export function SettingsSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const workspaceInfo = createAsync(() => getWorkspaceInfo(params.id))
|
const workspaceInfo = createAsync(() => getWorkspaceInfo(params.id!))
|
||||||
const submission = useSubmission(updateWorkspace)
|
const submission = useSubmission(updateWorkspace)
|
||||||
const [store, setStore] = createStore({ show: false })
|
const [store, setStore] = createStore({ show: false })
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const getUsageInfo = query(async (workspaceID: string) => {
|
|||||||
export function UsageSection() {
|
export function UsageSection() {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
// ORIGINAL CODE - COMMENTED OUT FOR TESTING
|
// ORIGINAL CODE - COMMENTED OUT FOR TESTING
|
||||||
const usage = createAsync(() => getUsageInfo(params.id))
|
const usage = createAsync(() => getUsageInfo(params.id!))
|
||||||
|
|
||||||
// DUMMY DATA FOR TESTING
|
// DUMMY DATA FOR TESTING
|
||||||
// const usage = () => [
|
// const usage = () => [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Resource } from "@opencode-ai/console-resource"
|
import { Resource } from "@opencode-ai/console-resource"
|
||||||
import { Actor } from "@opencode-ai/console-core/actor.js"
|
import { Actor } from "@opencode-ai/console-core/actor.js"
|
||||||
import { action, query } from "@solidjs/router"
|
import { action, json, query } from "@solidjs/router"
|
||||||
import { withActor } from "~/context/auth.withActor"
|
import { withActor } from "~/context/auth.withActor"
|
||||||
import { Billing } from "@opencode-ai/console-core/billing.js"
|
import { Billing } from "@opencode-ai/console-core/billing.js"
|
||||||
import { User } from "@opencode-ai/console-core/user.js"
|
import { User } from "@opencode-ai/console-core/user.js"
|
||||||
@@ -34,6 +34,11 @@ export function formatDateUTC(date: Date) {
|
|||||||
return date.toLocaleDateString("en-US", options)
|
return date.toLocaleDateString("en-US", options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatBalance(amount: number) {
|
||||||
|
const balance = ((amount ?? 0) / 100000000).toFixed(2)
|
||||||
|
return balance === "-0.00" ? "0.00" : balance
|
||||||
|
}
|
||||||
|
|
||||||
export async function getLastSeenWorkspaceID() {
|
export async function getLastSeenWorkspaceID() {
|
||||||
"use server"
|
"use server"
|
||||||
return withActor(async () => {
|
return withActor(async () => {
|
||||||
@@ -62,23 +67,40 @@ export const querySessionInfo = query(async (workspaceID: string) => {
|
|||||||
return withActor(() => {
|
return withActor(() => {
|
||||||
return {
|
return {
|
||||||
isAdmin: Actor.userRole() === "admin",
|
isAdmin: Actor.userRole() === "admin",
|
||||||
isBeta:
|
isBeta: Resource.App.stage === "production" ? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y" : true,
|
||||||
Resource.App.stage === "production"
|
|
||||||
? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y"
|
|
||||||
: true,
|
|
||||||
}
|
}
|
||||||
}, workspaceID)
|
}, workspaceID)
|
||||||
}, "session.get")
|
}, "session.get")
|
||||||
|
|
||||||
export const createCheckoutUrl = action(
|
export const createCheckoutUrl = action(
|
||||||
async (workspaceID: string, successUrl: string, cancelUrl: string) => {
|
async (workspaceID: string, amount: number, successUrl: string, cancelUrl: string) => {
|
||||||
"use server"
|
"use server"
|
||||||
return withActor(() => Billing.generateCheckoutUrl({ successUrl, cancelUrl }), workspaceID)
|
return json(
|
||||||
|
await withActor(
|
||||||
|
() =>
|
||||||
|
Billing.generateCheckoutUrl({ amount, successUrl, cancelUrl })
|
||||||
|
.then((data) => ({ error: undefined, data }))
|
||||||
|
.catch((e) => ({
|
||||||
|
error: e.message as string,
|
||||||
|
data: undefined,
|
||||||
|
})),
|
||||||
|
workspaceID,
|
||||||
|
),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
"checkoutUrl",
|
"checkoutUrl",
|
||||||
)
|
)
|
||||||
|
|
||||||
export const queryBillingInfo = query(async (workspaceID: string) => {
|
export const queryBillingInfo = query(async (workspaceID: string) => {
|
||||||
"use server"
|
"use server"
|
||||||
return withActor(() => Billing.get(), workspaceID)
|
return withActor(async () => {
|
||||||
|
const billing = await Billing.get()
|
||||||
|
return {
|
||||||
|
...billing,
|
||||||
|
reloadAmount: billing.reloadAmount ?? Billing.RELOAD_AMOUNT,
|
||||||
|
reloadAmountMin: Billing.RELOAD_AMOUNT_MIN,
|
||||||
|
reloadTrigger: billing.reloadTrigger ?? Billing.RELOAD_TRIGGER,
|
||||||
|
reloadTriggerMin: Billing.RELOAD_TRIGGER_MIN,
|
||||||
|
}
|
||||||
|
}, workspaceID)
|
||||||
}, "billing.get")
|
}, "billing.get")
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ body {
|
|||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
strong {
|
h1 {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: var(--color-text-strong);
|
color: var(--color-text-strong);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { createAsync, query, redirect } from "@solidjs/router"
|
|||||||
import { Title, Meta, Link } from "@solidjs/meta"
|
import { Title, Meta, Link } from "@solidjs/meta"
|
||||||
import { HttpHeader } from "@solidjs/start"
|
import { HttpHeader } from "@solidjs/start"
|
||||||
import zenLogoLight from "../../asset/zen-ornate-light.svg"
|
import zenLogoLight from "../../asset/zen-ornate-light.svg"
|
||||||
|
import { config } from "~/config"
|
||||||
import zenLogoDark from "../../asset/zen-ornate-dark.svg"
|
import zenLogoDark from "../../asset/zen-ornate-dark.svg"
|
||||||
import compareVideo from "../../asset/lander/opencode-comparison-min.mp4"
|
import compareVideo from "../../asset/lander/opencode-comparison-min.mp4"
|
||||||
import compareVideoPoster from "../../asset/lander/opencode-comparison-poster.png"
|
import compareVideoPoster from "../../asset/lander/opencode-comparison-poster.png"
|
||||||
@@ -30,6 +31,7 @@ export default function Home() {
|
|||||||
<main data-page="zen">
|
<main data-page="zen">
|
||||||
<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
|
<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>
|
<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" />
|
<Link rel="icon" type="image/svg+xml" href="/favicon-zen.svg" />
|
||||||
<Meta property="og:image" content="/social-share-zen.png" />
|
<Meta property="og:image" content="/social-share-zen.png" />
|
||||||
<Meta name="twitter: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">
|
<div data-slot="hero-copy">
|
||||||
<img data-slot="zen logo light" src={zenLogoLight} alt="zen logo light" />
|
<img data-slot="zen logo light" src={zenLogoLight} alt="zen logo light" />
|
||||||
<img data-slot="zen logo dark" src={zenLogoDark} alt="zen logo dark" />
|
<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>
|
<p>
|
||||||
Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically
|
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
|
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 MonthlyLimitError extends Error {}
|
||||||
export class UserLimitError extends Error {}
|
export class UserLimitError extends Error {}
|
||||||
export class ModelError extends Error {}
|
export class ModelError extends Error {}
|
||||||
|
export class RateLimitError extends Error {}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export type Format = "anthropic" | "openai" | "oa-compat"
|
|
||||||
@@ -12,27 +12,31 @@ import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
|
|||||||
import { ModelTable } from "@opencode-ai/console-core/schema/model.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 { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js"
|
||||||
import { logger } from "./logger"
|
import { logger } from "./logger"
|
||||||
import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error"
|
import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError, RateLimitError } from "./error"
|
||||||
import {
|
import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider"
|
||||||
createBodyConverter,
|
|
||||||
createStreamPartConverter,
|
|
||||||
createResponseConverter,
|
|
||||||
} from "./provider/provider"
|
|
||||||
import { Format } from "./format"
|
|
||||||
import { anthropicHelper } from "./provider/anthropic"
|
import { anthropicHelper } from "./provider/anthropic"
|
||||||
import { openaiHelper } from "./provider/openai"
|
import { openaiHelper } from "./provider/openai"
|
||||||
import { oaCompatHelper } from "./provider/openai-compatible"
|
import { oaCompatHelper } from "./provider/openai-compatible"
|
||||||
|
import { createRateLimiter } from "./rateLimiter"
|
||||||
|
|
||||||
type ZenData = Awaited<ReturnType<typeof ZenData.list>>
|
type ZenData = Awaited<ReturnType<typeof ZenData.list>>
|
||||||
type Model = ZenData["models"][string]
|
type RetryOptions = {
|
||||||
|
excludeProviders: string[]
|
||||||
|
retryCount: number
|
||||||
|
}
|
||||||
|
|
||||||
export async function handler(
|
export async function handler(
|
||||||
input: APIEvent,
|
input: APIEvent,
|
||||||
opts: {
|
opts: {
|
||||||
format: Format
|
format: ZenData.Format
|
||||||
parseApiKey: (headers: Headers) => string | undefined
|
parseApiKey: (headers: Headers) => string | undefined
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
type AuthInfo = Awaited<ReturnType<typeof authenticate>>
|
||||||
|
type ModelInfo = Awaited<ReturnType<typeof validateModel>>
|
||||||
|
type ProviderInfo = Awaited<ReturnType<typeof selectProvider>>
|
||||||
|
|
||||||
|
const MAX_RETRIES = 3
|
||||||
const FREE_WORKSPACES = [
|
const FREE_WORKSPACES = [
|
||||||
"wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
|
"wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
|
||||||
"wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench
|
"wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench
|
||||||
@@ -40,6 +44,7 @@ export async function handler(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const body = await input.request.json()
|
const body = await input.request.json()
|
||||||
|
const ip = input.request.headers.get("x-real-ip") ?? ""
|
||||||
logger.metric({
|
logger.metric({
|
||||||
is_tream: !!body.stream,
|
is_tream: !!body.stream,
|
||||||
session: input.request.headers.get("x-opencode-session"),
|
session: input.request.headers.get("x-opencode-session"),
|
||||||
@@ -47,42 +52,56 @@ export async function handler(
|
|||||||
})
|
})
|
||||||
const zenData = ZenData.list()
|
const zenData = ZenData.list()
|
||||||
const modelInfo = validateModel(zenData, body.model)
|
const modelInfo = validateModel(zenData, body.model)
|
||||||
const providerInfo = selectProvider(
|
const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
|
||||||
zenData,
|
await rateLimiter?.check()
|
||||||
modelInfo,
|
|
||||||
input.request.headers.get("x-real-ip") ?? "",
|
|
||||||
)
|
|
||||||
const authInfo = await authenticate(modelInfo, providerInfo)
|
|
||||||
validateBilling(modelInfo, authInfo)
|
|
||||||
validateModelSettings(authInfo)
|
|
||||||
updateProviderKey(authInfo, providerInfo)
|
|
||||||
logger.metric({ provider: providerInfo.id })
|
|
||||||
|
|
||||||
// Request to model provider
|
const retriableRequest = async (retry: RetryOptions = { excludeProviders: [], retryCount: 0 }) => {
|
||||||
const startTimestamp = Date.now()
|
const providerInfo = selectProvider(zenData, modelInfo, ip, retry)
|
||||||
const reqUrl = providerInfo.modifyUrl(providerInfo.api)
|
const authInfo = await authenticate(modelInfo, providerInfo)
|
||||||
const reqBody = JSON.stringify(
|
validateBilling(authInfo, modelInfo)
|
||||||
providerInfo.modifyBody({
|
validateModelSettings(authInfo)
|
||||||
...createBodyConverter(opts.format, providerInfo.format)(body),
|
updateProviderKey(authInfo, providerInfo)
|
||||||
model: providerInfo.model,
|
logger.metric({ provider: providerInfo.id })
|
||||||
}),
|
|
||||||
)
|
const startTimestamp = Date.now()
|
||||||
logger.debug("REQUEST URL: " + reqUrl)
|
const reqUrl = providerInfo.modifyUrl(providerInfo.api)
|
||||||
logger.debug("REQUEST: " + reqBody)
|
const reqBody = JSON.stringify(
|
||||||
const res = await fetch(reqUrl, {
|
providerInfo.modifyBody({
|
||||||
method: "POST",
|
...createBodyConverter(opts.format, providerInfo.format)(body),
|
||||||
headers: (() => {
|
model: providerInfo.model,
|
||||||
const headers = input.request.headers
|
}),
|
||||||
headers.delete("host")
|
)
|
||||||
headers.delete("content-length")
|
logger.debug("REQUEST URL: " + reqUrl)
|
||||||
providerInfo.modifyHeaders(headers, body, providerInfo.apiKey)
|
logger.debug("REQUEST: " + reqBody.substring(0, 300) + "...")
|
||||||
Object.entries(providerInfo.headerMappings ?? {}).forEach(([k, v]) => {
|
const res = await fetch(reqUrl, {
|
||||||
headers.set(k, headers.get(v)!)
|
method: "POST",
|
||||||
|
headers: (() => {
|
||||||
|
const headers = new Headers(input.request.headers)
|
||||||
|
providerInfo.modifyHeaders(headers, body, providerInfo.apiKey)
|
||||||
|
Object.entries(providerInfo.headerMappings ?? {}).forEach(([k, v]) => {
|
||||||
|
headers.set(k, headers.get(v)!)
|
||||||
|
})
|
||||||
|
headers.delete("host")
|
||||||
|
headers.delete("content-length")
|
||||||
|
headers.delete("x-opencode-request")
|
||||||
|
headers.delete("x-opencode-session")
|
||||||
|
return headers
|
||||||
|
})(),
|
||||||
|
body: reqBody,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Try another provider => stop retrying if using fallback provider
|
||||||
|
if (res.status !== 200 && modelInfo.fallbackProvider && providerInfo.id !== modelInfo.fallbackProvider) {
|
||||||
|
return retriableRequest({
|
||||||
|
excludeProviders: [...retry.excludeProviders, providerInfo.id],
|
||||||
|
retryCount: retry.retryCount + 1,
|
||||||
})
|
})
|
||||||
return headers
|
}
|
||||||
})(),
|
|
||||||
body: reqBody,
|
return { providerInfo, authInfo, res, startTimestamp }
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const { providerInfo, authInfo, res, startTimestamp } = await retriableRequest()
|
||||||
|
|
||||||
// Scrub response headers
|
// Scrub response headers
|
||||||
const resHeaders = new Headers()
|
const resHeaders = new Headers()
|
||||||
@@ -93,9 +112,6 @@ export async function handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("STATUS: " + res.status + " " + res.statusText)
|
logger.debug("STATUS: " + res.status + " " + res.statusText)
|
||||||
if (res.status === 400 || res.status === 503) {
|
|
||||||
logger.debug("RESPONSE: " + (await res.text()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle non-streaming response
|
// Handle non-streaming response
|
||||||
if (!body.stream) {
|
if (!body.stream) {
|
||||||
@@ -104,6 +120,7 @@ export async function handler(
|
|||||||
const body = JSON.stringify(responseConverter(json))
|
const body = JSON.stringify(responseConverter(json))
|
||||||
logger.metric({ response_length: body.length })
|
logger.metric({ response_length: body.length })
|
||||||
logger.debug("RESPONSE: " + body)
|
logger.debug("RESPONSE: " + body)
|
||||||
|
await rateLimiter?.track()
|
||||||
await trackUsage(authInfo, modelInfo, providerInfo, json.usage)
|
await trackUsage(authInfo, modelInfo, providerInfo, json.usage)
|
||||||
await reload(authInfo)
|
await reload(authInfo)
|
||||||
return new Response(body, {
|
return new Response(body, {
|
||||||
@@ -132,6 +149,7 @@ export async function handler(
|
|||||||
response_length: responseLength,
|
response_length: responseLength,
|
||||||
"timestamp.last_byte": Date.now(),
|
"timestamp.last_byte": Date.now(),
|
||||||
})
|
})
|
||||||
|
await rateLimiter?.track()
|
||||||
const usage = usageParser.retrieve()
|
const usage = usageParser.retrieve()
|
||||||
if (usage) {
|
if (usage) {
|
||||||
await trackUsage(authInfo, modelInfo, providerInfo, usage)
|
await trackUsage(authInfo, modelInfo, providerInfo, usage)
|
||||||
@@ -206,6 +224,15 @@ export async function handler(
|
|||||||
{ status: 401 },
|
{ 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(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: "error",
|
type: "error",
|
||||||
@@ -230,42 +257,42 @@ export async function handler(
|
|||||||
return { id: modelId, ...modelData }
|
return { id: modelId, ...modelData }
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectProvider(
|
function selectProvider(zenData: ZenData, modelInfo: ModelInfo, ip: string, retry: RetryOptions) {
|
||||||
zenData: ZenData,
|
const provider = (() => {
|
||||||
model: Awaited<ReturnType<typeof validateModel>>,
|
if (retry.retryCount === MAX_RETRIES) {
|
||||||
ip: string,
|
return modelInfo.providers.find((provider) => provider.id === modelInfo.fallbackProvider)
|
||||||
) {
|
}
|
||||||
const providers = model.providers
|
|
||||||
.filter((provider) => !provider.disabled)
|
|
||||||
.flatMap((provider) => Array<typeof provider>(provider.weight ?? 1).fill(provider))
|
|
||||||
|
|
||||||
// Use last character of IP address to select a provider
|
const providers = modelInfo.providers
|
||||||
const lastChar = ip.charCodeAt(ip.length - 1) || 0
|
.filter((provider) => !provider.disabled)
|
||||||
const index = lastChar % providers.length
|
.filter((provider) => !retry.excludeProviders.includes(provider.id))
|
||||||
const provider = providers[index]
|
.flatMap((provider) => Array<typeof provider>(provider.weight ?? 1).fill(provider))
|
||||||
|
|
||||||
if (!(provider.id in zenData.providers)) {
|
// Use the last 2 characters of IP address to select a provider
|
||||||
throw new ModelError(`Provider ${provider.id} not supported`)
|
const lastChars = ip.slice(-2)
|
||||||
}
|
const index = parseInt(lastChars, 16) % providers.length
|
||||||
|
return providers[index || 0]
|
||||||
|
})()
|
||||||
|
|
||||||
|
if (!provider) throw new ModelError("No provider available")
|
||||||
|
if (!(provider.id in zenData.providers)) throw new ModelError(`Provider ${provider.id} not supported`)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...provider,
|
...provider,
|
||||||
...zenData.providers[provider.id],
|
...zenData.providers[provider.id],
|
||||||
...(provider.id === "anthropic"
|
...(() => {
|
||||||
? anthropicHelper
|
const format = zenData.providers[provider.id].format
|
||||||
: provider.id === "openai"
|
if (format === "anthropic") return anthropicHelper
|
||||||
? openaiHelper
|
if (format === "openai") return openaiHelper
|
||||||
: oaCompatHelper),
|
return oaCompatHelper
|
||||||
|
})(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function authenticate(
|
async function authenticate(modelInfo: ModelInfo, providerInfo: ProviderInfo) {
|
||||||
model: Awaited<ReturnType<typeof validateModel>>,
|
|
||||||
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
|
|
||||||
) {
|
|
||||||
const apiKey = opts.parseApiKey(input.request.headers)
|
const apiKey = opts.parseApiKey(input.request.headers)
|
||||||
if (!apiKey) {
|
if (!apiKey || apiKey === "public") {
|
||||||
if (model.allowAnonymous) return
|
if (modelInfo.allowAnonymous) return
|
||||||
throw new AuthError("Missing API key.")
|
throw new AuthError("Missing API key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,6 +307,7 @@ export async function handler(
|
|||||||
monthlyLimit: BillingTable.monthlyLimit,
|
monthlyLimit: BillingTable.monthlyLimit,
|
||||||
monthlyUsage: BillingTable.monthlyUsage,
|
monthlyUsage: BillingTable.monthlyUsage,
|
||||||
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
|
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
|
||||||
|
reloadTrigger: BillingTable.reloadTrigger,
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
id: UserTable.id,
|
id: UserTable.id,
|
||||||
@@ -295,20 +323,11 @@ export async function handler(
|
|||||||
.from(KeyTable)
|
.from(KeyTable)
|
||||||
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
||||||
.innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
|
.innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
|
||||||
.innerJoin(
|
.innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)))
|
||||||
UserTable,
|
.leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, modelInfo.id)))
|
||||||
and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)),
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
ModelTable,
|
|
||||||
and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id)),
|
|
||||||
)
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
ProviderTable,
|
ProviderTable,
|
||||||
and(
|
and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)),
|
||||||
eq(ProviderTable.workspaceID, KeyTable.workspaceID),
|
|
||||||
eq(ProviderTable.provider, providerInfo.id),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
||||||
.then((rows) => rows[0]),
|
.then((rows) => rows[0]),
|
||||||
@@ -331,11 +350,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) return
|
||||||
if (authInfo.provider?.credentials) return
|
if (authInfo.provider?.credentials) return
|
||||||
if (authInfo.isFree) return
|
if (authInfo.isFree) return
|
||||||
if (model.allowAnonymous) return
|
if (modelInfo.allowAnonymous) return
|
||||||
|
|
||||||
const billing = authInfo.billing
|
const billing = authInfo.billing
|
||||||
if (!billing.paymentMethodID)
|
if (!billing.paymentMethodID)
|
||||||
@@ -379,39 +398,24 @@ export async function handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateModelSettings(authInfo: Awaited<ReturnType<typeof authenticate>>) {
|
function validateModelSettings(authInfo: AuthInfo) {
|
||||||
if (!authInfo) return
|
if (!authInfo) return
|
||||||
if (authInfo.isDisabled) throw new ModelError("Model is disabled")
|
if (authInfo.isDisabled) throw new ModelError("Model is disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateProviderKey(
|
function updateProviderKey(authInfo: AuthInfo, providerInfo: ProviderInfo) {
|
||||||
authInfo: Awaited<ReturnType<typeof authenticate>>,
|
|
||||||
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
|
|
||||||
) {
|
|
||||||
if (!authInfo) return
|
if (!authInfo) return
|
||||||
if (!authInfo.provider?.credentials) return
|
if (!authInfo.provider?.credentials) return
|
||||||
providerInfo.apiKey = authInfo.provider.credentials
|
providerInfo.apiKey = authInfo.provider.credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
async function trackUsage(
|
async function trackUsage(authInfo: AuthInfo, modelInfo: ModelInfo, providerInfo: ProviderInfo, usage: any) {
|
||||||
authInfo: Awaited<ReturnType<typeof authenticate>>,
|
const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } =
|
||||||
modelInfo: ReturnType<typeof validateModel>,
|
providerInfo.normalizeUsage(usage)
|
||||||
providerInfo: Awaited<ReturnType<typeof selectProvider>>,
|
|
||||||
usage: any,
|
|
||||||
) {
|
|
||||||
const {
|
|
||||||
inputTokens,
|
|
||||||
outputTokens,
|
|
||||||
reasoningTokens,
|
|
||||||
cacheReadTokens,
|
|
||||||
cacheWrite5mTokens,
|
|
||||||
cacheWrite1hTokens,
|
|
||||||
} = providerInfo.normalizeUsage(usage)
|
|
||||||
|
|
||||||
const modelCost =
|
const modelCost =
|
||||||
modelInfo.cost200K &&
|
modelInfo.cost200K &&
|
||||||
inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) >
|
inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) > 200_000
|
||||||
200_000
|
|
||||||
? modelInfo.cost200K
|
? modelInfo.cost200K
|
||||||
: modelInfo.cost
|
: modelInfo.cost
|
||||||
|
|
||||||
@@ -462,8 +466,7 @@ export async function handler(
|
|||||||
|
|
||||||
if (!authInfo) return
|
if (!authInfo) return
|
||||||
|
|
||||||
const cost =
|
const cost = authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent)
|
||||||
authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent)
|
|
||||||
await Database.transaction(async (tx) => {
|
await Database.transaction(async (tx) => {
|
||||||
await tx.insert(UsageTable).values({
|
await tx.insert(UsageTable).values({
|
||||||
workspaceID: authInfo.workspaceID,
|
workspaceID: authInfo.workspaceID,
|
||||||
@@ -503,9 +506,7 @@ export async function handler(
|
|||||||
`,
|
`,
|
||||||
timeMonthlyUsageUpdated: sql`now()`,
|
timeMonthlyUsageUpdated: sql`now()`,
|
||||||
})
|
})
|
||||||
.where(
|
.where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)))
|
||||||
and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await Database.use((tx) =>
|
await Database.use((tx) =>
|
||||||
@@ -516,7 +517,7 @@ export async function handler(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reload(authInfo: Awaited<ReturnType<typeof authenticate>>) {
|
async function reload(authInfo: AuthInfo) {
|
||||||
if (!authInfo) return
|
if (!authInfo) return
|
||||||
if (authInfo.isFree) return
|
if (authInfo.isFree) return
|
||||||
if (authInfo.provider?.credentials) return
|
if (authInfo.provider?.credentials) return
|
||||||
@@ -531,11 +532,11 @@ export async function handler(
|
|||||||
and(
|
and(
|
||||||
eq(BillingTable.workspaceID, authInfo.workspaceID),
|
eq(BillingTable.workspaceID, authInfo.workspaceID),
|
||||||
eq(BillingTable.reload, true),
|
eq(BillingTable.reload, true),
|
||||||
lt(BillingTable.balance, centsToMicroCents(Billing.CHARGE_THRESHOLD)),
|
lt(
|
||||||
or(
|
BillingTable.balance,
|
||||||
isNull(BillingTable.timeReloadLockedTill),
|
centsToMicroCents((authInfo.billing.reloadTrigger ?? Billing.RELOAD_TRIGGER) * 100),
|
||||||
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).media_type === "string" &&
|
||||||
typeof (src as any).data === "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
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +168,11 @@ export function fromAnthropicRequest(body: any): CommonRequest {
|
|||||||
.filter((t: any) => t && typeof t === "object" && "input_schema" in t)
|
.filter((t: any) => t && typeof t === "object" && "input_schema" in t)
|
||||||
.map((t: any) => ({
|
.map((t: any) => ({
|
||||||
type: "function",
|
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
|
: undefined
|
||||||
|
|
||||||
@@ -452,7 +459,12 @@ export function toAnthropicResponse(resp: CommonResponse) {
|
|||||||
} catch {
|
} catch {
|
||||||
input = (tc as any).function.arguments
|
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") {
|
if (json.type === "content_block_start") {
|
||||||
const cb = json.content_block
|
const cb = json.content_block
|
||||||
if (cb?.type === "text") {
|
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") {
|
} else if (cb?.type === "tool_use") {
|
||||||
out.choices.push({
|
out.choices.push({
|
||||||
index: json.index ?? 0,
|
index: json.index ?? 0,
|
||||||
delta: {
|
delta: {
|
||||||
tool_calls: [
|
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,
|
finish_reason: null,
|
||||||
@@ -532,7 +553,9 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
|
|||||||
} else if (d?.type === "input_json_delta") {
|
} else if (d?.type === "input_json_delta") {
|
||||||
out.choices.push({
|
out.choices.push({
|
||||||
index: json.index ?? 0,
|
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,
|
finish_reason: null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -532,7 +532,9 @@ export function toOaCompatibleChunk(chunk: CommonChunk): string {
|
|||||||
total_tokens: chunk.usage.total_tokens,
|
total_tokens: chunk.usage.total_tokens,
|
||||||
...(chunk.usage.prompt_tokens_details?.cached_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).media_type === "string" &&
|
||||||
typeof (s as any).data === "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
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +156,11 @@ export function fromOpenaiRequest(body: any): CommonRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((m as any).role === "tool") {
|
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
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +217,10 @@ export function toOpenaiRequest(body: CommonRequest) {
|
|||||||
typeof (s as any).media_type === "string" &&
|
typeof (s as any).media_type === "string" &&
|
||||||
typeof (s as any).data === "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
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,7 +508,9 @@ export function fromOpenaiChunk(chunk: string): CommonChunk | string {
|
|||||||
if (typeof name === "string" && name.length > 0) {
|
if (typeof name === "string" && name.length > 0) {
|
||||||
out.choices.push({
|
out.choices.push({
|
||||||
index: 0,
|
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,
|
finish_reason: null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -555,7 +567,12 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
|
|||||||
const model = chunk.model
|
const model = chunk.model
|
||||||
|
|
||||||
if (d.content) {
|
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)}`
|
return `event: response.output_text.delta\ndata: ${JSON.stringify(data)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,7 +582,13 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
|
|||||||
const data = {
|
const data = {
|
||||||
type: "response.output_item.added",
|
type: "response.output_item.added",
|
||||||
output_index: 0,
|
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)}`
|
return `event: response.output_item.added\ndata: ${JSON.stringify(data)}`
|
||||||
}
|
}
|
||||||
@@ -593,7 +616,11 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
|
|||||||
}
|
}
|
||||||
: undefined
|
: 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)}`
|
return `event: response.completed\ndata: ${JSON.stringify(data)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Format } from "../format"
|
import { ZenData } from "@opencode-ai/console-core/model.js"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
fromAnthropicChunk,
|
fromAnthropicChunk,
|
||||||
fromAnthropicRequest,
|
fromAnthropicRequest,
|
||||||
@@ -26,7 +25,7 @@ import {
|
|||||||
} from "./openai-compatible"
|
} from "./openai-compatible"
|
||||||
|
|
||||||
export type ProviderHelper = {
|
export type ProviderHelper = {
|
||||||
format: Format
|
format: ZenData.Format
|
||||||
modifyUrl: (providerApi: string) => string
|
modifyUrl: (providerApi: string) => string
|
||||||
modifyHeaders: (headers: Headers, body: Record<string, any>, apiKey: string) => void
|
modifyHeaders: (headers: Headers, body: Record<string, any>, apiKey: string) => void
|
||||||
modifyBody: (body: Record<string, any>) => Record<string, any>
|
modifyBody: (body: Record<string, any>) => Record<string, any>
|
||||||
@@ -158,7 +157,7 @@ export interface CommonChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createBodyConverter(from: Format, to: Format) {
|
export function createBodyConverter(from: ZenData.Format, to: ZenData.Format) {
|
||||||
return (body: any): any => {
|
return (body: any): any => {
|
||||||
if (from === to) return body
|
if (from === to) return body
|
||||||
|
|
||||||
@@ -173,7 +172,7 @@ export function createBodyConverter(from: Format, to: Format) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createStreamPartConverter(from: Format, to: Format) {
|
export function createStreamPartConverter(from: ZenData.Format, to: ZenData.Format) {
|
||||||
return (part: any): any => {
|
return (part: any): any => {
|
||||||
if (from === to) return part
|
if (from === to) return part
|
||||||
|
|
||||||
@@ -191,7 +190,7 @@ export function createStreamPartConverter(from: Format, to: Format) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createResponseConverter(from: Format, to: Format) {
|
export function createResponseConverter(from: ZenData.Format, to: ZenData.Format) {
|
||||||
return (response: any): any => {
|
return (response: any): any => {
|
||||||
if (from === to) return response
|
if (from === to) return response
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
.from(KeyTable)
|
||||||
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
|
||||||
.leftJoin(
|
.leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)))
|
||||||
ModelTable,
|
|
||||||
and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)),
|
|
||||||
)
|
|
||||||
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
|
||||||
.then((rows) => rows.map((row) => row.model)),
|
.then((rows) => rows.map((row) => row.model)),
|
||||||
)
|
)
|
||||||
|
|||||||
Vendored
+1
-1
@@ -6,4 +6,4 @@
|
|||||||
/// <reference path="../../../sst-env.d.ts" />
|
/// <reference path="../../../sst-env.d.ts" />
|
||||||
|
|
||||||
import "sst"
|
import "sst"
|
||||||
export {}
|
export {}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,17 +473,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -504,10 +486,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -599,10 +578,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -610,10 +586,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -670,9 +643,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -680,9 +651,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -699,4 +668,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,17 +473,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -504,10 +486,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -599,10 +578,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -610,10 +586,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -670,9 +643,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -680,9 +651,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -699,4 +668,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,17 +473,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -504,10 +486,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -592,10 +571,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -603,10 +579,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -663,9 +636,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -673,9 +644,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -692,4 +661,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,17 +473,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -504,10 +486,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -599,10 +578,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -610,10 +586,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -670,9 +643,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -680,9 +651,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -699,4 +668,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,17 +473,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -504,10 +486,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -613,18 +592,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -632,10 +605,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -692,9 +662,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -702,9 +670,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -721,4 +687,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,17 +473,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -504,10 +486,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -613,32 +592,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -646,10 +615,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -706,9 +672,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -716,9 +680,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -735,4 +697,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,17 +473,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -504,10 +486,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -599,32 +578,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -632,10 +601,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -692,9 +658,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -702,9 +666,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -721,4 +683,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -493,17 +480,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"columns": [
|
"columns": ["workspace_id", "name"],
|
||||||
"workspace_id",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -511,10 +493,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -606,32 +585,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -639,10 +608,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -699,9 +665,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -709,9 +673,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -728,4 +690,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -493,9 +480,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -503,10 +488,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -598,32 +580,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -631,10 +603,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -691,9 +660,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -701,9 +668,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -720,4 +685,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -479,9 +466,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -489,10 +474,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -584,32 +566,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -617,10 +589,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -677,9 +646,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -687,9 +654,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -706,4 +671,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -479,9 +466,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -489,10 +474,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -584,32 +566,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -617,10 +589,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -677,9 +646,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -687,9 +654,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -706,4 +671,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -479,9 +466,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -489,10 +474,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -605,32 +587,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -638,10 +610,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -698,9 +667,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -708,9 +675,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -727,4 +692,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -479,9 +466,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -489,10 +474,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -549,10 +531,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -560,10 +539,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -676,32 +652,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -709,10 +675,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -769,9 +732,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -779,9 +740,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -798,4 +757,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -398,10 +388,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -479,9 +466,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -489,10 +474,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -549,10 +531,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -560,10 +539,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -627,10 +603,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"workspace_provider": {
|
"workspace_provider": {
|
||||||
"name": "workspace_provider",
|
"name": "workspace_provider",
|
||||||
"columns": [
|
"columns": ["workspace_id", "provider"],
|
||||||
"workspace_id",
|
|
||||||
"provider"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -638,10 +611,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"provider_workspace_id_id_pk": {
|
"provider_workspace_id_id_pk": {
|
||||||
"name": "provider_workspace_id_id_pk",
|
"name": "provider_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -754,32 +724,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -787,10 +747,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -847,9 +804,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -857,9 +812,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -876,4 +829,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,9 +178,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,10 +186,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -280,10 +273,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -405,10 +395,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -486,9 +473,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -496,10 +481,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -556,10 +538,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -567,10 +546,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -634,10 +610,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"workspace_provider": {
|
"workspace_provider": {
|
||||||
"name": "workspace_provider",
|
"name": "workspace_provider",
|
||||||
"columns": [
|
"columns": ["workspace_id", "provider"],
|
||||||
"workspace_id",
|
|
||||||
"provider"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -645,10 +618,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"provider_workspace_id_id_pk": {
|
"provider_workspace_id_id_pk": {
|
||||||
"name": "provider_workspace_id_id_pk",
|
"name": "provider_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -761,32 +731,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -794,10 +754,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -854,9 +811,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -864,9 +819,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -883,4 +836,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -187,9 +185,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -197,10 +193,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -287,10 +280,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -412,10 +402,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -493,9 +480,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -503,10 +488,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -563,10 +545,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -574,10 +553,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -641,10 +617,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"workspace_provider": {
|
"workspace_provider": {
|
||||||
"name": "workspace_provider",
|
"name": "workspace_provider",
|
||||||
"columns": [
|
"columns": ["workspace_id", "provider"],
|
||||||
"workspace_id",
|
|
||||||
"provider"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -652,10 +625,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"provider_workspace_id_id_pk": {
|
"provider_workspace_id_id_pk": {
|
||||||
"name": "provider_workspace_id_id_pk",
|
"name": "provider_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -768,32 +738,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -801,10 +761,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -861,9 +818,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -871,9 +826,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -890,4 +843,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"email": {
|
"email": {
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -117,10 +115,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"provider": {
|
"provider": {
|
||||||
"name": "provider",
|
"name": "provider",
|
||||||
"columns": [
|
"columns": ["provider", "subject"],
|
||||||
"provider",
|
|
||||||
"subject"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -257,9 +252,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -267,10 +260,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -357,10 +347,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -482,10 +469,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -563,9 +547,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -573,10 +555,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -633,10 +612,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -644,10 +620,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -711,10 +684,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"workspace_provider": {
|
"workspace_provider": {
|
||||||
"name": "workspace_provider",
|
"name": "workspace_provider",
|
||||||
"columns": [
|
"columns": ["workspace_id", "provider"],
|
||||||
"workspace_id",
|
|
||||||
"provider"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -722,10 +692,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"provider_workspace_id_id_pk": {
|
"provider_workspace_id_id_pk": {
|
||||||
"name": "provider_workspace_id_id_pk",
|
"name": "provider_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -838,32 +805,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -871,10 +828,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -931,9 +885,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -941,9 +893,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -960,4 +910,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,17 +102,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"provider": {
|
"provider": {
|
||||||
"name": "provider",
|
"name": "provider",
|
||||||
"columns": [
|
"columns": ["provider", "subject"],
|
||||||
"provider",
|
|
||||||
"subject"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"account_id": {
|
"account_id": {
|
||||||
"name": "account_id",
|
"name": "account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -249,9 +244,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -259,10 +252,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -349,10 +339,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -474,10 +461,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -555,9 +539,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -565,10 +547,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -625,10 +604,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -636,10 +612,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -703,10 +676,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"workspace_provider": {
|
"workspace_provider": {
|
||||||
"name": "workspace_provider",
|
"name": "workspace_provider",
|
||||||
"columns": [
|
"columns": ["workspace_id", "provider"],
|
||||||
"workspace_id",
|
|
||||||
"provider"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -714,10 +684,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"provider_workspace_id_id_pk": {
|
"provider_workspace_id_id_pk": {
|
||||||
"name": "provider_workspace_id_id_pk",
|
"name": "provider_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -830,32 +797,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -863,10 +820,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -923,9 +877,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -933,9 +885,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -952,4 +902,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"account_id_pk": {
|
"account_id_pk": {
|
||||||
"name": "account_id_pk",
|
"name": "account_id_pk",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -109,17 +107,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"provider": {
|
"provider": {
|
||||||
"name": "provider",
|
"name": "provider",
|
||||||
"columns": [
|
"columns": ["provider", "subject"],
|
||||||
"provider",
|
|
||||||
"subject"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"account_id": {
|
"account_id": {
|
||||||
"name": "account_id",
|
"name": "account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -127,9 +120,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"auth_id_pk": {
|
"auth_id_pk": {
|
||||||
"name": "auth_id_pk",
|
"name": "auth_id_pk",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -263,9 +254,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -273,10 +262,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -363,10 +349,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -488,10 +471,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -569,9 +549,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -579,10 +557,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -639,10 +614,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -650,10 +622,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -717,10 +686,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"workspace_provider": {
|
"workspace_provider": {
|
||||||
"name": "workspace_provider",
|
"name": "workspace_provider",
|
||||||
"columns": [
|
"columns": ["workspace_id", "provider"],
|
||||||
"workspace_id",
|
|
||||||
"provider"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -728,10 +694,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"provider_workspace_id_id_pk": {
|
"provider_workspace_id_id_pk": {
|
||||||
"name": "provider_workspace_id_id_pk",
|
"name": "provider_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -844,32 +807,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -877,10 +830,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -937,9 +887,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -947,9 +895,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -966,4 +912,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"account_id_pk": {
|
"account_id_pk": {
|
||||||
"name": "account_id_pk",
|
"name": "account_id_pk",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -109,17 +107,12 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"provider": {
|
"provider": {
|
||||||
"name": "provider",
|
"name": "provider",
|
||||||
"columns": [
|
"columns": ["provider", "subject"],
|
||||||
"provider",
|
|
||||||
"subject"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"account_id": {
|
"account_id": {
|
||||||
"name": "account_id",
|
"name": "account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -127,9 +120,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"auth_id_pk": {
|
"auth_id_pk": {
|
||||||
"name": "auth_id_pk",
|
"name": "auth_id_pk",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -277,9 +268,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_customer_id": {
|
"global_customer_id": {
|
||||||
"name": "global_customer_id",
|
"name": "global_customer_id",
|
||||||
"columns": [
|
"columns": ["customer_id"],
|
||||||
"customer_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -287,10 +276,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"billing_workspace_id_id_pk": {
|
"billing_workspace_id_id_pk": {
|
||||||
"name": "billing_workspace_id_id_pk",
|
"name": "billing_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -377,10 +363,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"payment_workspace_id_id_pk": {
|
"payment_workspace_id_id_pk": {
|
||||||
"name": "payment_workspace_id_id_pk",
|
"name": "payment_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -502,10 +485,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"usage_workspace_id_id_pk": {
|
"usage_workspace_id_id_pk": {
|
||||||
"name": "usage_workspace_id_id_pk",
|
"name": "usage_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -583,9 +563,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"global_key": {
|
"global_key": {
|
||||||
"name": "global_key",
|
"name": "global_key",
|
||||||
"columns": [
|
"columns": ["key"],
|
||||||
"key"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -593,10 +571,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"key_workspace_id_id_pk": {
|
"key_workspace_id_id_pk": {
|
||||||
"name": "key_workspace_id_id_pk",
|
"name": "key_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -653,10 +628,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"model_workspace_model": {
|
"model_workspace_model": {
|
||||||
"name": "model_workspace_model",
|
"name": "model_workspace_model",
|
||||||
"columns": [
|
"columns": ["workspace_id", "model"],
|
||||||
"workspace_id",
|
|
||||||
"model"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -664,10 +636,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"model_workspace_id_id_pk": {
|
"model_workspace_id_id_pk": {
|
||||||
"name": "model_workspace_id_id_pk",
|
"name": "model_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -731,10 +700,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"workspace_provider": {
|
"workspace_provider": {
|
||||||
"name": "workspace_provider",
|
"name": "workspace_provider",
|
||||||
"columns": [
|
"columns": ["workspace_id", "provider"],
|
||||||
"workspace_id",
|
|
||||||
"provider"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -742,10 +708,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"provider_workspace_id_id_pk": {
|
"provider_workspace_id_id_pk": {
|
||||||
"name": "provider_workspace_id_id_pk",
|
"name": "provider_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -858,32 +821,22 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"user_account_id": {
|
"user_account_id": {
|
||||||
"name": "user_account_id",
|
"name": "user_account_id",
|
||||||
"columns": [
|
"columns": ["workspace_id", "account_id"],
|
||||||
"workspace_id",
|
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"user_email": {
|
"user_email": {
|
||||||
"name": "user_email",
|
"name": "user_email",
|
||||||
"columns": [
|
"columns": ["workspace_id", "email"],
|
||||||
"workspace_id",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
},
|
},
|
||||||
"global_account_id": {
|
"global_account_id": {
|
||||||
"name": "global_account_id",
|
"name": "global_account_id",
|
||||||
"columns": [
|
"columns": ["account_id"],
|
||||||
"account_id"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
},
|
},
|
||||||
"global_email": {
|
"global_email": {
|
||||||
"name": "global_email",
|
"name": "global_email",
|
||||||
"columns": [
|
"columns": ["email"],
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"isUnique": false
|
"isUnique": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -891,10 +844,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"user_workspace_id_id_pk": {
|
"user_workspace_id_id_pk": {
|
||||||
"name": "user_workspace_id_id_pk",
|
"name": "user_workspace_id_id_pk",
|
||||||
"columns": [
|
"columns": ["workspace_id", "id"]
|
||||||
"workspace_id",
|
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -951,9 +901,7 @@
|
|||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"columns": [
|
"columns": ["slug"],
|
||||||
"slug"
|
|
||||||
],
|
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -961,9 +909,7 @@
|
|||||||
"compositePrimaryKeys": {
|
"compositePrimaryKeys": {
|
||||||
"workspace_id": {
|
"workspace_id": {
|
||||||
"name": "workspace_id",
|
"name": "workspace_id",
|
||||||
"columns": [
|
"columns": ["id"]
|
||||||
"id"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
@@ -980,4 +926,4 @@
|
|||||||
"tables": {},
|
"tables": {},
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user