@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.
Files changed (3) hide show
  1. package/README.md +150 -3
  2. package/dist/index.mjs +2 -2
  3. 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, open **Chromium** with Playwright, and navigate to common TikTok Seller / Affiliate URLs.
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
- ## Usage
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 p(){let e=f.get(`apiUrl`),t=f.get(`apiKey`),n=f.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:e,apiKey:t,apiSecret:n}}function m(e){e.apiUrl&&f.set(`apiUrl`,e.apiUrl),e.apiKey&&f.set(`apiKey`,e.apiKey),e.apiSecret&&f.set(`apiSecret`,e.apiSecret)}function h(){let e=process.env.TTK_FETCH_API_URL,t=process.env.TTK_FETCH_API_KEY,n=process.env.TTK_FETCH_API_SECRET;e&&f.set(`apiUrl`,e),t&&f.set(`apiKey`,t),n&&f.set(`apiSecret`,n)}function g(e){try{if(e.clear){f.clear(),i.success(`✅ Configuration cleared`);return}if(e.show){let e=f.store;i.info(`📋 Current configuration:`),console.log(JSON.stringify(e,null,2));return}h();let t=f.get(`apiUrl`),n=f.get(`apiKey`),r=f.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 _(e,t){try{[`apiUrl`,`apiKey`,`apiSecret`].includes(e)||(i.error(`❌ Invalid config key: ${e}`),i.info(`Valid keys: apiUrl, apiKey, apiSecret`),process.exit(1)),m({[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 v(e){let{apiUrl:t,apiKey:n,apiSecret:r}=p(),i=new URLSearchParams({q:e.trim()}),a=await fetch(`${t}/ttk-proxy/shops/search?${i}`,{method:`GET`,headers:{"X-Api-Key":n,"X-Api-Secret":r},signal:AbortSignal.timeout(15e3)});if(!a.ok){let e=await a.text();throw Error(`Shop search failed (${a.status}): ${e||a.statusText}`)}return(await a.json()).shops}async function y(e){let{apiUrl:t,apiKey:n,apiSecret:r}=p(),i=await fetch(`${t}/ttk-proxy/get-cookies`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Api-Key":n,"X-Api-Secret":r},body:JSON.stringify({shopId:e}),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??[]}const b=[{name:`TikTok Seller Center`,value:`https://seller-us.tiktok.com/homepage`},{name:`TikTok Affiliate Center`,value:`https://affiliate-us.tiktok.com`},{name:`TikTok Support Messages`,value:`https://seller-us.tiktok.com/chat/inbox/current`}];function x(){p()}function S(){let e=process.env.HEADLESS?.toLowerCase();return e===`true`||e===`1`}function C(){let e=process.env.EXECUTABLE_PATH?.trim();return e?.length?e:void 0}async function w(){x();let e=await y((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 v(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:[...b]}),r=await d.launch({headless:S(),executablePath:C(),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 T=n(t(r(import.meta.url)),`..`,`package.json`),E=JSON.parse(e(T,`utf8`));await i.init(),h(),a.name(`shop-browser`).description(`Open TikTok shop pages using TTK proxy cookies`).version(E.version),a.command(`config`).description(`Manage TTK Fetch API credentials`).option(`-s, --show`,`Show current configuration`).option(`-c, --clear`,`Clear all configuration`).action(e=>{g(e)}),a.command(`config:set`).description(`Set a configuration value`).argument(`<key>`,`Configuration key (apiUrl, apiKey, apiSecret)`).argument(`<value>`,`Configuration value`).action((e,t)=>{_(e,t)});const D=process.argv.slice(2),O=D[0];if(D.length===0)try{await w()}catch(e){i.error(e instanceof Error?e.message:String(e)),process.exit(1)}else O===`config`||O===`config:set`?a.parse(process.argv):O===`-h`||O===`--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`)):O===`-V`||O===`--version`?i.info(E.version):(i.error(`Unknown argument: ${O??``}`),process.exit(1));export{};
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.140.3",
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": "tsdown && chmod +x bin/cli.js",
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.0",
58
- "@typescript/native-preview": "7.0.0-dev.20260513.1"
62
+ "tsx": "4.22.3",
63
+ "@typescript/native-preview": "7.0.0-dev.20260519.1",
64
+ "vite": "8.0.13"
59
65
  }
60
66
  }