@dimension-studios/shop-browser 1.202.0 → 1.203.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 +29 -29
- package/dist/index.mjs +1 -1
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -72,10 +72,10 @@ shop-browser --allow-invalid
|
|
|
72
72
|
|
|
73
73
|
### Optional environment
|
|
74
74
|
|
|
75
|
-
| Variable
|
|
76
|
-
|
|
77
|
-
| `HEADLESS`
|
|
78
|
-
| `EXECUTABLE_PATH`
|
|
75
|
+
| Variable | Purpose |
|
|
76
|
+
| ----------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `HEADLESS` | If `true` or `1`, runs Playwright headless (default: visible window). |
|
|
78
|
+
| `EXECUTABLE_PATH` | Path to Chrome/Chromium if the bundled Playwright browser is not used. |
|
|
79
79
|
| `REMOTE_DEBUGGING_PORT` | Exposes a local Chrome DevTools endpoint on `127.0.0.1:<port>` for tools such as Chrome DevTools MCP. |
|
|
80
80
|
|
|
81
81
|
Copy `.env.example` to `.env` only for local development; do not commit real secrets.
|
|
@@ -117,15 +117,15 @@ The extension injects shop cookies into your existing Chrome or Firefox browser
|
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
119
|
bun install
|
|
120
|
-
bun run --cwd
|
|
120
|
+
bun run --cwd tools/shop-browser build:extension
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
This produces:
|
|
124
124
|
|
|
125
|
-
- `
|
|
126
|
-
- `
|
|
127
|
-
- `
|
|
128
|
-
- `
|
|
125
|
+
- `tools/shop-browser/dist/extension/chrome` — unpacked Chrome extension
|
|
126
|
+
- `tools/shop-browser/dist/extension/firefox` — unpacked Firefox extension (for debugging)
|
|
127
|
+
- `tools/shop-browser/dist/extension/dimension-shop-browser.xpi` — Firefox add-on file
|
|
128
|
+
- `tools/shop-browser/dist/extension/dimension-shop-browser-chrome.zip` — zipped Chrome extension
|
|
129
129
|
|
|
130
130
|
Extension icons are copied from `extension/icons/` (exported from `apps/app/public/icons/icon.svg`).
|
|
131
131
|
|
|
@@ -134,7 +134,7 @@ Extension icons are copied from `extension/icons/` (exported from `apps/app/publ
|
|
|
134
134
|
1. Open `chrome://extensions`
|
|
135
135
|
2. Enable **Developer mode**
|
|
136
136
|
3. Click **Load unpacked**
|
|
137
|
-
4. Select `
|
|
137
|
+
4. Select `tools/shop-browser/dist/extension/chrome`
|
|
138
138
|
|
|
139
139
|
### Install in Firefox
|
|
140
140
|
|
|
@@ -149,17 +149,17 @@ Use this only on Firefox **ESR**, **Developer Edition**, **Nightly**, or other *
|
|
|
149
149
|
1. Open `about:config` and set `xpinstall.signatures.required` to `false`.
|
|
150
150
|
2. Open `about:addons`
|
|
151
151
|
3. Click the gear icon → **Install Add-on From File…**
|
|
152
|
-
4. Select `
|
|
152
|
+
4. Select `tools/shop-browser/dist/extension/dimension-shop-browser.xpi`
|
|
153
153
|
|
|
154
154
|
**Temporary install (recommended for standard Firefox; removed on restart):**
|
|
155
155
|
|
|
156
156
|
1. Open `about:debugging#/runtime/this-firefox`
|
|
157
157
|
2. Click **Load Temporary Add-on**
|
|
158
|
-
3. Select `
|
|
158
|
+
3. Select `tools/shop-browser/dist/extension/firefox/manifest.json`
|
|
159
159
|
|
|
160
160
|
### Extension usage
|
|
161
161
|
|
|
162
|
-
1. Build the extension with the app origin from `
|
|
162
|
+
1. Build the extension with the app origin from `tools/shop-browser/.env` (`NEXT_PUBLIC_APP_URL`, or `TTK_FETCH_API_URL` as fallback).
|
|
163
163
|
2. Open the extension popup and click **Sign in to Dimension** if you are not already signed in on `app.dimensionstudios.co`.
|
|
164
164
|
3. Search for a shop (minimum **2 characters**) and select it. Results are limited to shops you can access in your current organization.
|
|
165
165
|
4. Turn **Auto inject** on to inject cookies when you open TikTok domains, or use **Inject now** manually.
|
|
@@ -194,7 +194,7 @@ The extension is built and published automatically when `@dimension-studios/shop
|
|
|
194
194
|
3. **Firefox:** install the XPI (signed AMO distribution still requires a separate Mozilla submission).
|
|
195
195
|
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.
|
|
196
196
|
|
|
197
|
-
CI also runs `bun run --cwd
|
|
197
|
+
CI also runs `bun run --cwd tools/shop-browser build:extension` on every pull request (`.github/workflows/check.yml`) to catch build regressions early.
|
|
198
198
|
|
|
199
199
|
### Automatic store listing (Chrome + Firefox)
|
|
200
200
|
|
|
@@ -220,15 +220,15 @@ On **`main-release`** only, after a successful semantic-release, CI submits the
|
|
|
220
220
|
|
|
221
221
|
#### GitHub secrets (repository)
|
|
222
222
|
|
|
223
|
-
| Secret
|
|
224
|
-
|
|
225
|
-
| `SHOP_BROWSER_CHROME_EXTENSION_ID`
|
|
226
|
-
| `SHOP_BROWSER_CHROME_PUBLISHER_ID`
|
|
227
|
-
| `SHOP_BROWSER_CHROME_CLIENT_ID`
|
|
223
|
+
| Secret | Description |
|
|
224
|
+
| ----------------------------------- | --------------------------------------------------------------------- |
|
|
225
|
+
| `SHOP_BROWSER_CHROME_EXTENSION_ID` | Chrome extension ID (32-char string) |
|
|
226
|
+
| `SHOP_BROWSER_CHROME_PUBLISHER_ID` | Chrome Web Store publisher ID |
|
|
227
|
+
| `SHOP_BROWSER_CHROME_CLIENT_ID` | Google OAuth client ID |
|
|
228
228
|
| `SHOP_BROWSER_CHROME_CLIENT_SECRET` | Google OAuth client secret (plain `GOCSPX-…` value from Google Cloud) |
|
|
229
|
-
| `SHOP_BROWSER_CHROME_REFRESH_TOKEN` | Google OAuth refresh token
|
|
230
|
-
| `SHOP_BROWSER_AMO_JWT_ISSUER`
|
|
231
|
-
| `SHOP_BROWSER_AMO_JWT_SECRET`
|
|
229
|
+
| `SHOP_BROWSER_CHROME_REFRESH_TOKEN` | Google OAuth refresh token |
|
|
230
|
+
| `SHOP_BROWSER_AMO_JWT_ISSUER` | AMO JWT issuer (`user:…`) |
|
|
231
|
+
| `SHOP_BROWSER_AMO_JWT_SECRET` | AMO JWT secret |
|
|
232
232
|
|
|
233
233
|
If any store secret is missing, that store is skipped (release still succeeds). Both stores require all of their respective secrets to be set.
|
|
234
234
|
|
|
@@ -238,10 +238,10 @@ After building with production `NEXT_PUBLIC_APP_URL`:
|
|
|
238
238
|
|
|
239
239
|
```bash
|
|
240
240
|
export NEXT_PUBLIC_APP_URL=https://app.dimensionstudios.co
|
|
241
|
-
bun run --cwd
|
|
241
|
+
bun run --cwd tools/shop-browser build:extension
|
|
242
242
|
|
|
243
243
|
# Set the same SHOP_BROWSER_* secrets as in GitHub, then:
|
|
244
|
-
bun run --cwd
|
|
244
|
+
bun run --cwd tools/shop-browser publish:stores
|
|
245
245
|
```
|
|
246
246
|
|
|
247
247
|
New versions enter each store’s review queue after submission; approval is handled by Google/Mozilla.
|
|
@@ -250,15 +250,15 @@ New versions enter each store’s review queue after submission; approval is han
|
|
|
250
250
|
|
|
251
251
|
```bash
|
|
252
252
|
bun install
|
|
253
|
-
bun run --cwd
|
|
254
|
-
bun run --cwd
|
|
255
|
-
bun run --cwd
|
|
253
|
+
bun run --cwd tools/shop-browser build
|
|
254
|
+
bun run --cwd tools/shop-browser build:extension
|
|
255
|
+
bun run --cwd tools/shop-browser type-check
|
|
256
256
|
```
|
|
257
257
|
|
|
258
258
|
Run CLI from source (expects env via `dotenv` / linked root `.env`):
|
|
259
259
|
|
|
260
260
|
```bash
|
|
261
|
-
bun run --cwd
|
|
261
|
+
bun run --cwd tools/shop-browser start
|
|
262
262
|
# or from repo root:
|
|
263
263
|
bun run tools:isb
|
|
264
264
|
```
|
|
@@ -266,7 +266,7 @@ bun run tools:isb
|
|
|
266
266
|
Rebuild the extension after popup/background changes:
|
|
267
267
|
|
|
268
268
|
```bash
|
|
269
|
-
bun run --cwd
|
|
269
|
+
bun run --cwd tools/shop-browser dev:extension
|
|
270
270
|
```
|
|
271
271
|
|
|
272
272
|
Then reload the unpacked extension in your browser.
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
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";import{mkdir as f,mkdtemp as p,rm as m,writeFile as h}from"node:fs/promises";import{tmpdir as g}from"node:os";const _=[{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 v(e){return e.replace(/\/+$/,``)}const y=new o({projectName:`dimension-shop-browser`});function b(){let e=y.get(`apiUrl`),t=y.get(`apiKey`),n=y.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:v(e),apiKey:t,apiSecret:n}}function x(e){e.apiUrl&&y.set(`apiUrl`,v(e.apiUrl)),e.apiKey&&y.set(`apiKey`,e.apiKey),e.apiSecret&&y.set(`apiSecret`,e.apiSecret)}function S(){let e=process.env.TTK_FETCH_API_URL,t=process.env.TTK_FETCH_API_KEY,n=process.env.TTK_FETCH_API_SECRET;e&&y.set(`apiUrl`,v(e)),t&&y.set(`apiKey`,t),n&&y.set(`apiSecret`,n)}function C(e){try{if(e.clear){y.clear(),i.success(`✅ Configuration cleared`);return}if(e.show){let e=y.store;i.info(`📋 Current configuration:`),console.log(JSON.stringify(e,null,2));return}S();let t=y.get(`apiUrl`),n=y.get(`apiKey`),r=y.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 w(e,t){try{[`apiUrl`,`apiKey`,`apiSecret`].includes(e)||(i.error(`❌ Invalid config key: ${e}`),i.info(`Valid keys: apiUrl, apiKey, apiSecret`),process.exit(1)),x({[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)}}async function T(){let e=await p(n(g(),`shop-browser-`)),t=n(e,`Default`);await f(t,{recursive:!0});let r={roots:{bookmark_bar:{children:_.map(e=>({name:e.name,type:`url`,url:e.url})),name:`Bookmarks bar`,type:`folder`},other:{children:[],name:`Other bookmarks`,type:`folder`},synced:{children:[],name:`Mobile bookmarks`,type:`folder`}},version:1};return await h(n(t,`Bookmarks`),JSON.stringify(r)),await h(n(t,`Preferences`),JSON.stringify({bookmark_bar:{show_on_all_tabs:!0},browser:{check_default_browser:!1}})),{userDataDir:e,cleanup:()=>m(e,{recursive:!0,force:!0})}}function E(e){return{"X-Api-Key":e.apiKey,"X-Api-Secret":e.apiSecret}}function D(e){return v(e.apiUrl)}async function O(e,t){let n=new URLSearchParams({q:t.trim()}),r=D(e),i=await fetch(`${r}/ttk-proxy/shops/search?${n}`,{method:`GET`,headers:E(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 k(e,t,{allowInvalid:n=!1}={}){let r=D(e),i=await fetch(`${r}/ttk-proxy/get-cookies`,{method:`POST`,headers:{"Content-Type":`application/json`,...E(e)},body:JSON.stringify({shopId:t,allowInvalid:n}),signal:AbortSignal.timeout(15e3)});if(!i.ok){let e=await i.text();throw Error(`Could not fetch cookies (${i.status}): ${e||i.statusText}`)}return(await i.json()).cookies}async function A(e){return O(b(),e)}async function j(e,t){return k(b(),e,t)}function M(){b()}function N(){let e=process.env.HEADLESS?.toLowerCase();return e===`true`||e===`1`}function P(){let e=process.env.EXECUTABLE_PATH?.trim();return e?.length?e:void 0}function F(){let e=process.env.REMOTE_DEBUGGING_PORT?.trim();return e?.length?e:void 0}async function I({allowInvalid:e=!1}={}){M();let t=await j((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 A(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,{allowInvalid:e});if(!Array.isArray(t)||t.length===0)throw Error(`No cookies returned for this shop. Check TTK proxy access for this shop.`);e&&console.warn(`Using the stored cookie even if it is no longer marked valid — TikTok may ask you to log in again.`);let n=t,r=await u({message:`Select the page you want to navigate to:`,choices:_.map(e=>({name:e.name,value:e.url}))}),i=F(),{userDataDir:a,cleanup:o}=await T(),f;try{f=await d.launchPersistentContext(a,{headless:N(),executablePath:P(),viewport:null,args:[`--no-sandbox`,`--disable-setuid-sandbox`,`--disable-popup-blocking`,`--disable-external-protocol-handling`,`--no-first-run`,...i?[`--remote-debugging-port=${i}`]:[]]}),await f.addCookies(n);let e=f.pages()[0]??await f.newPage();await e.goto(r),console.warn(`Browser opened. Use the bookmark bar to switch TikTok pages. Close the window to exit.`),i&&console.warn(`DevTools endpoint: http://127.0.0.1:${i}`),e.on(`close`,()=>{f?.close()}),process.on(`SIGINT`,()=>{console.warn(`
|
|
3
|
-
Received SIGINT. Closing browser...`),f?.close()});let t=f.browser();t?await new Promise(e=>t.on(`disconnected`,()=>e())):await e.waitForEvent(`close`)}finally{await f?.close().catch(()=>{}),await o().catch(()=>{})}console.warn(`Browser closed by user. Exiting...`),process.exit(0)}const L=n(t(r(import.meta.url)),`..`,`package.json`),R=JSON.parse(e(L,`utf8`));await i.init(),S(),a.name(`shop-browser`).description(`Open TikTok shop pages using TTK proxy cookies`).version(R.version),a.command(`config`).description(`Manage TTK Fetch API credentials`).option(`-s, --show`,`Show current configuration`).option(`-c, --clear`,`Clear all configuration`).action(e=>{C(e)}),a.command(`config:set`).description(`Set a configuration value`).argument(`<key>`,`Configuration key (apiUrl, apiKey, apiSecret)`).argument(`<value>`,`Configuration value`).action((e,t)=>{w(e,t)});const z=process.argv.slice(2),B=z[0],V=new Set([`-i`,`--allow-invalid`]);if(z.
|
|
3
|
+
Received SIGINT. Closing browser...`),f?.close()});let t=f.browser();t?await new Promise(e=>t.on(`disconnected`,()=>e())):await e.waitForEvent(`close`)}finally{await f?.close().catch(()=>{}),await o().catch(()=>{})}console.warn(`Browser closed by user. Exiting...`),process.exit(0)}const L=n(t(r(import.meta.url)),`..`,`package.json`),R=JSON.parse(e(L,`utf8`));await i.init(),S(),a.name(`shop-browser`).description(`Open TikTok shop pages using TTK proxy cookies`).version(R.version),a.command(`config`).description(`Manage TTK Fetch API credentials`).option(`-s, --show`,`Show current configuration`).option(`-c, --clear`,`Clear all configuration`).action(e=>{C(e)}),a.command(`config:set`).description(`Set a configuration value`).argument(`<key>`,`Configuration key (apiUrl, apiKey, apiSecret)`).argument(`<value>`,`Configuration value`).action((e,t)=>{w(e,t)});const z=process.argv.slice(2),B=z[0],V=new Set([`-i`,`--allow-invalid`]);if(z.every(e=>V.has(e)))try{await I({allowInvalid:z.length>0})}catch(e){i.error(e instanceof Error?e.message:String(e)),process.exit(1)}else B===`config`||B===`config:set`?a.parse(process.argv):B===`-h`||B===`--help`?(i.info(`\n${a.helpInformation()}`),i.info(`Run "${a.name()}" with no arguments to search for a shop and open Chromium with cookies.`),i.info(`Add "-i, --allow-invalid" to open a shop whose stored cookie is no longer marked valid (disabled shop, expired login).
|
|
4
4
|
`)):B===`-V`||B===`--version`?i.info(R.version):(i.error(`Unknown argument: ${B??``}`),process.exit(1));export{};
|
package/package.json
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dimension-studios/shop-browser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.203.0",
|
|
4
4
|
"description": "Open TikTok shop pages in Chromium using TTK proxy cookies",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"tiktok",
|
|
7
|
-
"shop",
|
|
8
6
|
"browser",
|
|
9
|
-
"playwright",
|
|
10
7
|
"cli",
|
|
11
|
-
"extension"
|
|
8
|
+
"extension",
|
|
9
|
+
"playwright",
|
|
10
|
+
"shop",
|
|
11
|
+
"tiktok"
|
|
12
12
|
],
|
|
13
|
-
"author": "Dimension Studios",
|
|
14
13
|
"license": "ISC",
|
|
14
|
+
"author": "Dimension Studios",
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
17
|
"url": "git+https://github.com/dimension-studios-inc/dimension.git",
|
|
18
|
-
"directory": "
|
|
19
|
-
},
|
|
20
|
-
"publishConfig": {
|
|
21
|
-
"access": "public"
|
|
18
|
+
"directory": "tools/shop-browser"
|
|
22
19
|
},
|
|
23
|
-
"type": "module",
|
|
24
20
|
"bin": {
|
|
25
21
|
"shop-browser": "bin/cli.js"
|
|
26
22
|
},
|
|
@@ -29,6 +25,7 @@
|
|
|
29
25
|
"bin",
|
|
30
26
|
"README.md"
|
|
31
27
|
],
|
|
28
|
+
"type": "module",
|
|
32
29
|
"exports": {
|
|
33
30
|
".": {
|
|
34
31
|
"types": "./dist/index.d.mts",
|
|
@@ -39,6 +36,9 @@
|
|
|
39
36
|
"import": "./dist/shared/tiktok-url.mjs"
|
|
40
37
|
}
|
|
41
38
|
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "bun run build:cli && bun run build:extension",
|
|
44
44
|
"build:cli": "tsdown && chmod +x bin/cli.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dev": "tsdown --watch",
|
|
49
49
|
"dev:extension": "node scripts/build-extension.mjs",
|
|
50
50
|
"start": "bun src/index.ts",
|
|
51
|
-
"type-check": "
|
|
51
|
+
"type-check": "bun check && bun check -p tsconfig.extension.json",
|
|
52
52
|
"prepublishOnly": "bun run build:cli"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@types/node": "24.13.6",
|
|
65
65
|
"@types/webextension-polyfill": "0.12.6",
|
|
66
|
+
"tsdown": "0.23.0",
|
|
66
67
|
"typescript": "7.0.2",
|
|
67
|
-
"vite": "8.3.1"
|
|
68
|
-
"tsdown": "0.23.0"
|
|
68
|
+
"vite": "8.3.1"
|
|
69
69
|
}
|
|
70
70
|
}
|