footnote-data 0.1.1 → 0.3.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 +63 -4
  2. package/footnote.mjs +52 -2
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -2,10 +2,16 @@
2
2
 
3
3
  Employment-diligence data from primary public records: statutory WARN layoff
4
4
  notices, certified H-1B/LCA wage filings, USCIS petition outcomes, DOL Wage &
5
- Hour and OSHA enforcement, federal litigation posture, and severance terms
6
- parsed from SEC filings. Counts are measured, matches are exact-or-absent, and
7
- every response carries `data_gaps` absence of evidence is always
8
- distinguished from evidence of absence.
5
+ Hour and OSHA enforcement, DOL debarment, H-2 seasonal-labor and PERM green-card
6
+ certifications, ICE SEVP OPT/STEM-OPT top employers, federal litigation posture,
7
+ and severance terms parsed from SEC filings. Counts are measured, matches are
8
+ exact-or-absent, and absence of evidence is always distinguished from evidence
9
+ of absence.
10
+
11
+ Free keys get trust/posture answers (WARN, H-1B, debarment). The
12
+ volume/series datasets — H-2, PERM, OPT — are **Data Pro**; a free key hitting
13
+ them gets a `403 upgrade_required` that names the dataset and the way up, never
14
+ a silent 404. `footnote datasets` lists every holding with its `access` tier.
9
15
 
10
16
  Zero runtime dependencies. Node 18+. Docs and pricing: <https://usefootnote.com/data>.
11
17
 
@@ -83,6 +89,7 @@ footnote h1b employer "Databricks"
83
89
 
84
90
  # Top sponsors by certified filing volume (free tier: top 25)
85
91
  footnote h1b top-sponsors --limit 10
92
+ footnote h1b active-sponsors --limit 10 # certified-to-employ-today, by covered positions
86
93
 
87
94
  # Petition OUTCOMES (USCIS) + current attestation INTENT (LCA), in one view
88
95
  footnote sponsorship "Meta Platforms"
@@ -124,6 +131,52 @@ footnote litigation "Example Corp"
124
131
  footnote severance "Example Corp"
125
132
  ```
126
133
 
134
+ ### Work authorization & debarment
135
+
136
+ ```bash
137
+ # DOL debarment status — free tier: current / lapsed / none + program labels
138
+ footnote debarment "Example Staffing LLC"
139
+
140
+ # H-2A/H-2B seasonal-labor certifications for an employer (Data Pro)
141
+ footnote h2 "Example Farms" --program h2a --fy 2026
142
+
143
+ # National H-2 KPIs + the USCIS approved-worker trend (Data Pro)
144
+ footnote h2 summary
145
+
146
+ # PERM green-card certification decision counts (Data Pro)
147
+ footnote perm "Example Corp" --fy 2026
148
+
149
+ # ICE SEVP Top-200 OPT / STEM-OPT employers, ranked (Data Pro)
150
+ footnote opt-top --fy 2024 --limit 25
151
+ ```
152
+
153
+ ```text
154
+ $ footnote debarment "Example Staffing LLC"
155
+ employer_query example staffing
156
+ matched true
157
+ status current
158
+ programs OFLC H-2A
159
+
160
+ tier: free
161
+ match: exact normalized legal name + registered spelling variants (never fuzzy); …
162
+ interpretation: status is derived at read time — 'current' = a debarment in force today …
163
+ ▲ upgrade: Full debarment history — dates, entity spelling, willful flag, and violation text — is on Data Pro
164
+ ```
165
+
166
+ Honesty rails these commands keep, straight from the record:
167
+
168
+ - **debarment** — a no-match is *not* a clean bill (it means no exact-legal-name
169
+ entry on the DOL list); `status` is derived at read time, never stored.
170
+ - **h2** — wages are RAW rates with their unit, **never annualized** (seasonal
171
+ work); worker counts are OFLC application workers, not visas issued.
172
+ - **h2 summary** — OFLC certification (intent) and USCIS approvals (outcome) are
173
+ different pipeline stages and are **never** divided into a conversion rate.
174
+ - **perm** — a PERM certification is DOL's *step one* of green-card sponsorship,
175
+ not a green card; there is **no prevailing-wage field**.
176
+ - **opt-top** — `opt_or_stem_opt_students` is the source's own combined count and
177
+ is **not** `opt_students + stem_opt_students` (a student in both programs is
178
+ counted once per program); these are students, not employees.
179
+
127
180
  ### Dataset provenance
128
181
 
129
182
  ```bash
