wwv-plugin-opencorporates 1.0.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 ADDED
@@ -0,0 +1,106 @@
1
+ # wwv-plugin-opencorporates
2
+
3
+ > **WorldWideView Plugin** β€” OpenCorporates Business Intelligence Layer
4
+
5
+ Search for companies using the [OpenCorporates API](https://opencorporates.com) and plot them on the WorldWideView 3D globe with full ownership, officer, and financial status data.
6
+
7
+ ---
8
+
9
+ ## What it does
10
+
11
+ - Searches OpenCorporates for any company name you specify
12
+ - Geocodes each company's registered address via OpenStreetMap Nominatim
13
+ - Plots them as colored pins on the globe:
14
+ - 🟒 **Green** = Active company
15
+ - πŸ”΄ **Red** = Dissolved / struck off / liquidated
16
+ - 🟑 **Yellow** = Unknown status
17
+ - Click any pin to see: company number, jurisdiction, type, incorporation date, officers, registry URL
18
+ - Refreshes every 10 minutes
19
+ - Filter by jurisdiction (e.g. `us_de` for Delaware, `gb` for UK, `eg` for Egypt)
20
+
21
+ ---
22
+
23
+ ## Use Cases
24
+
25
+ - Track shell company networks by jurisdiction
26
+ - Map corporate ownership structures geographically
27
+ - Research where companies in a financial crime investigation are registered
28
+ - Compare corporate density across jurisdictions
29
+ - Follow the money β€” see where holding companies cluster
30
+
31
+ ---
32
+
33
+ ## Installation
34
+
35
+ ### Option 1: Via WorldWideView Marketplace (once published)
36
+
37
+ 1. Open WorldWideView β†’ click **Submit a Plugin**
38
+ 2. Enter: `wwv-plugin-opencorporates`
39
+ 3. Click **Submit Plugin**
40
+
41
+ ### Option 2: Manual / Local Dev
42
+
43
+ ```bash
44
+ # 1. Clone / download this plugin
45
+ git clone https://your-repo/wwv-plugin-opencorporates
46
+ cd wwv-plugin-opencorporates
47
+
48
+ # 2. Install dependencies
49
+ npm install
50
+
51
+ # 3. Build
52
+ npm run build
53
+
54
+ # 4. Publish to npm (required for marketplace submission)
55
+ npm login
56
+ npm publish --access public
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Configuration
62
+
63
+ After installing in WorldWideView, open the plugin settings panel and fill in:
64
+
65
+ | Field | Description | Example |
66
+ |---|---|---|
67
+ | **API Key** | Your OpenCorporates API key | `abc123xyz` |
68
+ | **Company Search Query** | What to search for | `Goldman Sachs` |
69
+ | **Jurisdiction Filter** | Limit by country/state (optional) | `us_de` or `gb` |
70
+ | **Max Results** | How many companies to plot (1-100) | `50` |
71
+
72
+ ### Get a free OpenCorporates API key:
73
+ πŸ‘‰ https://opencorporates.com/api_accounts/new
74
+
75
+ ### Jurisdiction codes:
76
+ - `us_de` β€” Delaware USA
77
+ - `us_ny` β€” New York USA
78
+ - `gb` β€” United Kingdom
79
+ - `eg` β€” Egypt
80
+ - `ae` β€” UAE
81
+ - `ky` β€” Cayman Islands
82
+ - Leave blank for global search
83
+
84
+ ---
85
+
86
+ ## How it works
87
+
88
+ ```
89
+ User sets search query
90
+ ↓
91
+ OpenCorporates API β†’ returns company list
92
+ ↓
93
+ Each company's address β†’ Nominatim geocoder β†’ lat/lon
94
+ ↓
95
+ Globe entity emitted with color based on company status
96
+ ↓
97
+ WorldWideView plots pin on 3D globe
98
+ ↓
99
+ Click pin β†’ popup shows full company data
100
+ ```
101
+
102
+ ---
103
+
104
+ ## License
105
+
106
+ MIT β€” build on it, modify it, do whatever.
@@ -0,0 +1,122 @@
1
+ const d = /* @__PURE__ */ new Map();
2
+ async function h(t) {
3
+ if (d.has(t)) return d.get(t);
4
+ try {
5
+ const e = encodeURIComponent(t), n = await (await fetch(`https://nominatim.openstreetmap.org/search?q=${e}&format=json&limit=1`, {
6
+ headers: { "User-Agent": "wwv-plugin-opencorporates/1.0" }
7
+ })).json();
8
+ if (n && n[0]) {
9
+ const s = { lat: parseFloat(n[0].lat), lon: parseFloat(n[0].lon) };
10
+ return d.set(t, s), s;
11
+ }
12
+ } catch {
13
+ }
14
+ return d.set(t, null), null;
15
+ }
16
+ const _ = "https://api.opencorporates.com/v0.4";
17
+ async function w(t, e, r, n) {
18
+ var l;
19
+ const s = new URLSearchParams({
20
+ q: t,
21
+ api_token: e,
22
+ per_page: String(Math.min(n, 100)),
23
+ fields: "name,company_number,jurisdiction_code,incorporation_date,dissolution_date,company_type,registry_url,registered_address,current_status"
24
+ });
25
+ r && s.set("jurisdiction_code", r);
26
+ const u = `${_}/companies/search?${s}`, a = await fetch(u);
27
+ if (!a.ok) throw new Error(`OpenCorporates API error: ${a.status} ${a.statusText}`);
28
+ const c = await a.json();
29
+ return ((l = c == null ? void 0 : c.results) == null ? void 0 : l.companies) ?? [];
30
+ }
31
+ function C(t) {
32
+ if (!t) return "#FFD700";
33
+ const e = t.toLowerCase();
34
+ return e.includes("active") || e.includes("live") ? "#00FF88" : e.includes("dissolv") || e.includes("struck") || e.includes("liquidat") ? "#FF4444" : "#FFD700";
35
+ }
36
+ async function $(t) {
37
+ var a, c, l, m;
38
+ const e = t.company, r = [
39
+ (a = e.registered_address) == null ? void 0 : a.street_address,
40
+ (c = e.registered_address) == null ? void 0 : c.locality,
41
+ (l = e.registered_address) == null ? void 0 : l.country
42
+ ].filter(Boolean);
43
+ if (r.length === 0) return null;
44
+ const n = r.join(", "), s = await h(n);
45
+ if (!s) return null;
46
+ const u = () => (Math.random() - 0.5) * 0.01;
47
+ return {
48
+ id: `oc-${e.jurisdiction_code}-${e.company_number}`,
49
+ lat: s.lat + u(),
50
+ lon: s.lon + u(),
51
+ label: e.name,
52
+ color: C(e.current_status),
53
+ size: 10,
54
+ data: {
55
+ "Company Number": e.company_number,
56
+ Jurisdiction: ((m = e.jurisdiction_code) == null ? void 0 : m.toUpperCase()) ?? "β€”",
57
+ Type: e.company_type ?? "β€”",
58
+ Status: e.current_status ?? "β€”",
59
+ Incorporated: e.incorporation_date ?? "β€”",
60
+ Dissolved: e.dissolution_date ?? "β€”",
61
+ Address: n,
62
+ Registry: e.registry_url ?? "β€”",
63
+ Officers: (e.officers ?? []).map((y) => `${y.name} (${y.position})`).join(", ") || "β€”",
64
+ _source: "OpenCorporates"
65
+ }
66
+ };
67
+ }
68
+ let o, i, p = null, g = !1;
69
+ async function f() {
70
+ if (!g) {
71
+ if (!i.apiKey) {
72
+ o.showNotification("OpenCorporates: Please set your API key in plugin settings.", "error");
73
+ return;
74
+ }
75
+ if (!i.searchQuery) {
76
+ o.showNotification("OpenCorporates: Enter a company name in plugin settings to search.", "info");
77
+ return;
78
+ }
79
+ g = !0, o.log(`[OpenCorporates] Searching: "${i.searchQuery}" (jurisdiction: ${i.jurisdiction || "global"})`), o.showNotification(`Searching OpenCorporates for "${i.searchQuery}"…`, "info");
80
+ try {
81
+ const t = await w(
82
+ i.searchQuery,
83
+ i.apiKey,
84
+ i.jurisdiction,
85
+ i.maxResults ?? 50
86
+ );
87
+ o.log(`[OpenCorporates] Found ${t.length} companies, geocoding…`);
88
+ const e = [];
89
+ for (let r = 0; r < t.length; r++) {
90
+ const n = await $(t[r]);
91
+ n && e.push(n), r % 5 === 4 && await new Promise((s) => setTimeout(s, 1200));
92
+ }
93
+ o.emit("entities:replace", {
94
+ pluginId: "wwv-plugin-opencorporates",
95
+ entities: e
96
+ }), o.showNotification(
97
+ `OpenCorporates: Plotted ${e.length} companies on the globe.`,
98
+ "success"
99
+ ), o.log(`[OpenCorporates] Done. ${e.length} entities emitted.`);
100
+ } catch (t) {
101
+ const e = t instanceof Error ? t.message : String(t);
102
+ o.log(`[OpenCorporates] Error: ${e}`), o.showNotification(`OpenCorporates error: ${e}`, "error");
103
+ } finally {
104
+ g = !1;
105
+ }
106
+ }
107
+ }
108
+ const O = {
109
+ id: "wwv-plugin-opencorporates",
110
+ async initialize(t, e) {
111
+ o = t, i = e, o.log("[OpenCorporates] Plugin initialized."), o.onConfigChange((r) => {
112
+ i = r, p && clearInterval(p), setTimeout(() => f(), 1500);
113
+ }), await f(), p = setInterval(() => f(), 10 * 60 * 1e3);
114
+ },
115
+ destroy() {
116
+ p && clearInterval(p), o == null || o.log("[OpenCorporates] Plugin destroyed.");
117
+ }
118
+ };
119
+ export {
120
+ O as default
121
+ };
122
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * wwv-plugin-opencorporates\n * WorldWideView plugin β€” OpenCorporates Business Intelligence Layer\n *\n * Queries the OpenCorporates API for companies matching a search term,\n * geocodes their registered addresses, and emits them as globe entities\n * with rich financial/ownership popups.\n */\n\n// ─── Types (mirrors @worldwideview/wwv-plugin-sdk interfaces) ────────────────\n\ninterface PluginContext {\n emit: (event: string, payload: unknown) => void;\n onConfigChange: (cb: (cfg: PluginConfig) => void) => void;\n log: (msg: string) => void;\n showNotification: (msg: string, type?: \"info\" | \"error\" | \"success\") => void;\n}\n\ninterface PluginConfig {\n apiKey: string;\n searchQuery: string;\n jurisdiction: string;\n maxResults: number;\n}\n\ninterface GlobeEntity {\n id: string;\n lat: number;\n lon: number;\n label: string;\n color: string; // hex\n size: number; // pixels\n data: Record<string, unknown>;\n}\n\ninterface OcCompany {\n company: {\n name: string;\n company_number: string;\n jurisdiction_code: string;\n incorporation_date: string;\n dissolution_date: string | null;\n company_type: string;\n registry_url: string;\n registered_address: {\n street_address?: string;\n locality?: string;\n country?: string;\n } | null;\n officers?: Array<{ name: string; position: string }>;\n number_of_employees?: number;\n current_status: string;\n };\n}\n\n// ─── Geocoding cache (simple in-memory) ──────────────────────────────────────\n\nconst geocodeCache = new Map<string, { lat: number; lon: number } | null>();\n\nasync function geocodeAddress(address: string): Promise<{ lat: number; lon: number } | null> {\n if (geocodeCache.has(address)) return geocodeCache.get(address)!;\n try {\n const q = encodeURIComponent(address);\n const res = await fetch(`https://nominatim.openstreetmap.org/search?q=${q}&format=json&limit=1`, {\n headers: { \"User-Agent\": \"wwv-plugin-opencorporates/1.0\" }\n });\n const data = await res.json();\n if (data && data[0]) {\n const result = { lat: parseFloat(data[0].lat), lon: parseFloat(data[0].lon) };\n geocodeCache.set(address, result);\n return result;\n }\n } catch (_) {/* silently fail */}\n geocodeCache.set(address, null);\n return null;\n}\n\n// ─── OpenCorporates API helpers ───────────────────────────────────────────────\n\nconst OC_BASE = \"https://api.opencorporates.com/v0.4\";\n\nasync function searchCompanies(\n query: string,\n apiKey: string,\n jurisdiction: string,\n perPage: number\n): Promise<OcCompany[]> {\n const params = new URLSearchParams({\n q: query,\n api_token: apiKey,\n per_page: String(Math.min(perPage, 100)),\n fields: \"name,company_number,jurisdiction_code,incorporation_date,dissolution_date,company_type,registry_url,registered_address,current_status\"\n });\n if (jurisdiction) params.set(\"jurisdiction_code\", jurisdiction);\n\n const url = `${OC_BASE}/companies/search?${params}`;\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenCorporates API error: ${res.status} ${res.statusText}`);\n const json = await res.json();\n return json?.results?.companies ?? [];\n}\n\n// ─── Color logic (active=green, dissolved=red, unknown=yellow) ────────────────\n\nfunction statusColor(status: string | null): string {\n if (!status) return \"#FFD700\";\n const s = status.toLowerCase();\n if (s.includes(\"active\") || s.includes(\"live\")) return \"#00FF88\";\n if (s.includes(\"dissolv\") || s.includes(\"struck\") || s.includes(\"liquidat\")) return \"#FF4444\";\n return \"#FFD700\";\n}\n\n// ─── Build globe entity from OC company ──────────────────────────────────────\n\nasync function companyToEntity(raw: OcCompany): Promise<GlobeEntity | null> {\n const c = raw.company;\n\n // Build address string for geocoding\n const addrParts = [\n c.registered_address?.street_address,\n c.registered_address?.locality,\n c.registered_address?.country\n ].filter(Boolean);\n\n if (addrParts.length === 0) return null;\n const addressStr = addrParts.join(\", \");\n\n const coords = await geocodeAddress(addressStr);\n if (!coords) return null;\n\n // Add slight jitter so overlapping pins don't stack exactly\n const jitter = () => (Math.random() - 0.5) * 0.01;\n\n return {\n id: `oc-${c.jurisdiction_code}-${c.company_number}`,\n lat: coords.lat + jitter(),\n lon: coords.lon + jitter(),\n label: c.name,\n color: statusColor(c.current_status),\n size: 10,\n data: {\n \"Company Number\": c.company_number,\n \"Jurisdiction\": c.jurisdiction_code?.toUpperCase() ?? \"β€”\",\n \"Type\": c.company_type ?? \"β€”\",\n \"Status\": c.current_status ?? \"β€”\",\n \"Incorporated\": c.incorporation_date ?? \"β€”\",\n \"Dissolved\": c.dissolution_date ?? \"β€”\",\n \"Address\": addressStr,\n \"Registry\": c.registry_url ?? \"β€”\",\n \"Officers\": (c.officers ?? []).map((o) => `${o.name} (${o.position})`).join(\", \") || \"β€”\",\n \"_source\": \"OpenCorporates\"\n }\n };\n}\n\n// ─── Plugin lifecycle ─────────────────────────────────────────────────────────\n\nlet _ctx: PluginContext;\nlet _cfg: PluginConfig;\nlet _pollTimer: ReturnType<typeof setInterval> | null = null;\nlet _running = false;\n\nasync function runScan() {\n if (_running) return;\n if (!_cfg.apiKey) {\n _ctx.showNotification(\"OpenCorporates: Please set your API key in plugin settings.\", \"error\");\n return;\n }\n if (!_cfg.searchQuery) {\n _ctx.showNotification(\"OpenCorporates: Enter a company name in plugin settings to search.\", \"info\");\n return;\n }\n\n _running = true;\n _ctx.log(`[OpenCorporates] Searching: \"${_cfg.searchQuery}\" (jurisdiction: ${_cfg.jurisdiction || \"global\"})`);\n _ctx.showNotification(`Searching OpenCorporates for \"${_cfg.searchQuery}\"…`, \"info\");\n\n try {\n const companies = await searchCompanies(\n _cfg.searchQuery,\n _cfg.apiKey,\n _cfg.jurisdiction,\n _cfg.maxResults ?? 50\n );\n\n _ctx.log(`[OpenCorporates] Found ${companies.length} companies, geocoding…`);\n\n const entities: GlobeEntity[] = [];\n\n // Process in batches to avoid hammering Nominatim\n for (let i = 0; i < companies.length; i++) {\n const entity = await companyToEntity(companies[i]);\n if (entity) entities.push(entity);\n // Nominatim rate limit: 1 req/sec\n if (i % 5 === 4) await new Promise((r) => setTimeout(r, 1200));\n }\n\n _ctx.emit(\"entities:replace\", {\n pluginId: \"wwv-plugin-opencorporates\",\n entities\n });\n\n _ctx.showNotification(\n `OpenCorporates: Plotted ${entities.length} companies on the globe.`,\n \"success\"\n );\n _ctx.log(`[OpenCorporates] Done. ${entities.length} entities emitted.`);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n _ctx.log(`[OpenCorporates] Error: ${msg}`);\n _ctx.showNotification(`OpenCorporates error: ${msg}`, \"error\");\n } finally {\n _running = false;\n }\n}\n\n// ─── Exported plugin object (WorldWideView plugin contract) ──────────────────\n\nexport default {\n id: \"wwv-plugin-opencorporates\",\n\n async initialize(context: PluginContext, config: PluginConfig) {\n _ctx = context;\n _cfg = config;\n\n _ctx.log(\"[OpenCorporates] Plugin initialized.\");\n\n // React to config changes (user types new search query / API key)\n _ctx.onConfigChange((newCfg: PluginConfig) => {\n _cfg = newCfg;\n // Debounce: clear old timer, rescan after 1.5s\n if (_pollTimer) clearInterval(_pollTimer);\n setTimeout(() => runScan(), 1500);\n });\n\n // Initial scan\n await runScan();\n\n // Refresh every 10 minutes (company data doesn't change fast)\n _pollTimer = setInterval(() => runScan(), 10 * 60 * 1000);\n },\n\n destroy() {\n if (_pollTimer) clearInterval(_pollTimer);\n _ctx?.log(\"[OpenCorporates] Plugin destroyed.\");\n }\n};\n"],"names":["geocodeCache","geocodeAddress","address","q","data","result","OC_BASE","searchCompanies","query","apiKey","jurisdiction","perPage","_a","params","url","res","json","statusColor","status","s","companyToEntity","raw","_b","_c","_d","c","addrParts","addressStr","coords","jitter","o","_ctx","_cfg","_pollTimer","_running","runScan","companies","entities","i","entity","r","err","msg","index","context","config","newCfg"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";const d=new Map;async function h(t){if(d.has(t))return d.get(t);try{const e=encodeURIComponent(t),n=await(await fetch(`https://nominatim.openstreetmap.org/search?q=${e}&format=json&limit=1`,{headers:{"User-Agent":"wwv-plugin-opencorporates/1.0"}})).json();if(n&&n[0]){const s={lat:parseFloat(n[0].lat),lon:parseFloat(n[0].lon)};return d.set(t,s),s}}catch{}return d.set(t,null),null}const _="https://api.opencorporates.com/v0.4";async function w(t,e,r,n){var l;const s=new URLSearchParams({q:t,api_token:e,per_page:String(Math.min(n,100)),fields:"name,company_number,jurisdiction_code,incorporation_date,dissolution_date,company_type,registry_url,registered_address,current_status"});r&&s.set("jurisdiction_code",r);const u=`${_}/companies/search?${s}`,a=await fetch(u);if(!a.ok)throw new Error(`OpenCorporates API error: ${a.status} ${a.statusText}`);const c=await a.json();return((l=c==null?void 0:c.results)==null?void 0:l.companies)??[]}function C(t){if(!t)return"#FFD700";const e=t.toLowerCase();return e.includes("active")||e.includes("live")?"#00FF88":e.includes("dissolv")||e.includes("struck")||e.includes("liquidat")?"#FF4444":"#FFD700"}async function $(t){var a,c,l,m;const e=t.company,r=[(a=e.registered_address)==null?void 0:a.street_address,(c=e.registered_address)==null?void 0:c.locality,(l=e.registered_address)==null?void 0:l.country].filter(Boolean);if(r.length===0)return null;const n=r.join(", "),s=await h(n);if(!s)return null;const u=()=>(Math.random()-.5)*.01;return{id:`oc-${e.jurisdiction_code}-${e.company_number}`,lat:s.lat+u(),lon:s.lon+u(),label:e.name,color:C(e.current_status),size:10,data:{"Company Number":e.company_number,Jurisdiction:((m=e.jurisdiction_code)==null?void 0:m.toUpperCase())??"β€”",Type:e.company_type??"β€”",Status:e.current_status??"β€”",Incorporated:e.incorporation_date??"β€”",Dissolved:e.dissolution_date??"β€”",Address:n,Registry:e.registry_url??"β€”",Officers:(e.officers??[]).map(y=>`${y.name} (${y.position})`).join(", ")||"β€”",_source:"OpenCorporates"}}}let o,i,p=null,g=!1;async function f(){if(!g){if(!i.apiKey){o.showNotification("OpenCorporates: Please set your API key in plugin settings.","error");return}if(!i.searchQuery){o.showNotification("OpenCorporates: Enter a company name in plugin settings to search.","info");return}g=!0,o.log(`[OpenCorporates] Searching: "${i.searchQuery}" (jurisdiction: ${i.jurisdiction||"global"})`),o.showNotification(`Searching OpenCorporates for "${i.searchQuery}"…`,"info");try{const t=await w(i.searchQuery,i.apiKey,i.jurisdiction,i.maxResults??50);o.log(`[OpenCorporates] Found ${t.length} companies, geocoding…`);const e=[];for(let r=0;r<t.length;r++){const n=await $(t[r]);n&&e.push(n),r%5===4&&await new Promise(s=>setTimeout(s,1200))}o.emit("entities:replace",{pluginId:"wwv-plugin-opencorporates",entities:e}),o.showNotification(`OpenCorporates: Plotted ${e.length} companies on the globe.`,"success"),o.log(`[OpenCorporates] Done. ${e.length} entities emitted.`)}catch(t){const e=t instanceof Error?t.message:String(t);o.log(`[OpenCorporates] Error: ${e}`),o.showNotification(`OpenCorporates error: ${e}`,"error")}finally{g=!1}}}const O={id:"wwv-plugin-opencorporates",async initialize(t,e){o=t,i=e,o.log("[OpenCorporates] Plugin initialized."),o.onConfigChange(r=>{i=r,p&&clearInterval(p),setTimeout(()=>f(),1500)}),await f(),p=setInterval(()=>f(),10*60*1e3)},destroy(){p&&clearInterval(p),o==null||o.log("[OpenCorporates] Plugin destroyed.")}};module.exports=O;
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * wwv-plugin-opencorporates\n * WorldWideView plugin β€” OpenCorporates Business Intelligence Layer\n *\n * Queries the OpenCorporates API for companies matching a search term,\n * geocodes their registered addresses, and emits them as globe entities\n * with rich financial/ownership popups.\n */\n\n// ─── Types (mirrors @worldwideview/wwv-plugin-sdk interfaces) ────────────────\n\ninterface PluginContext {\n emit: (event: string, payload: unknown) => void;\n onConfigChange: (cb: (cfg: PluginConfig) => void) => void;\n log: (msg: string) => void;\n showNotification: (msg: string, type?: \"info\" | \"error\" | \"success\") => void;\n}\n\ninterface PluginConfig {\n apiKey: string;\n searchQuery: string;\n jurisdiction: string;\n maxResults: number;\n}\n\ninterface GlobeEntity {\n id: string;\n lat: number;\n lon: number;\n label: string;\n color: string; // hex\n size: number; // pixels\n data: Record<string, unknown>;\n}\n\ninterface OcCompany {\n company: {\n name: string;\n company_number: string;\n jurisdiction_code: string;\n incorporation_date: string;\n dissolution_date: string | null;\n company_type: string;\n registry_url: string;\n registered_address: {\n street_address?: string;\n locality?: string;\n country?: string;\n } | null;\n officers?: Array<{ name: string; position: string }>;\n number_of_employees?: number;\n current_status: string;\n };\n}\n\n// ─── Geocoding cache (simple in-memory) ──────────────────────────────────────\n\nconst geocodeCache = new Map<string, { lat: number; lon: number } | null>();\n\nasync function geocodeAddress(address: string): Promise<{ lat: number; lon: number } | null> {\n if (geocodeCache.has(address)) return geocodeCache.get(address)!;\n try {\n const q = encodeURIComponent(address);\n const res = await fetch(`https://nominatim.openstreetmap.org/search?q=${q}&format=json&limit=1`, {\n headers: { \"User-Agent\": \"wwv-plugin-opencorporates/1.0\" }\n });\n const data = await res.json();\n if (data && data[0]) {\n const result = { lat: parseFloat(data[0].lat), lon: parseFloat(data[0].lon) };\n geocodeCache.set(address, result);\n return result;\n }\n } catch (_) {/* silently fail */}\n geocodeCache.set(address, null);\n return null;\n}\n\n// ─── OpenCorporates API helpers ───────────────────────────────────────────────\n\nconst OC_BASE = \"https://api.opencorporates.com/v0.4\";\n\nasync function searchCompanies(\n query: string,\n apiKey: string,\n jurisdiction: string,\n perPage: number\n): Promise<OcCompany[]> {\n const params = new URLSearchParams({\n q: query,\n api_token: apiKey,\n per_page: String(Math.min(perPage, 100)),\n fields: \"name,company_number,jurisdiction_code,incorporation_date,dissolution_date,company_type,registry_url,registered_address,current_status\"\n });\n if (jurisdiction) params.set(\"jurisdiction_code\", jurisdiction);\n\n const url = `${OC_BASE}/companies/search?${params}`;\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenCorporates API error: ${res.status} ${res.statusText}`);\n const json = await res.json();\n return json?.results?.companies ?? [];\n}\n\n// ─── Color logic (active=green, dissolved=red, unknown=yellow) ────────────────\n\nfunction statusColor(status: string | null): string {\n if (!status) return \"#FFD700\";\n const s = status.toLowerCase();\n if (s.includes(\"active\") || s.includes(\"live\")) return \"#00FF88\";\n if (s.includes(\"dissolv\") || s.includes(\"struck\") || s.includes(\"liquidat\")) return \"#FF4444\";\n return \"#FFD700\";\n}\n\n// ─── Build globe entity from OC company ──────────────────────────────────────\n\nasync function companyToEntity(raw: OcCompany): Promise<GlobeEntity | null> {\n const c = raw.company;\n\n // Build address string for geocoding\n const addrParts = [\n c.registered_address?.street_address,\n c.registered_address?.locality,\n c.registered_address?.country\n ].filter(Boolean);\n\n if (addrParts.length === 0) return null;\n const addressStr = addrParts.join(\", \");\n\n const coords = await geocodeAddress(addressStr);\n if (!coords) return null;\n\n // Add slight jitter so overlapping pins don't stack exactly\n const jitter = () => (Math.random() - 0.5) * 0.01;\n\n return {\n id: `oc-${c.jurisdiction_code}-${c.company_number}`,\n lat: coords.lat + jitter(),\n lon: coords.lon + jitter(),\n label: c.name,\n color: statusColor(c.current_status),\n size: 10,\n data: {\n \"Company Number\": c.company_number,\n \"Jurisdiction\": c.jurisdiction_code?.toUpperCase() ?? \"β€”\",\n \"Type\": c.company_type ?? \"β€”\",\n \"Status\": c.current_status ?? \"β€”\",\n \"Incorporated\": c.incorporation_date ?? \"β€”\",\n \"Dissolved\": c.dissolution_date ?? \"β€”\",\n \"Address\": addressStr,\n \"Registry\": c.registry_url ?? \"β€”\",\n \"Officers\": (c.officers ?? []).map((o) => `${o.name} (${o.position})`).join(\", \") || \"β€”\",\n \"_source\": \"OpenCorporates\"\n }\n };\n}\n\n// ─── Plugin lifecycle ─────────────────────────────────────────────────────────\n\nlet _ctx: PluginContext;\nlet _cfg: PluginConfig;\nlet _pollTimer: ReturnType<typeof setInterval> | null = null;\nlet _running = false;\n\nasync function runScan() {\n if (_running) return;\n if (!_cfg.apiKey) {\n _ctx.showNotification(\"OpenCorporates: Please set your API key in plugin settings.\", \"error\");\n return;\n }\n if (!_cfg.searchQuery) {\n _ctx.showNotification(\"OpenCorporates: Enter a company name in plugin settings to search.\", \"info\");\n return;\n }\n\n _running = true;\n _ctx.log(`[OpenCorporates] Searching: \"${_cfg.searchQuery}\" (jurisdiction: ${_cfg.jurisdiction || \"global\"})`);\n _ctx.showNotification(`Searching OpenCorporates for \"${_cfg.searchQuery}\"…`, \"info\");\n\n try {\n const companies = await searchCompanies(\n _cfg.searchQuery,\n _cfg.apiKey,\n _cfg.jurisdiction,\n _cfg.maxResults ?? 50\n );\n\n _ctx.log(`[OpenCorporates] Found ${companies.length} companies, geocoding…`);\n\n const entities: GlobeEntity[] = [];\n\n // Process in batches to avoid hammering Nominatim\n for (let i = 0; i < companies.length; i++) {\n const entity = await companyToEntity(companies[i]);\n if (entity) entities.push(entity);\n // Nominatim rate limit: 1 req/sec\n if (i % 5 === 4) await new Promise((r) => setTimeout(r, 1200));\n }\n\n _ctx.emit(\"entities:replace\", {\n pluginId: \"wwv-plugin-opencorporates\",\n entities\n });\n\n _ctx.showNotification(\n `OpenCorporates: Plotted ${entities.length} companies on the globe.`,\n \"success\"\n );\n _ctx.log(`[OpenCorporates] Done. ${entities.length} entities emitted.`);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n _ctx.log(`[OpenCorporates] Error: ${msg}`);\n _ctx.showNotification(`OpenCorporates error: ${msg}`, \"error\");\n } finally {\n _running = false;\n }\n}\n\n// ─── Exported plugin object (WorldWideView plugin contract) ──────────────────\n\nexport default {\n id: \"wwv-plugin-opencorporates\",\n\n async initialize(context: PluginContext, config: PluginConfig) {\n _ctx = context;\n _cfg = config;\n\n _ctx.log(\"[OpenCorporates] Plugin initialized.\");\n\n // React to config changes (user types new search query / API key)\n _ctx.onConfigChange((newCfg: PluginConfig) => {\n _cfg = newCfg;\n // Debounce: clear old timer, rescan after 1.5s\n if (_pollTimer) clearInterval(_pollTimer);\n setTimeout(() => runScan(), 1500);\n });\n\n // Initial scan\n await runScan();\n\n // Refresh every 10 minutes (company data doesn't change fast)\n _pollTimer = setInterval(() => runScan(), 10 * 60 * 1000);\n },\n\n destroy() {\n if (_pollTimer) clearInterval(_pollTimer);\n _ctx?.log(\"[OpenCorporates] Plugin destroyed.\");\n }\n};\n"],"names":["geocodeCache","geocodeAddress","address","q","data","result","OC_BASE","searchCompanies","query","apiKey","jurisdiction","perPage","params","url","res","json","_a","statusColor","status","s","companyToEntity","raw","c","addrParts","_b","_c","addressStr","coords","jitter","_d","o","_ctx","_cfg","_pollTimer","_running","runScan","companies","entities","i","entity","r","err","msg","index","context","config","newCfg"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "wwv-plugin-opencorporates",
3
+ "version": "1.0.0",
4
+ "description": "WorldWideView plugin β€” OpenCorporates business intelligence layer. Plots companies on the globe with financial & ownership data.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": ["dist"],
9
+ "scripts": {
10
+ "build": "vite build",
11
+ "dev": "vite build --watch"
12
+ },
13
+ "worldwideview": {
14
+ "id": "wwv-plugin-opencorporates",
15
+ "name": "OpenCorporates Intelligence",
16
+ "description": "Search and visualize companies worldwide using the OpenCorporates API. Plots HQ locations on the globe with ownership, officers, filing history and financial flags.",
17
+ "version": "1.0.0",
18
+ "author": "malek",
19
+ "category": "FINANCIAL",
20
+ "tags": ["finance", "corporate", "osint", "business", "shell-companies"],
21
+ "icon": "🏒",
22
+ "pluginType": "ActiveProxied",
23
+ "configSchema": {
24
+ "apiKey": {
25
+ "type": "string",
26
+ "label": "OpenCorporates API Key",
27
+ "description": "Get a free key at opencorporates.com/api_accounts/new",
28
+ "required": true,
29
+ "secret": true
30
+ },
31
+ "searchQuery": {
32
+ "type": "string",
33
+ "label": "Company Search Query",
34
+ "description": "Company name to search and plot",
35
+ "required": false,
36
+ "default": ""
37
+ },
38
+ "jurisdiction": {
39
+ "type": "string",
40
+ "label": "Jurisdiction Filter",
41
+ "description": "e.g. us_de, gb, eg β€” leave blank for global",
42
+ "required": false,
43
+ "default": ""
44
+ },
45
+ "maxResults": {
46
+ "type": "number",
47
+ "label": "Max Results",
48
+ "description": "Max companies to plot (1-100)",
49
+ "required": false,
50
+ "default": 50
51
+ }
52
+ }
53
+ },
54
+ "devDependencies": {
55
+ "vite": "^5.0.0",
56
+ "typescript": "^5.0.0"
57
+ }
58
+ }