@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.
Files changed (3) hide show
  1. package/README.md +29 -29
  2. package/dist/index.mjs +1 -1
  3. 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 | 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. |
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 packages/shop-browser build:extension
120
+ bun run --cwd tools/shop-browser build:extension
121
121
  ```
122
122
 
123
123
  This produces:
124
124
 
125
- - `packages/shop-browser/dist/extension/chrome` — unpacked Chrome extension
126
- - `packages/shop-browser/dist/extension/firefox` — unpacked Firefox extension (for debugging)
127
- - `packages/shop-browser/dist/extension/dimension-shop-browser.xpi` — Firefox add-on file
128
- - `packages/shop-browser/dist/extension/dimension-shop-browser-chrome.zip` — zipped Chrome extension
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 `packages/shop-browser/dist/extension/chrome`
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 `packages/shop-browser/dist/extension/dimension-shop-browser.xpi`
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 `packages/shop-browser/dist/extension/firefox/manifest.json`
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 `packages/shop-browser/.env` (`NEXT_PUBLIC_APP_URL`, or `TTK_FETCH_API_URL` as fallback).
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 packages/shop-browser build:extension` on every pull request (`.github/workflows/check.yml`) to catch build regressions early.
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 | 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 |
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` | AMO JWT issuer (`user:…`) |
231
- | `SHOP_BROWSER_AMO_JWT_SECRET` | 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 packages/shop-browser build:extension
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 packages/shop-browser publish:stores
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 packages/shop-browser build
254
- bun run --cwd packages/shop-browser build:extension
255
- bun run --cwd packages/shop-browser type-check
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 packages/shop-browser start
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 packages/shop-browser dev:extension
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.length===0||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).
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.202.0",
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": "packages/shop-browser"
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": "tsc --noEmit && tsc --noEmit -p tsconfig.extension.json",
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
  }