@lobehub/edge-contract 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +19 -2
- package/dist/acquisition-context.d.ts +12 -0
- package/dist/acquisition-context.js +175 -0
- package/dist/landing-locales.d.ts +4 -0
- package/dist/landing-locales.js +22 -0
- package/dist/last-workspace-cookie.d.ts +7 -0
- package/dist/last-workspace-cookie.js +30 -0
- package/dist/request-locale.d.ts +13 -0
- package/dist/request-locale.js +97 -0
- package/dist/seo-topics.d.ts +261 -0
- package/dist/seo-topics.js +269 -0
- package/fixtures/acquisition-context.json +257 -0
- package/fixtures/last-workspace-cookie.json +141 -0
- package/fixtures/request-locale.json +262 -0
- package/package.json +49 -3
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// Key = topic slug (the `q` query param), value = display name for the SEO page and Hero.
|
|
2
|
+
// Landing server-renders `q` only for these topics; the gateway drops any other `q` from the
|
|
3
|
+
// cache key. A topic missing here loses its server-rendered page.
|
|
4
|
+
export const SEO_TOPICS = {
|
|
5
|
+
agent: {
|
|
6
|
+
'aliyun': 'Aliyun',
|
|
7
|
+
'baichuan': 'Baichuan',
|
|
8
|
+
'baidu': 'Baidu',
|
|
9
|
+
'bilibili': 'Bilibili',
|
|
10
|
+
'chatgpt': 'ChatGPT',
|
|
11
|
+
'claude': 'Claude',
|
|
12
|
+
'claude-code': 'Claude Code',
|
|
13
|
+
'clawdbot': 'ClawdBot',
|
|
14
|
+
'coding': 'Coding',
|
|
15
|
+
'codx': 'Codx',
|
|
16
|
+
'crewai': 'CrewAI',
|
|
17
|
+
'cursor': 'Cursor',
|
|
18
|
+
'deepseek': 'DeepSeek',
|
|
19
|
+
'design': 'Design',
|
|
20
|
+
'dingtalk': 'DingTalk',
|
|
21
|
+
'discord': 'Discord',
|
|
22
|
+
'doubao': 'Doubao',
|
|
23
|
+
'douyin': 'Douyin',
|
|
24
|
+
'education': 'Education',
|
|
25
|
+
'excel': 'Microsoft Excel',
|
|
26
|
+
'feishu': 'Feishu',
|
|
27
|
+
'gemini': 'Gemini',
|
|
28
|
+
'github': 'GitHub',
|
|
29
|
+
'hunyuan': 'Hunyuan',
|
|
30
|
+
'image': 'Image',
|
|
31
|
+
'jd': 'JD.com',
|
|
32
|
+
'kimi': 'Kimi',
|
|
33
|
+
'kuaishou': 'Kuaishou',
|
|
34
|
+
'langchain': 'LangChain',
|
|
35
|
+
'line': 'Line',
|
|
36
|
+
'manus': 'Manus',
|
|
37
|
+
'marketing': 'Marketing',
|
|
38
|
+
'memory': 'Memory',
|
|
39
|
+
'moltbot': 'MoltBot',
|
|
40
|
+
'notion': 'Notion',
|
|
41
|
+
'office': 'Office',
|
|
42
|
+
'ollama': 'Ollama',
|
|
43
|
+
'openai': 'OpenAI',
|
|
44
|
+
'openclaw': 'OpenClaw',
|
|
45
|
+
'pdf': 'PDF',
|
|
46
|
+
'pinduoduo': 'Pinduoduo',
|
|
47
|
+
'programming': 'Programming',
|
|
48
|
+
'qwen': 'Qwen',
|
|
49
|
+
'rag': 'RAG',
|
|
50
|
+
'reddit': 'Reddit',
|
|
51
|
+
'research': 'Research',
|
|
52
|
+
'slack': 'Slack',
|
|
53
|
+
'taobao': 'Taobao',
|
|
54
|
+
'telegram': 'Telegram',
|
|
55
|
+
'tencent': 'Tencent',
|
|
56
|
+
'tongyi': 'Tongyi',
|
|
57
|
+
'toutiao': 'Toutiao',
|
|
58
|
+
'translation': 'Translation',
|
|
59
|
+
'vscode': 'VS Code',
|
|
60
|
+
'wechat': 'WeChat',
|
|
61
|
+
'wecom': 'WeCom',
|
|
62
|
+
'weibo': 'Weibo',
|
|
63
|
+
'wenxin': 'Wenxin',
|
|
64
|
+
'writing': 'Writing',
|
|
65
|
+
'xiaohongshu': 'Xiaohongshu',
|
|
66
|
+
'youtube': 'YouTube',
|
|
67
|
+
'zhipu': 'Zhipu',
|
|
68
|
+
'京东': '京东',
|
|
69
|
+
'今日头条': '今日头条',
|
|
70
|
+
'企业微信': '企业微信',
|
|
71
|
+
'公众号': '公众号',
|
|
72
|
+
'写作': '写作',
|
|
73
|
+
'哔哩哔哩': '哔哩哔哩',
|
|
74
|
+
'小红书': '小红书',
|
|
75
|
+
'微信': '微信',
|
|
76
|
+
'微博': '微博',
|
|
77
|
+
'快手': '快手',
|
|
78
|
+
'抖音': '抖音',
|
|
79
|
+
'拼多多': '拼多多',
|
|
80
|
+
'推特': '推特',
|
|
81
|
+
'淘宝': '淘宝',
|
|
82
|
+
'百度': '百度',
|
|
83
|
+
'营销': '营销',
|
|
84
|
+
'论文': '论文',
|
|
85
|
+
'豆包': '豆包',
|
|
86
|
+
'运营': '运营',
|
|
87
|
+
'钉钉': '钉钉',
|
|
88
|
+
'阿里云': '阿里云',
|
|
89
|
+
'飞书': '飞书',
|
|
90
|
+
},
|
|
91
|
+
mcp: {
|
|
92
|
+
'aliyun': 'Aliyun',
|
|
93
|
+
'aws': 'AWS',
|
|
94
|
+
'azure': 'Azure',
|
|
95
|
+
'baidu': 'Baidu',
|
|
96
|
+
'bilibili': 'Bilibili',
|
|
97
|
+
'bitbucket': 'Bitbucket',
|
|
98
|
+
'blender': 'Blender',
|
|
99
|
+
'brave': 'Brave',
|
|
100
|
+
'chrome': 'Chrome',
|
|
101
|
+
'confluence': 'Confluence',
|
|
102
|
+
'deepseek': 'DeepSeek',
|
|
103
|
+
'dingtalk': 'DingTalk',
|
|
104
|
+
'discord': 'Discord',
|
|
105
|
+
'excel': 'Microsoft Excel',
|
|
106
|
+
'feishu': 'Feishu',
|
|
107
|
+
'fhir': 'FHIR',
|
|
108
|
+
'figma': 'Figma',
|
|
109
|
+
'firebase': 'Firebase',
|
|
110
|
+
'firecrawl': 'Firecrawl',
|
|
111
|
+
'gemini': 'Gemini',
|
|
112
|
+
'git': 'Git',
|
|
113
|
+
'github': 'GitHub',
|
|
114
|
+
'gitlab': 'GitLab',
|
|
115
|
+
'gmail': 'Gmail',
|
|
116
|
+
'godot': 'Godot',
|
|
117
|
+
'google': 'Google',
|
|
118
|
+
'google-calendar': 'Google Calendar',
|
|
119
|
+
'grafana': 'Grafana',
|
|
120
|
+
'home-assistant': 'Home Assistant',
|
|
121
|
+
'huawei': 'Huawei',
|
|
122
|
+
'image': 'Image',
|
|
123
|
+
'jd': 'JD.com',
|
|
124
|
+
'jetbrains': 'JetBrains',
|
|
125
|
+
'jira': 'Jira',
|
|
126
|
+
'kuaishou': 'Kuaishou',
|
|
127
|
+
'kubernetes': 'Kubernetes',
|
|
128
|
+
'line': 'Line',
|
|
129
|
+
'linkedin': 'LinkedIn',
|
|
130
|
+
'memory': 'Memory',
|
|
131
|
+
'mongo': 'MongoDB',
|
|
132
|
+
'mysql': 'MySQL',
|
|
133
|
+
'neo4j': 'Neo4j',
|
|
134
|
+
'notion': 'Notion',
|
|
135
|
+
'obsidian': 'Obsidian',
|
|
136
|
+
'ollama': 'Ollama',
|
|
137
|
+
'openapi': 'OpenAPI',
|
|
138
|
+
'outlook': 'Outlook',
|
|
139
|
+
'pdf': 'PDF',
|
|
140
|
+
'perplexity': 'Perplexity',
|
|
141
|
+
'playwright': 'Playwright',
|
|
142
|
+
'postgres': 'PostgreSQL',
|
|
143
|
+
'python': 'Python',
|
|
144
|
+
'qdrant': 'Qdrant',
|
|
145
|
+
'rag': 'RAG',
|
|
146
|
+
'reddit': 'Reddit',
|
|
147
|
+
'salesforce': 'Salesforce',
|
|
148
|
+
'sheets': 'Google Sheets',
|
|
149
|
+
'shopify': 'Shopify',
|
|
150
|
+
'slack': 'Slack',
|
|
151
|
+
'spotify': 'Spotify',
|
|
152
|
+
'sql': 'SQL',
|
|
153
|
+
'sqlite': 'SQLite',
|
|
154
|
+
'steam': 'Steam',
|
|
155
|
+
'stripe': 'Stripe',
|
|
156
|
+
'supabase': 'Supabase',
|
|
157
|
+
'taobao': 'Taobao',
|
|
158
|
+
'tavily': 'Tavily',
|
|
159
|
+
'telegram': 'Telegram',
|
|
160
|
+
'tencent': 'Tencent',
|
|
161
|
+
'unity': 'Unity',
|
|
162
|
+
'unity-editor': 'Unity Editor',
|
|
163
|
+
'vercel': 'Vercel',
|
|
164
|
+
'wechat': 'WeChat',
|
|
165
|
+
'wecom': 'WeCom',
|
|
166
|
+
'whatsapp': 'WhatsApp',
|
|
167
|
+
'word': 'Microsoft Word',
|
|
168
|
+
'x-twitter': 'X (Twitter)',
|
|
169
|
+
'youtube': 'YouTube',
|
|
170
|
+
'zapier': 'Zapier',
|
|
171
|
+
'zhihu': 'Zhihu',
|
|
172
|
+
'京东': '京东',
|
|
173
|
+
'企业微信': '企业微信',
|
|
174
|
+
'哔哩哔哩': '哔哩哔哩',
|
|
175
|
+
'微信': '微信',
|
|
176
|
+
'快手': '快手',
|
|
177
|
+
'淘宝': '淘宝',
|
|
178
|
+
'百度': '百度',
|
|
179
|
+
'知乎': '知乎',
|
|
180
|
+
'钉钉': '钉钉',
|
|
181
|
+
'阿里云': '阿里云',
|
|
182
|
+
'飞书': '飞书',
|
|
183
|
+
},
|
|
184
|
+
skills: {
|
|
185
|
+
'aliyun': 'Aliyun',
|
|
186
|
+
'aws': 'AWS',
|
|
187
|
+
'baidu': 'Baidu',
|
|
188
|
+
'bilibili': 'Bilibili',
|
|
189
|
+
'chatgpt': 'ChatGPT',
|
|
190
|
+
'claude': 'Claude',
|
|
191
|
+
'claude-code': 'Claude Code',
|
|
192
|
+
'clawdbot': 'ClawdBot',
|
|
193
|
+
'cline': 'Cline',
|
|
194
|
+
'codex': 'Codex',
|
|
195
|
+
'codx': 'Codx',
|
|
196
|
+
'copilot': 'GitHub Copilot',
|
|
197
|
+
'cursor': 'Cursor',
|
|
198
|
+
'database': 'Database',
|
|
199
|
+
'dingtalk': 'DingTalk',
|
|
200
|
+
'discord': 'Discord',
|
|
201
|
+
'docker': 'Docker',
|
|
202
|
+
'excel': 'Microsoft Excel',
|
|
203
|
+
'feishu': 'Feishu',
|
|
204
|
+
'figma': 'Figma',
|
|
205
|
+
'firebase': 'Firebase',
|
|
206
|
+
'git': 'Git',
|
|
207
|
+
'github': 'GitHub',
|
|
208
|
+
'huawei': 'Huawei',
|
|
209
|
+
'image': 'Image',
|
|
210
|
+
'jd': 'JD.com',
|
|
211
|
+
'kuaishou': 'Kuaishou',
|
|
212
|
+
'kubernetes': 'Kubernetes',
|
|
213
|
+
'line': 'Line',
|
|
214
|
+
'manus': 'Manus',
|
|
215
|
+
'memory': 'Memory',
|
|
216
|
+
'moltbot': 'MoltBot',
|
|
217
|
+
'mysql': 'MySQL',
|
|
218
|
+
'notion': 'Notion',
|
|
219
|
+
'ollama': 'Ollama',
|
|
220
|
+
'openclaw': 'OpenClaw',
|
|
221
|
+
'pdf': 'PDF',
|
|
222
|
+
'perplexity': 'Perplexity',
|
|
223
|
+
'pinduoduo': 'Pinduoduo',
|
|
224
|
+
'playwright': 'Playwright',
|
|
225
|
+
'postgres': 'PostgreSQL',
|
|
226
|
+
'python': 'Python',
|
|
227
|
+
'rag': 'RAG',
|
|
228
|
+
'reddit': 'Reddit',
|
|
229
|
+
'redis': 'Redis',
|
|
230
|
+
'search': 'Search',
|
|
231
|
+
'slack': 'Slack',
|
|
232
|
+
'sql': 'SQL',
|
|
233
|
+
'supabase': 'Supabase',
|
|
234
|
+
'taobao': 'Taobao',
|
|
235
|
+
'tavily': 'Tavily',
|
|
236
|
+
'telegram': 'Telegram',
|
|
237
|
+
'tencent': 'Tencent',
|
|
238
|
+
'vscode': 'VS Code',
|
|
239
|
+
'wechat': 'WeChat',
|
|
240
|
+
'wecom': 'WeCom',
|
|
241
|
+
'windsurf': 'Windsurf',
|
|
242
|
+
'youtube': 'YouTube',
|
|
243
|
+
'zhihu': 'Zhihu',
|
|
244
|
+
'公众号': '公众号',
|
|
245
|
+
'写作': '写作',
|
|
246
|
+
'哔哩哔哩': '哔哩哔哩',
|
|
247
|
+
'小红书': '小红书',
|
|
248
|
+
'微信': '微信',
|
|
249
|
+
'抖音': '抖音',
|
|
250
|
+
'推特': '推特',
|
|
251
|
+
'淘宝': '淘宝',
|
|
252
|
+
'百度': '百度',
|
|
253
|
+
'知乎': '知乎',
|
|
254
|
+
'营销': '营销',
|
|
255
|
+
'论文': '论文',
|
|
256
|
+
'运营': '运营',
|
|
257
|
+
'钉钉': '钉钉',
|
|
258
|
+
'阿里云': '阿里云',
|
|
259
|
+
'飞书': '飞书',
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
export const hasSeoTopic = (market, topic) => Object.hasOwn(SEO_TOPICS[market], topic);
|
|
263
|
+
// Free-text searches outside the sitemapped topics are never server-rendered:
|
|
264
|
+
// SSR renders the list without `q` and the browser fetches the results, so the
|
|
265
|
+
// HTML is identical to the URL without `q` and the CDN can share one cache entry
|
|
266
|
+
export const isClientOnlySearch = (market, q) => {
|
|
267
|
+
const topic = typeof q === 'string' ? q.trim() : '';
|
|
268
|
+
return Boolean(topic) && !hasSeoTopic(market, topic);
|
|
269
|
+
};
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
{
|
|
2
|
+
"attributionParams": [
|
|
3
|
+
"gad_source",
|
|
4
|
+
"mc_cid",
|
|
5
|
+
"gclid",
|
|
6
|
+
"gclsrc",
|
|
7
|
+
"dclid",
|
|
8
|
+
"gbraid",
|
|
9
|
+
"wbraid",
|
|
10
|
+
"fbclid",
|
|
11
|
+
"msclkid",
|
|
12
|
+
"twclid",
|
|
13
|
+
"li_fat_id",
|
|
14
|
+
"igshid",
|
|
15
|
+
"ttclid",
|
|
16
|
+
"rdt_cid",
|
|
17
|
+
"epik",
|
|
18
|
+
"qclid",
|
|
19
|
+
"sccid",
|
|
20
|
+
"irclid",
|
|
21
|
+
"_kx"
|
|
22
|
+
],
|
|
23
|
+
"authority": "lobehub-cloud@19f89cf50 src/libs/analytics/acquisitionContext.ts and src/proxy.ts ATTRIBUTION_PARAMS",
|
|
24
|
+
"cases": [
|
|
25
|
+
{
|
|
26
|
+
"expected": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
27
|
+
"input": {
|
|
28
|
+
"context": {
|
|
29
|
+
"capturedAt": "2026-11-06T08:00:00.000Z",
|
|
30
|
+
"lhCid": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
31
|
+
},
|
|
32
|
+
"kind": "sign",
|
|
33
|
+
"secret": "fixture-secret-fixture-secret-00"
|
|
34
|
+
},
|
|
35
|
+
"name": "sign lower-case click id"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"expected": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
39
|
+
"input": {
|
|
40
|
+
"context": {
|
|
41
|
+
"capturedAt": "2026-11-06T08:00:00.000Z",
|
|
42
|
+
"lhCid": "3F2A9C1E-5B7D-4E8A-9C21-7D4E5F6A8B90"
|
|
43
|
+
},
|
|
44
|
+
"kind": "sign",
|
|
45
|
+
"secret": "fixture-secret-fixture-secret-00"
|
|
46
|
+
},
|
|
47
|
+
"name": "sign upper-case click id is lower-cased"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"expected": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
51
|
+
"input": {
|
|
52
|
+
"context": {
|
|
53
|
+
"capturedAt": "2026-11-06T08:00:00Z",
|
|
54
|
+
"lhCid": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
55
|
+
},
|
|
56
|
+
"kind": "sign",
|
|
57
|
+
"secret": "fixture-secret-fixture-secret-00"
|
|
58
|
+
},
|
|
59
|
+
"name": "sign normalizes the timestamp"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"expected": {
|
|
63
|
+
"capturedAt": "2026-11-06T08:00:00.000Z",
|
|
64
|
+
"lhCid": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
65
|
+
},
|
|
66
|
+
"input": {
|
|
67
|
+
"now": "2026-11-07T00:00:00.000Z",
|
|
68
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
69
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
70
|
+
"kind": "verify"
|
|
71
|
+
},
|
|
72
|
+
"name": "verify valid"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"expected": null,
|
|
76
|
+
"input": {
|
|
77
|
+
"now": "2026-11-07T00:00:00.000Z",
|
|
78
|
+
"secret": "another-secret",
|
|
79
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
80
|
+
"kind": "verify"
|
|
81
|
+
},
|
|
82
|
+
"name": "verify wrong secret"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"expected": null,
|
|
86
|
+
"input": {
|
|
87
|
+
"now": "2026-12-06T08:00:01.000Z",
|
|
88
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
89
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
90
|
+
"kind": "verify"
|
|
91
|
+
},
|
|
92
|
+
"name": "verify past 30 days"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"expected": {
|
|
96
|
+
"capturedAt": "2026-11-06T08:00:00.000Z",
|
|
97
|
+
"lhCid": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
98
|
+
},
|
|
99
|
+
"input": {
|
|
100
|
+
"now": "2026-12-06T08:00:00.000Z",
|
|
101
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
102
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
103
|
+
"kind": "verify"
|
|
104
|
+
},
|
|
105
|
+
"name": "verify at 30 days"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"expected": null,
|
|
109
|
+
"input": {
|
|
110
|
+
"now": "2026-11-06T07:54:59.000Z",
|
|
111
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
112
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
113
|
+
"kind": "verify"
|
|
114
|
+
},
|
|
115
|
+
"name": "verify captured in the future"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"expected": {
|
|
119
|
+
"capturedAt": "2026-11-06T08:00:00.000Z",
|
|
120
|
+
"lhCid": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
121
|
+
},
|
|
122
|
+
"input": {
|
|
123
|
+
"now": "2026-11-06T07:55:01.000Z",
|
|
124
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
125
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
126
|
+
"kind": "verify"
|
|
127
|
+
},
|
|
128
|
+
"name": "verify within future skew"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"expected": null,
|
|
132
|
+
"input": {
|
|
133
|
+
"now": "2026-11-07T00:00:00.000Z",
|
|
134
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
135
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxxx.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148",
|
|
136
|
+
"kind": "verify"
|
|
137
|
+
},
|
|
138
|
+
"name": "verify tampered payload"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"expected": null,
|
|
142
|
+
"input": {
|
|
143
|
+
"now": "2026-11-07T00:00:00.000Z",
|
|
144
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
145
|
+
"token": "eyJjYXB0dXJlZEF0IjoiMjAyNi0xMS0wNlQwODowMDowMC4wMDBaIiwibGhDaWQiOiIzZjJhOWMxZS01YjdkLTRlOGEtOWMyMS03ZDRlNWY2YThiOTAiLCJ2ZXJzaW9uIjoxfQ.8T7LWAoeGsHxFp2U7WWylIDGXI19NFdSPtEtkhlb148.x",
|
|
146
|
+
"kind": "verify"
|
|
147
|
+
},
|
|
148
|
+
"name": "verify three parts"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"expected": null,
|
|
152
|
+
"input": {
|
|
153
|
+
"now": "2026-11-07T00:00:00.000Z",
|
|
154
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
155
|
+
"token": "a+b.c/d",
|
|
156
|
+
"kind": "verify"
|
|
157
|
+
},
|
|
158
|
+
"name": "verify not base64url"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"expected": null,
|
|
162
|
+
"input": {
|
|
163
|
+
"now": "2026-11-07T00:00:00.000Z",
|
|
164
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
165
|
+
"token": "",
|
|
166
|
+
"kind": "verify"
|
|
167
|
+
},
|
|
168
|
+
"name": "verify empty"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"expected": null,
|
|
172
|
+
"input": {
|
|
173
|
+
"now": "2026-11-07T00:00:00.000Z",
|
|
174
|
+
"secret": "fixture-secret-fixture-secret-00",
|
|
175
|
+
"token": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
176
|
+
"kind": "verify"
|
|
177
|
+
},
|
|
178
|
+
"name": "verify too long"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"expected": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90",
|
|
182
|
+
"input": {
|
|
183
|
+
"kind": "capture",
|
|
184
|
+
"url": "https://lobehub.com/tasks?lh_cid=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
185
|
+
},
|
|
186
|
+
"name": "capture valid click id"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"expected": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90",
|
|
190
|
+
"input": {
|
|
191
|
+
"kind": "capture",
|
|
192
|
+
"url": "https://lobehub.com/tasks?lh_cid=3F2A9C1E-5B7D-4E8A-9C21-7D4E5F6A8B90"
|
|
193
|
+
},
|
|
194
|
+
"name": "capture upper-case click id"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"expected": null,
|
|
198
|
+
"input": {
|
|
199
|
+
"kind": "capture",
|
|
200
|
+
"url": "https://lobehub.com/tasks?lh_cid=3f2a9c1e-5b7d-1e8a-9c21-7d4e5f6a8b90"
|
|
201
|
+
},
|
|
202
|
+
"name": "capture not a v4 uuid"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"expected": null,
|
|
206
|
+
"input": {
|
|
207
|
+
"kind": "capture",
|
|
208
|
+
"url": "https://lobehub.com/tasks?lh_cid=user-private-value"
|
|
209
|
+
},
|
|
210
|
+
"name": "capture free text"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"expected": null,
|
|
214
|
+
"input": {
|
|
215
|
+
"kind": "capture",
|
|
216
|
+
"url": "https://lobehub.com/tasks"
|
|
217
|
+
},
|
|
218
|
+
"name": "capture missing"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"expected": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90",
|
|
222
|
+
"input": {
|
|
223
|
+
"kind": "capture",
|
|
224
|
+
"url": "https://lobehub.com/signin?callbackUrl=https%3A%2F%2Flobehub.com%2Ftasks%3Flh_cid%3D3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
225
|
+
},
|
|
226
|
+
"name": "capture from the sign-in callback"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"expected": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90",
|
|
230
|
+
"input": {
|
|
231
|
+
"kind": "capture",
|
|
232
|
+
"url": "https://lobehub.com/signup?callbackUrl=https%3A%2F%2Flobehub.com%2Ftasks%3Flh_cid%3D3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
233
|
+
},
|
|
234
|
+
"name": "capture from the sign-up callback"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"expected": null,
|
|
238
|
+
"input": {
|
|
239
|
+
"kind": "capture",
|
|
240
|
+
"url": "https://lobehub.com/signin?callbackUrl=https%3A%2F%2Fevil.example%2F%3Flh_cid%3D3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
241
|
+
},
|
|
242
|
+
"name": "capture ignores a cross-origin callback"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"expected": null,
|
|
246
|
+
"input": {
|
|
247
|
+
"kind": "capture",
|
|
248
|
+
"url": "https://lobehub.com/tasks?callbackUrl=https%3A%2F%2Flobehub.com%2Fx%3Flh_cid%3D3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90"
|
|
249
|
+
},
|
|
250
|
+
"name": "capture ignores callbacks off the auth pages"
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
"cookie": {
|
|
254
|
+
"maxAgeSeconds": 2592000,
|
|
255
|
+
"name": "lh_acq"
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"authority": "lobehub-cloud@19f89cf50 packages/const/src/workspace.ts parseLastWorkspaceCookie",
|
|
3
|
+
"cases": [
|
|
4
|
+
{
|
|
5
|
+
"expected": "my-team",
|
|
6
|
+
"input": {
|
|
7
|
+
"raw": "user_1:my-team",
|
|
8
|
+
"userId": "user_1"
|
|
9
|
+
},
|
|
10
|
+
"name": "valid"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"expected": null,
|
|
14
|
+
"input": {
|
|
15
|
+
"raw": "user_1:my-team",
|
|
16
|
+
"userId": "user_2"
|
|
17
|
+
},
|
|
18
|
+
"name": "another user"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"expected": null,
|
|
22
|
+
"input": {
|
|
23
|
+
"raw": "my-team",
|
|
24
|
+
"userId": "user_1"
|
|
25
|
+
},
|
|
26
|
+
"name": "no separator"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"expected": null,
|
|
30
|
+
"input": {
|
|
31
|
+
"raw": ":my-team",
|
|
32
|
+
"userId": "user_1"
|
|
33
|
+
},
|
|
34
|
+
"name": "empty user part"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"expected": null,
|
|
38
|
+
"input": {
|
|
39
|
+
"raw": "user_1:",
|
|
40
|
+
"userId": "user_1"
|
|
41
|
+
},
|
|
42
|
+
"name": "empty slug"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"expected": null,
|
|
46
|
+
"input": {
|
|
47
|
+
"raw": "user_1:ab",
|
|
48
|
+
"userId": "user_1"
|
|
49
|
+
},
|
|
50
|
+
"name": "slug too short"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"expected": "abc",
|
|
54
|
+
"input": {
|
|
55
|
+
"raw": "user_1:abc",
|
|
56
|
+
"userId": "user_1"
|
|
57
|
+
},
|
|
58
|
+
"name": "slug at min length"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"expected": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
62
|
+
"input": {
|
|
63
|
+
"raw": "user_1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
64
|
+
"userId": "user_1"
|
|
65
|
+
},
|
|
66
|
+
"name": "slug at max length"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"expected": null,
|
|
70
|
+
"input": {
|
|
71
|
+
"raw": "user_1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
72
|
+
"userId": "user_1"
|
|
73
|
+
},
|
|
74
|
+
"name": "slug too long"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"expected": null,
|
|
78
|
+
"input": {
|
|
79
|
+
"raw": "user_1:My-Team",
|
|
80
|
+
"userId": "user_1"
|
|
81
|
+
},
|
|
82
|
+
"name": "upper-case slug"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"expected": null,
|
|
86
|
+
"input": {
|
|
87
|
+
"raw": "user_1:my-team-",
|
|
88
|
+
"userId": "user_1"
|
|
89
|
+
},
|
|
90
|
+
"name": "trailing dash"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"expected": null,
|
|
94
|
+
"input": {
|
|
95
|
+
"raw": "user_1:-my-team",
|
|
96
|
+
"userId": "user_1"
|
|
97
|
+
},
|
|
98
|
+
"name": "leading dash"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"expected": null,
|
|
102
|
+
"input": {
|
|
103
|
+
"raw": "user_1:../admin",
|
|
104
|
+
"userId": "user_1"
|
|
105
|
+
},
|
|
106
|
+
"name": "path traversal"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"expected": null,
|
|
110
|
+
"input": {
|
|
111
|
+
"raw": "user_1:my:team",
|
|
112
|
+
"userId": "user_1"
|
|
113
|
+
},
|
|
114
|
+
"name": "second colon"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"expected": null,
|
|
118
|
+
"input": {
|
|
119
|
+
"raw": "user_1:my-team\r\nx",
|
|
120
|
+
"userId": "user_1"
|
|
121
|
+
},
|
|
122
|
+
"name": "CRLF smuggling"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"expected": null,
|
|
126
|
+
"input": {
|
|
127
|
+
"raw": null,
|
|
128
|
+
"userId": "user_1"
|
|
129
|
+
},
|
|
130
|
+
"name": "missing cookie"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"expected": null,
|
|
134
|
+
"input": {
|
|
135
|
+
"raw": "user_1:my-team",
|
|
136
|
+
"userId": null
|
|
137
|
+
},
|
|
138
|
+
"name": "missing user"
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|