@@ -228,11 +281,17 @@ that apply to that call.
228
281
  | `warn states` | `GET /api/data/v1/warn/states` |
229
282
  | `h1b employer` | `GET /api/data/v1/h1b/employer` |
230
283
  | `h1b top-sponsors` | `GET /api/data/v1/h1b/top-sponsors` |
284
+ | `h1b active-sponsors` | `GET /api/data/v1/h1b/active-sponsors` |
231
285
  | `sponsorship` | `GET /api/data/v1/sponsorship/employer` |
232
286
  | `enforcement` | `GET /api/data/v1/enforcement/employer` |
233
287
  | `litigation` | `GET /api/data/v1/litigation/employer` |
234
288
  | `osha` | `GET /api/data/v1/osha/employer` |
235
289
  | `severance` | `GET /api/data/v1/severance/employer` |
236
290
  | `wage-comparison` | `GET /api/data/v1/wage-comparison/employer` |
291
+ | `debarment` | `GET /api/data/v1/debarment` |
292
+ | `h2` | `GET /api/data/v1/h2/employers` |
293
+ | `h2 summary` | `GET /api/data/v1/h2/summary` |
294
+ | `perm` | `GET /api/data/v1/perm/employers` |
295
+ | `opt-top` | `GET /api/data/v1/opt/top-employers` |
237
296
  | `datasets` | `GET /api/data/v1/datasets` |
238
297
  | `get <path>` | `GET <any /api/data/v1 path>` |
package/footnote.mjs CHANGED
@@ -6,7 +6,7 @@
6
6
  * params, read from the source, never guessed.
7
7
  */
8
8
 
9
- export const VERSION = "0.1.0";
9
+ export const VERSION = "0.2.0";
10
10
  export const DEFAULT_API_URL = "https://usefootnote.com";
11
11
 
12
12
  const UPGRADE_URL = "https://usefootnote.com/data";
@@ -38,6 +38,8 @@ const VALIDATORS = {
38
38
  nonNegInt: { ok: (v) => /^\d+$/.test(v), hint: "a non-negative integer" },
39
39
  date: { ok: (v) => /^\d{4}-\d{2}-\d{2}$/.test(v), hint: "a date formatted YYYY-MM-DD" },
40
40
  text3: { ok: (v) => v.trim().length >= 3, hint: "at least 3 characters" },
41
+ program: { ok: (v) => /^h2[ab]$/i.test(v), hint: "h2a or h2b", map: (v) => v.toLowerCase() },
42
+ year: { ok: (v) => /^\d{4}$/.test(v), hint: "a 4-digit year (e.g. 2024)" },
41
43
  };
42
44
 
