@dimension-studios/shop-browser 1.140.3 → 1.141.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/README.md +150 -3
- package/dist/index.mjs +2 -2
- package/package.json +13 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @dimension-studios/shop-browser
|
|
2
2
|
|
|
3
|
-
Interactive CLI to pick a TikTok shop (authorized for your API token), load cookies from the Dimension **TTK Fetch** API,
|
|
3
|
+
Interactive CLI and browser extension to pick a TikTok shop (authorized for your API token), load cookies from the Dimension **TTK Fetch** API, and open TikTok Seller / Affiliate sessions.
|
|
4
4
|
|
|
5
5
|
Uses the same credentials as **`@dimension-studios/ttk-proxy`**. Publishable tarball includes only compiled `dist/` and `bin/` — no database or internal monorepo code.
|
|
6
6
|
|
|
@@ -52,7 +52,7 @@ shop-browser config:set apiSecret "your-api-secret"
|
|
|
52
52
|
shop-browser config --show
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
##
|
|
55
|
+
## CLI usage
|
|
56
56
|
|
|
57
57
|
Run with **no arguments** to start the flow:
|
|
58
58
|
|
|
@@ -81,15 +81,154 @@ shop-browser --version
|
|
|
81
81
|
shop-browser config --help
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
## Browser extension
|
|
85
|
+
|
|
86
|
+
The extension injects shop cookies into your existing Chrome or Firefox browser on TikTok domains (`*.tiktok.com`, `*.tiktokshop.com`, `*.tiktokglobalshop.com`).
|
|
87
|
+
|
|
88
|
+
### Build the extension (monorepo)
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install
|
|
92
|
+
npm run build:extension -w @dimension-studios/shop-browser
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
This produces:
|
|
96
|
+
|
|
97
|
+
- `packages/shop-browser/dist/extension/chrome` — unpacked Chrome extension
|
|
98
|
+
- `packages/shop-browser/dist/extension/firefox` — unpacked Firefox extension (for debugging)
|
|
99
|
+
- `packages/shop-browser/dist/extension/dimension-shop-browser.xpi` — Firefox add-on file
|
|
100
|
+
|
|
101
|
+
Extension icons are copied from `extension/icons/` (exported from `apps/app/public/icons/icon.svg`).
|
|
102
|
+
|
|
103
|
+
### Install in Chrome
|
|
104
|
+
|
|
105
|
+
1. Open `chrome://extensions`
|
|
106
|
+
2. Enable **Developer mode**
|
|
107
|
+
3. Click **Load unpacked**
|
|
108
|
+
4. Select `packages/shop-browser/dist/extension/chrome`
|
|
109
|
+
|
|
110
|
+
### Install in Firefox
|
|
111
|
+
|
|
112
|
+
Requires **Firefox 127** or later.
|
|
113
|
+
|
|
114
|
+
**Standard Firefox release:** Mozilla blocks unsigned add-ons on normal release builds. Use the temporary install flow below for local development, or install a signed XPI distributed through AMO or your organization. The Firefox manifest declares required data collection permissions (`authenticationInfo`, `searchTerms`) so the add-on can pass AMO validation for that signed distribution path.
|
|
115
|
+
|
|
116
|
+
**Permanent install (unsigned, special Firefox builds only):**
|
|
117
|
+
|
|
118
|
+
Use this only on Firefox **ESR**, **Developer Edition**, **Nightly**, or other **unbranded** builds where unsigned add-ons are allowed. On standard release Firefox, setting `xpinstall.signatures.required` to `false` does **not** permit a permanent unsigned install.
|
|
119
|
+
|
|
120
|
+
1. Open `about:config` and set `xpinstall.signatures.required` to `false`.
|
|
121
|
+
2. Open `about:addons`
|
|
122
|
+
3. Click the gear icon → **Install Add-on From File…**
|
|
123
|
+
4. Select `packages/shop-browser/dist/extension/dimension-shop-browser.xpi`
|
|
124
|
+
|
|
125
|
+
**Temporary install (recommended for standard Firefox; removed on restart):**
|
|
126
|
+
|
|
127
|
+
1. Open `about:debugging#/runtime/this-firefox`
|
|
128
|
+
2. Click **Load Temporary Add-on**
|
|
129
|
+
3. Select `packages/shop-browser/dist/extension/firefox/manifest.json`
|
|
130
|
+
|
|
131
|
+
### Extension usage
|
|
132
|
+
|
|
133
|
+
1. Build the extension with the app origin from `packages/shop-browser/.env` (`NEXT_PUBLIC_APP_URL`, or `TTK_FETCH_API_URL` as fallback).
|
|
134
|
+
2. Open the extension popup and click **Sign in to Dimension** if you are not already signed in on `app.dimensionstudios.co`.
|
|
135
|
+
3. Search for a shop (minimum **2 characters**) and select it. Results are limited to shops you can access in your current organization.
|
|
136
|
+
4. Turn **Auto inject** on to inject cookies when you open TikTok domains, or use **Inject now** manually.
|
|
137
|
+
5. Turning auto inject **off** stops future injections and leaves existing browser cookies untouched.
|
|
138
|
+
|
|
139
|
+
### IAM permission
|
|
140
|
+
|
|
141
|
+
Users need the **Use Shop Browser extension** permission (`SHOP_BROWSER_EXTENSION_ACCESS`) for each shop they inject. Organization administrators can grant it from organization-wide or shop-scoped IAM groups. This permission exposes raw TikTok shop session cookies and effectively lets the user act as an admin for that shop in their browser — grant it only to trusted users.
|
|
142
|
+
|
|
143
|
+
The CLI continues to use API URL + key + secret (`TTK_FETCH_API_*`); only the browser extension uses SaaS session cookies.
|
|
144
|
+
|
|
145
|
+
### CI/CD release
|
|
146
|
+
|
|
147
|
+
The extension is built and published automatically when `@dimension-studios/shop-browser` is released via [semantic-release](https://github.com/semantic-release/semantic-release) on `main-release` / `preprod-release`.
|
|
148
|
+
|
|
149
|
+
**What CI does**
|
|
150
|
+
|
|
151
|
+
1. Bumps the npm package version (same release as the CLI).
|
|
152
|
+
2. Builds the extension with `NEXT_PUBLIC_APP_URL` from GitHub Actions vars (wired in `.github/workflows/release.yml`). The extension manifest version comes from `@dimension-studios/shop-browser` `package.json` (aligned with the semantic-release version on CI).
|
|
153
|
+
3. Attaches release artifacts to the GitHub Release:
|
|
154
|
+
- `dimension-shop-browser.xpi` — Firefox add-on
|
|
155
|
+
- `dimension-shop-browser-chrome.zip` — Chrome unpacked extension (upload to Chrome Web Store or load unpacked)
|
|
156
|
+
|
|
157
|
+
**Required GitHub configuration**
|
|
158
|
+
|
|
159
|
+
- Repository variable: `NEXT_PUBLIC_APP_URL` (e.g. `https://app.dimensionstudios.co` for production releases).
|
|
160
|
+
|
|
161
|
+
**Install from a release**
|
|
162
|
+
|
|
163
|
+
1. Open the [GitHub Releases](https://github.com/dimension-studios/dimension/releases) page for this repo.
|
|
164
|
+
2. Download the XPI or Chrome ZIP from the latest `@dimension-studios/shop-browser` release.
|
|
165
|
+
3. **Firefox:** install the XPI (signed AMO distribution still requires a separate Mozilla submission).
|
|
166
|
+
4. **Chrome:** upload the ZIP to the [Chrome Web Store developer dashboard](https://chrome.google.com/webstore/devconsole), or unzip and load unpacked for internal testing.
|
|
167
|
+
|
|
168
|
+
CI also runs `npm run build:extension` on every pull request (`.github/workflows/check.yml`) to catch build regressions early.
|
|
169
|
+
|
|
170
|
+
### Automatic store listing (Chrome + Firefox)
|
|
171
|
+
|
|
172
|
+
On **`main-release`** only, after a successful semantic-release, CI submits the built extension to:
|
|
173
|
+
|
|
174
|
+
- **Chrome Web Store** — upload + publish via `chrome-webstore-upload-cli`
|
|
175
|
+
- **Firefox Add-ons (AMO)** — listed submission via `web-ext sign --use-submission-api`
|
|
176
|
+
|
|
177
|
+
Preprod (`preprod-release`) still publishes GitHub Release artifacts but does **not** auto-list on stores.
|
|
178
|
+
|
|
179
|
+
#### One-time developer setup
|
|
180
|
+
|
|
181
|
+
**Chrome Web Store**
|
|
182
|
+
|
|
183
|
+
1. Create the extension item in the [Chrome Web Store developer dashboard](https://chrome.google.com/webstore/devconsole) (first upload can be manual).
|
|
184
|
+
2. Enable the [Chrome Web Store API](https://developer.chrome.com/docs/webstore/using-api) on a Google Cloud project.
|
|
185
|
+
3. Create OAuth credentials and generate a refresh token — [chrome-webstore-upload-keys](https://github.com/fregante/chrome-webstore-upload-keys) walks through this.
|
|
186
|
+
4. Note your **Publisher ID** (developer dashboard) and **Extension ID** (from the listing URL or `chrome://extensions` when loaded unpacked).
|
|
187
|
+
|
|
188
|
+
**Firefox Add-ons**
|
|
189
|
+
|
|
190
|
+
1. Create the add-on on [addons.mozilla.org](https://addons.mozilla.org/developers/) (listed).
|
|
191
|
+
2. Generate **JWT API credentials** (issuer + secret) from the developer hub.
|
|
192
|
+
3. The extension ID is already set in `extension/manifest.firefox.json`: `dimension-shop-browser@dimensionstudios.co`.
|
|
193
|
+
|
|
194
|
+
#### GitHub secrets (repository)
|
|
195
|
+
|
|
196
|
+
| Secret | Description |
|
|
197
|
+
|--------|-------------|
|
|
198
|
+
| `SHOP_BROWSER_CHROME_EXTENSION_ID` | Chrome extension ID (32-char string) |
|
|
199
|
+
| `SHOP_BROWSER_CHROME_PUBLISHER_ID` | Chrome Web Store publisher ID |
|
|
200
|
+
| `SHOP_BROWSER_CHROME_CLIENT_ID` | Google OAuth client ID |
|
|
201
|
+
| `SHOP_BROWSER_CHROME_CLIENT_SECRET` | Google OAuth client secret (store **base64-encoded** in GitHub; decoded at publish time) |
|
|
202
|
+
| `SHOP_BROWSER_CHROME_REFRESH_TOKEN` | Google OAuth refresh token |
|
|
203
|
+
| `SHOP_BROWSER_AMO_JWT_ISSUER` | AMO JWT issuer (`user:…`) |
|
|
204
|
+
| `SHOP_BROWSER_AMO_JWT_SECRET` | AMO JWT secret |
|
|
205
|
+
|
|
206
|
+
If any store secret is missing, that store is skipped (release still succeeds). Both stores require all of their respective secrets to be set.
|
|
207
|
+
|
|
208
|
+
#### Manual store publish (local)
|
|
209
|
+
|
|
210
|
+
After building with production `NEXT_PUBLIC_APP_URL`:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
export NEXT_PUBLIC_APP_URL=https://app.dimensionstudios.co
|
|
214
|
+
npm run build:extension -w @dimension-studios/shop-browser
|
|
215
|
+
|
|
216
|
+
# Set the same SHOP_BROWSER_* secrets as in GitHub, then:
|
|
217
|
+
npm run publish:stores -w @dimension-studios/shop-browser
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
New versions enter each store’s review queue after submission; approval is handled by Google/Mozilla.
|
|
221
|
+
|
|
84
222
|
## Development (in this monorepo)
|
|
85
223
|
|
|
86
224
|
```bash
|
|
87
225
|
npm install
|
|
88
226
|
npm run build -w @dimension-studios/shop-browser
|
|
227
|
+
npm run build:extension -w @dimension-studios/shop-browser
|
|
89
228
|
npm run type-check -w @dimension-studios/shop-browser
|
|
90
229
|
```
|
|
91
230
|
|
|
92
|
-
Run from source (expects env via `dotenv` / linked root `.env`):
|
|
231
|
+
Run CLI from source (expects env via `dotenv` / linked root `.env`):
|
|
93
232
|
|
|
94
233
|
```bash
|
|
95
234
|
npm run start -w @dimension-studios/shop-browser
|
|
@@ -97,6 +236,14 @@ npm run start -w @dimension-studios/shop-browser
|
|
|
97
236
|
npm run tools:isb
|
|
98
237
|
```
|
|
99
238
|
|
|
239
|
+
Rebuild the extension after popup/background changes:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
npm run dev:extension -w @dimension-studios/shop-browser
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Then reload the unpacked extension in your browser.
|
|
246
|
+
|
|
100
247
|
## Related packages
|
|
101
248
|
|
|
102
249
|
- **`@dimension-studios/ttk-proxy`** — call TTK proxy APIs from the terminal, including `ttk-proxy shops <query>` for debugging shop search.
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync as e}from"node:fs";import{dirname as t,join as n}from"node:path";import{fileURLToPath as r}from"node:url";import{logger as i}from"@rharkor/logger";import{program as a}from"commander";import"dotenv/config";import o from"conf";import{setTimeout as s}from"node:timers/promises";import{Separator as c,search as l,select as u}from"@inquirer/prompts";import{chromium as d}from"playwright";const f=new o({projectName:`dimension-shop-browser`});function
|
|
3
|
-
Received SIGINT. Closing browser...`),r.close()}),await new Promise(e=>r.on(`disconnected`,e)),console.warn(`Browser closed by user. Exiting...`),process.exit(0)}const
|
|
2
|
+
import{readFileSync as e}from"node:fs";import{dirname as t,join as n}from"node:path";import{fileURLToPath as r}from"node:url";import{logger as i}from"@rharkor/logger";import{program as a}from"commander";import"dotenv/config";import o from"conf";import{setTimeout as s}from"node:timers/promises";import{Separator as c,search as l,select as u}from"@inquirer/prompts";import{chromium as d}from"playwright";const f=[{id:`seller`,name:`Seller Center`,url:`https://seller-us.tiktok.com/homepage`},{id:`affiliate`,name:`Affiliate Center`,url:`https://affiliate-us.tiktok.com`},{id:`support`,name:`Support Messages`,url:`https://seller-us.tiktok.com/chat/inbox/current`}];typeof __APP_API_ORIGIN__==`string`&&__APP_API_ORIGIN__.length>0&&__APP_API_ORIGIN__;function p(e){return e.replace(/\/+$/,``)}const m=new o({projectName:`dimension-shop-browser`});function h(){let e=m.get(`apiUrl`),t=m.get(`apiKey`),n=m.get(`apiSecret`);if(!e||!t||!n)throw Error("Missing API configuration. Run `shop-browser config` or set TTK_FETCH_API_URL, TTK_FETCH_API_KEY, and TTK_FETCH_API_SECRET.");return{apiUrl:p(e),apiKey:t,apiSecret:n}}function g(e){e.apiUrl&&m.set(`apiUrl`,p(e.apiUrl)),e.apiKey&&m.set(`apiKey`,e.apiKey),e.apiSecret&&m.set(`apiSecret`,e.apiSecret)}function _(){let e=process.env.TTK_FETCH_API_URL,t=process.env.TTK_FETCH_API_KEY,n=process.env.TTK_FETCH_API_SECRET;e&&m.set(`apiUrl`,p(e)),t&&m.set(`apiKey`,t),n&&m.set(`apiSecret`,n)}function v(e){try{if(e.clear){m.clear(),i.success(`✅ Configuration cleared`);return}if(e.show){let e=m.store;i.info(`📋 Current configuration:`),console.log(JSON.stringify(e,null,2));return}_();let t=m.get(`apiUrl`),n=m.get(`apiKey`),r=m.get(`apiSecret`);(!t||!n||!r)&&(i.error(`❌ Missing configuration`),i.info(`Please set the following environment variables:`),i.info(` - TTK_FETCH_API_URL`),i.info(` - TTK_FETCH_API_KEY`),i.info(` - TTK_FETCH_API_SECRET`),i.info(`Or manually set them using:`),i.info(` shop-browser config:set apiUrl "your-url"`),i.info(` shop-browser config:set apiKey "your-key"`),i.info(` shop-browser config:set apiSecret "your-secret"`),process.exit(1));let a=t,o=n,s=r;i.success(`✅ Configuration loaded successfully`),i.info(`📋 Current configuration:`),i.info(` API URL: ${a}`),i.info(` API Key: ${o}`),i.info(` API Secret: ${c(s)}`);function c(e){return!e||e.length<8?`*`.repeat(e.length):`${e.slice(0,4)}${`*`.repeat(e.length-8)}${e.slice(-4)}`}}catch(e){i.error(`❌ Failed to manage configuration`),e instanceof Error?i.error(e.message):i.error(String(e)),process.exit(1)}}function y(e,t){try{[`apiUrl`,`apiKey`,`apiSecret`].includes(e)||(i.error(`❌ Invalid config key: ${e}`),i.info(`Valid keys: apiUrl, apiKey, apiSecret`),process.exit(1)),g({[e]:t}),i.success(`✅ Set ${e} successfully`)}catch(e){i.error(`❌ Failed to set configuration`),e instanceof Error?i.error(e.message):i.error(String(e)),process.exit(1)}}function b(e){return{"X-Api-Key":e.apiKey,"X-Api-Secret":e.apiSecret}}function x(e){return p(e.apiUrl)}async function S(e,t){let n=new URLSearchParams({q:t.trim()}),r=x(e),i=await fetch(`${r}/ttk-proxy/shops/search?${n}`,{method:`GET`,headers:b(e),signal:AbortSignal.timeout(15e3)});if(!i.ok){let e=await i.text();throw Error(`Shop search failed (${i.status}): ${e||i.statusText}`)}return(await i.json()).shops}async function C(e,t){let n=x(e),r=await fetch(`${n}/ttk-proxy/get-cookies`,{method:`POST`,headers:{"Content-Type":`application/json`,...b(e)},body:JSON.stringify({shopId:t}),signal:AbortSignal.timeout(15e3)});if(!r.ok){let e=await r.text();throw Error(`Could not fetch cookies (${r.status}): ${e||r.statusText}`)}return(await r.json()).cookies??[]}async function w(e){return S(h(),e)}async function T(e){return C(h(),e)}function E(){h()}function D(){let e=process.env.HEADLESS?.toLowerCase();return e===`true`||e===`1`}function O(){let e=process.env.EXECUTABLE_PATH?.trim();return e?.length?e:void 0}async function k(){E();let e=await T((await l({message:`Select a shop:`,source:async(e,{signal:t})=>{let n=e?.trim();if(t.aborted||!n)return[];if(n.length<2)return[new c(`Enter at least 2 characters to search`)];await s(300);let r=await w(n).catch(e=>(console.error(e instanceof Error?e.message:e),[]));return t.aborted?[]:r.length===0?[new c(`No shops found — try another search`)]:r.map(e=>({name:`${e.name} (${e.slug})`,value:{id:e.id,slug:e.slug,name:e.name}}))}})).id);if(!Array.isArray(e)||e.length===0)throw Error(`No cookies returned for this shop. Check TTK proxy access for this shop.`);let t=e,n=await u({message:`Select the page you want to navigate to:`,choices:f.map(e=>({name:e.name,value:e.url}))}),r=await d.launch({headless:D(),executablePath:O(),args:[`--no-sandbox`,`--disable-setuid-sandbox`,`--disable-popup-blocking`,`--disable-external-protocol-handling`]}),i=await r.newContext({viewport:null});await i.addCookies(t);let a=await i.newPage();await a.goto(n),console.warn(`Browser opened. Close the browser window to end the process.`),a.on(`close`,()=>r.close()),process.on(`SIGINT`,()=>{console.warn(`
|
|
3
|
+
Received SIGINT. Closing browser...`),r.close()}),await new Promise(e=>r.on(`disconnected`,e)),console.warn(`Browser closed by user. Exiting...`),process.exit(0)}const A=n(t(r(import.meta.url)),`..`,`package.json`),j=JSON.parse(e(A,`utf8`));await i.init(),_(),a.name(`shop-browser`).description(`Open TikTok shop pages using TTK proxy cookies`).version(j.version),a.command(`config`).description(`Manage TTK Fetch API credentials`).option(`-s, --show`,`Show current configuration`).option(`-c, --clear`,`Clear all configuration`).action(e=>{v(e)}),a.command(`config:set`).description(`Set a configuration value`).argument(`<key>`,`Configuration key (apiUrl, apiKey, apiSecret)`).argument(`<value>`,`Configuration value`).action((e,t)=>{y(e,t)});const M=process.argv.slice(2),N=M[0];if(M.length===0)try{await k()}catch(e){i.error(e instanceof Error?e.message:String(e)),process.exit(1)}else N===`config`||N===`config:set`?a.parse(process.argv):N===`-h`||N===`--help`?(i.info(`\n${a.helpInformation()}`),i.info(`Run "${a.name()}" with no arguments to search for a shop and open Chromium with cookies.\n`)):N===`-V`||N===`--version`?i.info(j.version):(i.error(`Unknown argument: ${N??``}`),process.exit(1));export{};
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dimension-studios/shop-browser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.141.0",
|
|
4
4
|
"description": "Open TikTok shop pages in Chromium using TTK proxy cookies",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tiktok",
|
|
7
7
|
"shop",
|
|
8
8
|
"browser",
|
|
9
9
|
"playwright",
|
|
10
|
-
"cli"
|
|
10
|
+
"cli",
|
|
11
|
+
"extension"
|
|
11
12
|
],
|
|
12
13
|
"author": "Dimension Studios",
|
|
13
14
|
"license": "ISC",
|
|
@@ -35,12 +36,16 @@
|
|
|
35
36
|
}
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
|
-
"build": "
|
|
39
|
+
"build": "npm run build:cli && npm run build:extension",
|
|
40
|
+
"build:cli": "tsdown && chmod +x bin/cli.js",
|
|
41
|
+
"build:extension": "node scripts/build-extension.mjs",
|
|
42
|
+
"publish:stores": "node scripts/publish-extension-stores.mjs",
|
|
39
43
|
"clean": "rm -rf dist",
|
|
40
44
|
"dev": "tsdown --watch",
|
|
45
|
+
"dev:extension": "node scripts/build-extension.mjs",
|
|
41
46
|
"start": "dotenv -- tsx src/index.ts",
|
|
42
|
-
"type-check": "tsgo --noEmit",
|
|
43
|
-
"prepublishOnly": "npm run build"
|
|
47
|
+
"type-check": "tsgo --noEmit && tsgo --noEmit -p tsconfig.extension.json",
|
|
48
|
+
"prepublishOnly": "npm run build:cli"
|
|
44
49
|
},
|
|
45
50
|
"dependencies": {
|
|
46
51
|
"@rharkor/logger": "1.3.3",
|
|
@@ -54,7 +59,8 @@
|
|
|
54
59
|
"devDependencies": {
|
|
55
60
|
"@types/node": "24.12.4",
|
|
56
61
|
"dotenv-cli": "11.0.0",
|
|
57
|
-
"tsx": "4.22.
|
|
58
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
62
|
+
"tsx": "4.22.3",
|
|
63
|
+
"@typescript/native-preview": "7.0.0-dev.20260519.1",
|
|
64
|
+
"vite": "8.0.13"
|
|
59
65
|
}
|
|
60
66
|
}
|