mirror of
https://github.com/avinal/sciezka.git
synced 2026-07-03 23:30:09 +05:30
feat: project infrastructure and MV3 extension setup
TypeScript + esbuild build system, Manifest V3 with background script, content script for iframe overlay injection, and typed message contracts between extension contexts. Assisted-by: Claude Code Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import * as esbuild from "esbuild";
|
||||
|
||||
const watch = process.argv.includes("--watch");
|
||||
|
||||
const options = {
|
||||
entryPoints: [
|
||||
"src/background.ts",
|
||||
"src/content.ts",
|
||||
"src/sciezka.ts",
|
||||
],
|
||||
bundle: true,
|
||||
outdir: "dist",
|
||||
format: "iife",
|
||||
target: "es2020",
|
||||
sourcemap: watch,
|
||||
};
|
||||
|
||||
if (watch) {
|
||||
const ctx = await esbuild.context(options);
|
||||
await ctx.watch();
|
||||
console.log("Watching for changes...");
|
||||
} else {
|
||||
await esbuild.build(options);
|
||||
console.log("Build complete.");
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Sciezka",
|
||||
"version": "0.1.0",
|
||||
"description": "A browser extension to fuzzy search tabs, history and bookmarks.",
|
||||
"icons": {
|
||||
"48": "icons/border-48.png"
|
||||
},
|
||||
"permissions": [
|
||||
"tabs",
|
||||
"history",
|
||||
"bookmarks",
|
||||
"sessions",
|
||||
"storage"
|
||||
],
|
||||
"background": {
|
||||
"scripts": ["dist/background.js"]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["dist/content.js"],
|
||||
"run_at": "document_idle"
|
||||
}
|
||||
],
|
||||
"commands": {
|
||||
"toggle-sciezka": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+K"
|
||||
},
|
||||
"description": "Toggle Sciezka search"
|
||||
}
|
||||
},
|
||||
"options_ui": {
|
||||
"page": "options/options.html",
|
||||
"open_in_tab": true
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": ["sciezka.html", "sciezka.css", "dist/sciezka.js"],
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+486
@@ -0,0 +1,486 @@
|
||||
{
|
||||
"name": "sciezka",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sciezka",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"typescript": "^5.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
||||
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
||||
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
||||
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
||||
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
||||
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
||||
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
||||
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
||||
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
||||
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
||||
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.25.12",
|
||||
"@esbuild/android-arm": "0.25.12",
|
||||
"@esbuild/android-arm64": "0.25.12",
|
||||
"@esbuild/android-x64": "0.25.12",
|
||||
"@esbuild/darwin-arm64": "0.25.12",
|
||||
"@esbuild/darwin-x64": "0.25.12",
|
||||
"@esbuild/freebsd-arm64": "0.25.12",
|
||||
"@esbuild/freebsd-x64": "0.25.12",
|
||||
"@esbuild/linux-arm": "0.25.12",
|
||||
"@esbuild/linux-arm64": "0.25.12",
|
||||
"@esbuild/linux-ia32": "0.25.12",
|
||||
"@esbuild/linux-loong64": "0.25.12",
|
||||
"@esbuild/linux-mips64el": "0.25.12",
|
||||
"@esbuild/linux-ppc64": "0.25.12",
|
||||
"@esbuild/linux-riscv64": "0.25.12",
|
||||
"@esbuild/linux-s390x": "0.25.12",
|
||||
"@esbuild/linux-x64": "0.25.12",
|
||||
"@esbuild/netbsd-arm64": "0.25.12",
|
||||
"@esbuild/netbsd-x64": "0.25.12",
|
||||
"@esbuild/openbsd-arm64": "0.25.12",
|
||||
"@esbuild/openbsd-x64": "0.25.12",
|
||||
"@esbuild/openharmony-arm64": "0.25.12",
|
||||
"@esbuild/sunos-x64": "0.25.12",
|
||||
"@esbuild/win32-arm64": "0.25.12",
|
||||
"@esbuild/win32-ia32": "0.25.12",
|
||||
"@esbuild/win32-x64": "0.25.12"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "sciezka",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "A browser extension for fuzzy searching tabs, history and bookmarks.",
|
||||
"scripts": {
|
||||
"build": "node build.mjs",
|
||||
"watch": "node build.mjs --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"typescript": "^5.8.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import type { Message, SearchRequest, ActionRequest, SearchItem } from "./types";
|
||||
|
||||
async function getOpenTabs(): Promise<SearchItem[]> {
|
||||
const tabs = await chrome.tabs.query({});
|
||||
return tabs.map((tab) => ({
|
||||
id: `tab-${tab.id}`,
|
||||
title: tab.title ?? "",
|
||||
url: tab.url ?? "",
|
||||
type: "tabs" as const,
|
||||
favIconUrl: tab.favIconUrl,
|
||||
}));
|
||||
}
|
||||
|
||||
async function getHistory(query: string): Promise<SearchItem[]> {
|
||||
const results = await chrome.history.search({
|
||||
text: query,
|
||||
maxResults: 50,
|
||||
startTime: 0,
|
||||
});
|
||||
return results.map((item) => ({
|
||||
id: `history-${item.id}`,
|
||||
title: item.title ?? "",
|
||||
url: item.url ?? "",
|
||||
type: "history" as const,
|
||||
}));
|
||||
}
|
||||
|
||||
async function getBookmarks(query: string): Promise<SearchItem[]> {
|
||||
const results = await chrome.bookmarks.search(query || " ");
|
||||
return results
|
||||
.filter((b) => b.url)
|
||||
.map((item) => ({
|
||||
id: `bookmark-${item.id}`,
|
||||
title: item.title ?? "",
|
||||
url: item.url!,
|
||||
type: "bookmarks" as const,
|
||||
}));
|
||||
}
|
||||
|
||||
async function getRecentlyClosed(): Promise<SearchItem[]> {
|
||||
const sessions = await chrome.sessions.getRecentlyClosed({ maxResults: 25 });
|
||||
return sessions
|
||||
.filter((s) => s.tab)
|
||||
.map((session) => ({
|
||||
id: `closed-${session.tab!.sessionId}`,
|
||||
title: session.tab!.title ?? "",
|
||||
url: session.tab!.url ?? "",
|
||||
type: "closed" as const,
|
||||
favIconUrl: session.tab!.favIconUrl,
|
||||
}));
|
||||
}
|
||||
|
||||
async function handleSearch(request: SearchRequest): Promise<SearchItem[]> {
|
||||
const { query, mode } = request;
|
||||
switch (mode) {
|
||||
case "tabs":
|
||||
return getOpenTabs();
|
||||
case "history":
|
||||
return getHistory(query);
|
||||
case "bookmarks":
|
||||
return getBookmarks(query);
|
||||
case "closed":
|
||||
return getRecentlyClosed();
|
||||
case "all": {
|
||||
const [tabs, history, bookmarks, closed] = await Promise.all([
|
||||
getOpenTabs(),
|
||||
getHistory(query),
|
||||
getBookmarks(query),
|
||||
getRecentlyClosed(),
|
||||
]);
|
||||
return [...tabs, ...history, ...bookmarks, ...closed];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAction(request: ActionRequest): Promise<void> {
|
||||
const rawId = request.id.replace(/^(tab|history|bookmark|closed)-/, "");
|
||||
|
||||
switch (request.action) {
|
||||
case "switch": {
|
||||
const tabId = parseInt(rawId, 10);
|
||||
await chrome.tabs.update(tabId, { active: true });
|
||||
const tab = await chrome.tabs.get(tabId);
|
||||
if (tab.windowId != null) {
|
||||
await chrome.windows.update(tab.windowId, { focused: true });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "open": {
|
||||
if (request.newTab) {
|
||||
await chrome.tabs.create({ url: request.id });
|
||||
} else {
|
||||
const [activeTab] = await chrome.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true,
|
||||
});
|
||||
if (activeTab?.id != null) {
|
||||
await chrome.tabs.update(activeTab.id, { url: request.id });
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "close": {
|
||||
const tabId = parseInt(rawId, 10);
|
||||
await chrome.tabs.remove(tabId);
|
||||
break;
|
||||
}
|
||||
case "restore": {
|
||||
await chrome.sessions.restore(rawId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chrome.commands.onCommand.addListener(async (command) => {
|
||||
if (command === "toggle-sciezka") {
|
||||
const [tab] = await chrome.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true,
|
||||
});
|
||||
if (tab?.id != null) {
|
||||
chrome.tabs.sendMessage(tab.id, { type: "toggle" } satisfies Message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(
|
||||
(msg: unknown, _sender, sendResponse) => {
|
||||
const message = msg as Message;
|
||||
if (message.type === "search") {
|
||||
handleSearch(message).then((items) => {
|
||||
sendResponse({ type: "searchResults", results: items });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (message.type === "action") {
|
||||
handleAction(message).then(() => sendResponse({ ok: true }));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
Vendored
+78
@@ -0,0 +1,78 @@
|
||||
declare namespace chrome {
|
||||
namespace tabs {
|
||||
interface Tab {
|
||||
id?: number;
|
||||
windowId?: number;
|
||||
title?: string;
|
||||
url?: string;
|
||||
favIconUrl?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
function query(queryInfo: Record<string, unknown>): Promise<Tab[]>;
|
||||
function get(tabId: number): Promise<Tab>;
|
||||
function create(createProperties: { url?: string; active?: boolean }): Promise<Tab>;
|
||||
function update(tabId: number, updateProperties: { active?: boolean; url?: string }): Promise<Tab>;
|
||||
function remove(tabId: number | number[]): Promise<void>;
|
||||
function sendMessage(tabId: number, message: unknown): void;
|
||||
}
|
||||
|
||||
namespace windows {
|
||||
function update(windowId: number, updateInfo: { focused?: boolean }): Promise<void>;
|
||||
}
|
||||
|
||||
namespace history {
|
||||
interface HistoryItem {
|
||||
id: string;
|
||||
title?: string;
|
||||
url?: string;
|
||||
lastVisitTime?: number;
|
||||
}
|
||||
function search(query: { text: string; maxResults?: number; startTime?: number }): Promise<HistoryItem[]>;
|
||||
}
|
||||
|
||||
namespace bookmarks {
|
||||
interface BookmarkTreeNode {
|
||||
id: string;
|
||||
title: string;
|
||||
url?: string;
|
||||
children?: BookmarkTreeNode[];
|
||||
}
|
||||
function search(query: string): Promise<BookmarkTreeNode[]>;
|
||||
}
|
||||
|
||||
namespace sessions {
|
||||
interface Session {
|
||||
tab?: tabs.Tab & { sessionId?: string };
|
||||
window?: { sessionId?: string };
|
||||
}
|
||||
function getRecentlyClosed(filter?: { maxResults?: number }): Promise<Session[]>;
|
||||
function restore(sessionId: string): Promise<Session>;
|
||||
}
|
||||
|
||||
namespace commands {
|
||||
const onCommand: {
|
||||
addListener(callback: (command: string) => void): void;
|
||||
};
|
||||
}
|
||||
|
||||
namespace runtime {
|
||||
function getURL(path: string): string;
|
||||
const onMessage: {
|
||||
addListener(
|
||||
callback: (
|
||||
message: unknown,
|
||||
sender: { tab?: tabs.Tab; id?: string },
|
||||
sendResponse: (response?: unknown) => void
|
||||
) => boolean | void
|
||||
): void;
|
||||
};
|
||||
function sendMessage(message: unknown, responseCallback?: (response: unknown) => void): void;
|
||||
}
|
||||
|
||||
namespace storage {
|
||||
const sync: {
|
||||
get(keys: string | string[]): Promise<Record<string, unknown>>;
|
||||
set(items: Record<string, unknown>): Promise<void>;
|
||||
};
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
import type { Message } from "./types";
|
||||
|
||||
let overlay: HTMLDivElement | null = null;
|
||||
let iframe: HTMLIFrameElement | null = null;
|
||||
|
||||
function createOverlay(): void {
|
||||
overlay = document.createElement("div");
|
||||
overlay.id = "sciezka-overlay";
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0);
|
||||
z-index: 2147483647;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
padding-top: 12vh;
|
||||
transition: background 0.15s ease;
|
||||
`;
|
||||
|
||||
iframe = document.createElement("iframe");
|
||||
iframe.src = chrome.runtime.getURL("sciezka.html");
|
||||
iframe.style.cssText = `
|
||||
width: 620px;
|
||||
height: 60px;
|
||||
border: none;
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
|
||||
background: transparent;
|
||||
opacity: 0;
|
||||
transform: translateY(-8px);
|
||||
transition: opacity 0.15s ease, transform 0.15s ease, height 0.1s ease;
|
||||
`;
|
||||
|
||||
overlay.appendChild(iframe);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
overlay!.style.background = "rgba(0, 0, 0, 0.4)";
|
||||
iframe!.style.opacity = "1";
|
||||
iframe!.style.transform = "translateY(0)";
|
||||
});
|
||||
|
||||
overlay.addEventListener("click", (e) => {
|
||||
if (e.target === overlay) {
|
||||
removeOverlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removeOverlay(): void {
|
||||
if (overlay) {
|
||||
overlay.remove();
|
||||
overlay = null;
|
||||
iframe = null;
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(): void {
|
||||
if (overlay) {
|
||||
removeOverlay();
|
||||
} else {
|
||||
createOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener((msg: unknown) => {
|
||||
const message = msg as Message;
|
||||
if (message.type === "toggle") {
|
||||
toggle();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape" && overlay) {
|
||||
removeOverlay();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.source !== iframe?.contentWindow) return;
|
||||
|
||||
const data = event.data as Message;
|
||||
if (data.type === "closeSaka") {
|
||||
removeOverlay();
|
||||
return;
|
||||
}
|
||||
if (data.type === "resize") {
|
||||
if (iframe) {
|
||||
iframe.style.height = `${(data as { height: number }).height}px`;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (data.type === "search" || data.type === "action") {
|
||||
chrome.runtime.sendMessage(data, (response) => {
|
||||
iframe?.contentWindow?.postMessage(response, "*");
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
export type SearchMode = "tabs" | "history" | "bookmarks" | "closed" | "all";
|
||||
export type SearchMethod = "fuzzy" | "fulltext" | "prefix";
|
||||
|
||||
export interface SearchItem {
|
||||
id: string;
|
||||
title: string;
|
||||
url: string;
|
||||
type: SearchMode;
|
||||
favIconUrl?: string;
|
||||
}
|
||||
|
||||
export interface SearchResult {
|
||||
item: SearchItem;
|
||||
score: number;
|
||||
positions: number[];
|
||||
}
|
||||
|
||||
export interface SearchRequest {
|
||||
type: "search";
|
||||
query: string;
|
||||
mode: SearchMode;
|
||||
method: SearchMethod;
|
||||
}
|
||||
|
||||
export interface SearchResponse {
|
||||
type: "searchResults";
|
||||
results: SearchResult[];
|
||||
}
|
||||
|
||||
export interface ActionRequest {
|
||||
type: "action";
|
||||
action: "switch" | "open" | "close" | "restore";
|
||||
id: string;
|
||||
newTab?: boolean;
|
||||
}
|
||||
|
||||
export interface ToggleMessage {
|
||||
type: "toggle";
|
||||
}
|
||||
|
||||
export interface CloseMessage {
|
||||
type: "closeSaka";
|
||||
}
|
||||
|
||||
export interface ResizeMessage {
|
||||
type: "resize";
|
||||
height: number;
|
||||
}
|
||||
|
||||
export type Message =
|
||||
| SearchRequest
|
||||
| SearchResponse
|
||||
| ActionRequest
|
||||
| ToggleMessage
|
||||
| CloseMessage
|
||||
| ResizeMessage;
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user