43
45
  /**
@@ -80,6 +82,13 @@ export const COMMANDS = [
80
82
  summary: "Top H-1B sponsors by certified filing volume",
81
83
  flags: { limit: "posInt" },
82
84
  },
85
+ {
86
+ name: "h1b active-sponsors",
87
+ path: "/api/data/v1/h1b/active-sponsors",
88
+ route: "app/api/data/v1/h1b/active-sponsors/route.ts",
89
+ summary: "Employers with certified LCA windows covering today, by covered positions",
90
+ flags: { limit: "posInt" },
91
+ },
83
92
  {
84
93
  name: "sponsorship",
85
94
  path: "/api/data/v1/sponsorship/employer",
@@ -122,6 +131,45 @@ export const COMMANDS = [
122
131
  summary: "Advertised (posting) vs DOL-attested (LCA) wages",
123
132
  positional: { param: "name", label: "<employer>", min: 2 },
124
133
  },
134
+ {
135
+ name: "debarment",
136
+ path: "/api/data/v1/debarment",
137
+ route: "app/api/data/v1/debarment/route.ts",
138
+ summary: "DOL debarment status: current / lapsed / none (free tier)",
139
+ positional: { param: "employer", label: "<employer>", min: 2 },
140
+ },
141
+ {
142
+ // Two-word "h2 summary" is matched before the one-word "h2" employer lookup
143
+ // (findCommand tries the 2-word join first), so both resolve unambiguously.
144
+ name: "h2 summary",
145
+ path: "/api/data/v1/h2/summary",
146
+ route: "app/api/data/v1/h2/summary/route.ts",
147
+ summary: "National H-2A/H-2B KPIs + USCIS worker trend (Data Pro)",
148
+ flags: {},
149
+ },
150
+ {
151
+ name: "h2",
152
+ path: "/api/data/v1/h2/employers",
153
+ route: "app/api/data/v1/h2/employers/route.ts",
154
+ summary: "H-2A/H-2B certifications for an employer (Data Pro)",
155
+ positional: { param: "name", label: "<employer>", min: 2 },
156
+ flags: { program: "program", fy: "year" },
157
+ },
158
+ {
159
+ name: "perm",
160
+ path: "/api/data/v1/perm/employers",
161
+ route: "app/api/data/v1/perm/employers/route.ts",
162
+ summary: "PERM green-card decision counts for an employer (Data Pro)",
163
+ positional: { param: "name", label: "<employer>", min: 2 },
164
+ flags: { fy: "year" },
165
+ },
166
+ {
167
+ name: "opt-top",
168
+ path: "/api/data/v1/opt/top-employers",
169
+ route: "app/api/data/v1/opt/top-employers/route.ts",
170
+ summary: "SEVP Top-200 OPT/STEM-OPT employers, ranked (Data Pro)",
171
+ flags: { fy: "year", limit: "posInt" },
172
+ },
125
173
  {
126
174
  name: "datasets",
127
175
  path: "/api/data/v1/datasets",
@@ -397,8 +445,10 @@ function renderApiError(status, body, headers, io, style) {
397
445
 
398
446
  export function helpText() {
399
447
  const rows = COMMANDS.map((c) => {
448
+ const flagLabel = (t) =>
449
+ t === "date" ? "YYYY-MM-DD" : t === "state" ? "CA" : t === "text3" ? "TEXT" : t === "program" ? "h2a|h2b" : t === "year" ? "YYYY" : "N";
400
450
  const flags = Object.entries(c.flags ?? {})
401
- .map(([f, t]) => `[--${f} ${t === "date" ? "YYYY-MM-DD" : t === "state" ? "CA" : t === "text3" ? "TEXT" : "N"}]`)
451
+ .map(([f, t]) => `[--${f} ${flagLabel(t)}]`)
402
452
  .join(" ");
403
453
  const pos = c.positional ? ` ${c.positional.label}` : "";
404
454
  return [` footnote ${c.name}${pos}${flags ? ` ${flags}` : ""}`, c.summary];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "footnote-data",
3
- "version": "0.1.1",
4
- "description": "The official Footnote CLI \u2014 career intelligence from the public record: WARN layoffs, H-1B & green-card sponsorship, certified wages, and federal enforcement, straight from usefootnote.com's Data API.",
3
+ "version": "0.3.0",
4
+ "description": "The official Footnote CLI \u2014 career intelligence from the public record: WARN layoffs, H-1B & green-card sponsorship, H-2 seasonal labor, PERM, OPT, DOL debarment, certified wages, and federal enforcement, straight from usefootnote.com's Data API.",
5
5
  "keywords": [
6
6
  "layoffs",
7
7
  "warn-act",