business-obligations 0.3.0 → 0.3.1
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/CHANGELOG.md +6 -0
- package/COVERAGE.md +1 -1
- package/README.md +2 -2
- package/data/cities/MN.json +13 -4
- package/data/cities/TN.json +3 -2
- package/data/cities/TX.json +2 -2
- package/dist/cli.js +33 -41
- package/dist/index.cjs +33 -41
- package/dist/index.js +33 -41
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ project follows [Semantic Versioning](https://semver.org/) with the data-aware p
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.3.1] - 2026-10-16
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **data:** Minneapolis sick and safe time, Nashville license fee, Austin sourcing
|
|
13
|
+
|
|
8
14
|
## [0.3.0] - 2026-10-16
|
|
9
15
|
|
|
10
16
|
### Fixed
|
package/COVERAGE.md
CHANGED
|
@@ -8,7 +8,7 @@ page on the date shown; everything not listed as checked is compiled from public
|
|
|
8
8
|
|
|
9
9
|
- **Jurisdictions:** 51 (50 states and DC)
|
|
10
10
|
- **States with unconfirmed fields:** 1
|
|
11
|
-
- **Seeded cities:** 307:
|
|
11
|
+
- **Seeded cities:** 307: 165 with city-specific rules, 25 checked with no general city license or tax, 117 researched but unconfirmed (all other cities get the state's local licensing regime named for the city and county)
|
|
12
12
|
- **Seeded counties:** 312: 145 with county-specific filings (mainly business personal property returns), the rest researched but unconfirmed or with nothing county-level
|
|
13
13
|
- **300 largest counties** (approximate): 297 of 300 covered
|
|
14
14
|
- **300 largest cities** (2020 census; ranks beyond 100 are approximate): 300 of 300 covered
|
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ them. Start with [CONTRIBUTING.md](https://github.com/Alisa007/business-obligati
|
|
|
111
111
|
npm install business-obligations
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
ESM and CommonJS are both supported. Node 20+. About
|
|
114
|
+
ESM and CommonJS are both supported. Node 20+. About 115 KB gzipped, no runtime dependencies.
|
|
115
115
|
|
|
116
116
|
## Using it from plain JavaScript
|
|
117
117
|
|
|
@@ -413,7 +413,7 @@ It sets no cookies, records no sessions and respects Do Not Track. It is off unl
|
|
|
413
413
|
|
|
414
414
|
## Size
|
|
415
415
|
|
|
416
|
-
The core bundle is about
|
|
416
|
+
The core bundle is about 115 KB gzipped with all 51 jurisdictions' data. ZIP lookup (about 305 KB gzipped) lives in the
|
|
417
417
|
separate `business-obligations/zip` entry and is only loaded when you import it. `npm run size` enforces the budgets.
|
|
418
418
|
|
|
419
419
|
## Extending
|
package/data/cities/MN.json
CHANGED
|
@@ -2,11 +2,20 @@
|
|
|
2
2
|
{
|
|
3
3
|
"state": "MN",
|
|
4
4
|
"city": "Minneapolis",
|
|
5
|
-
"status": "unverified",
|
|
6
|
-
"note": "Licensing appears to be industry-specific through Business Licenses and Consumer Services; the city's own list was not confirmed.",
|
|
7
5
|
"counties": ["Hennepin"],
|
|
8
|
-
"items": [
|
|
9
|
-
|
|
6
|
+
"items": [
|
|
7
|
+
{
|
|
8
|
+
"id": "minneapolis.sick-and-safe-time",
|
|
9
|
+
"title": "Provide Minneapolis sick and safe time",
|
|
10
|
+
"category": "recordkeeping",
|
|
11
|
+
"authority": "City of Minneapolis Labor Standards Enforcement",
|
|
12
|
+
"description": "Employers must give employees paid sick and safe time: 1 hour for every 30 hours worked, up to 48 hours a year and 80 hours overall, or front-load 48 hours a year. Keep a written policy and give it to new hires, display the Minneapolis labor standards poster in each language spoken by 5% or more of employees, and show employees the hours used and available each pay period.",
|
|
13
|
+
"frequency": "ongoing",
|
|
14
|
+
"url": "https://sicktimeinfo.minneapolismn.gov/employer-resources.html",
|
|
15
|
+
"appliesTo": ["employees"]
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"checkedOn": "2026-10-16"
|
|
10
19
|
},
|
|
11
20
|
{
|
|
12
21
|
"state": "MN",
|
package/data/cities/TN.json
CHANGED
|
@@ -91,12 +91,13 @@
|
|
|
91
91
|
"title": "Obtain Nashville / Davidson County business license",
|
|
92
92
|
"category": "license",
|
|
93
93
|
"authority": "Davidson County Clerk, Business Tax Division",
|
|
94
|
-
"description": "Businesses in Nashville-Davidson County obtain a business license from the County Clerk and
|
|
94
|
+
"description": "Businesses in Nashville-Davidson County obtain a business tax license or a minimal activity license from the County Clerk. The license fee is $30 for a business inside Nashville city limits (Urban Service District) and $15 outside city limits but within Davidson County. Report gross receipts to the Tennessee Department of Revenue with the annual business tax return.",
|
|
95
95
|
"frequency": "once",
|
|
96
96
|
"url": "https://www.nashville.gov/departments/county-clerk/business-services/apply-business-license",
|
|
97
97
|
"appliesTo": ["all"]
|
|
98
98
|
}
|
|
99
99
|
],
|
|
100
|
-
"aliases": ["Nashville-Davidson", "Metro Nashville"]
|
|
100
|
+
"aliases": ["Nashville-Davidson", "Metro Nashville"],
|
|
101
|
+
"checkedOn": "2026-10-16"
|
|
101
102
|
}
|
|
102
103
|
]
|
package/data/cities/TX.json
CHANGED
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"state": "TX",
|
|
31
31
|
"city": "Austin",
|
|
32
32
|
"status": "unverified",
|
|
33
|
-
"note": "The city's start-a-business page
|
|
33
|
+
"note": "The city's start-a-business page says Texas has no general business license, that most Austin businesses need permits or licenses depending on type, location and activity (issued through Austin Development Services), and lists no general city business license. Business personal property tax is administered by the Travis County Appraisal District, not the city.",
|
|
34
34
|
"counties": ["Travis"],
|
|
35
35
|
"sourceUrl": "https://www.austintexas.gov/economic-development/start-business",
|
|
36
36
|
"items": [],
|
|
37
|
-
"checkedOn": "2026-10-
|
|
37
|
+
"checkedOn": "2026-10-16"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"state": "TX",
|
package/dist/cli.js
CHANGED
|
@@ -9868,11 +9868,20 @@ var MN_default2 = [
|
|
|
9868
9868
|
{
|
|
9869
9869
|
state: "MN",
|
|
9870
9870
|
city: "Minneapolis",
|
|
9871
|
-
status: "unverified",
|
|
9872
|
-
note: "Licensing appears to be industry-specific through Business Licenses and Consumer Services; the city's own list was not confirmed.",
|
|
9873
9871
|
counties: ["Hennepin"],
|
|
9874
|
-
items: [
|
|
9875
|
-
|
|
9872
|
+
items: [
|
|
9873
|
+
{
|
|
9874
|
+
id: "minneapolis.sick-and-safe-time",
|
|
9875
|
+
title: "Provide Minneapolis sick and safe time",
|
|
9876
|
+
category: "recordkeeping",
|
|
9877
|
+
authority: "City of Minneapolis Labor Standards Enforcement",
|
|
9878
|
+
description: "Employers must give employees paid sick and safe time: 1 hour for every 30 hours worked, up to 48 hours a year and 80 hours overall, or front-load 48 hours a year. Keep a written policy and give it to new hires, display the Minneapolis labor standards poster in each language spoken by 5% or more of employees, and show employees the hours used and available each pay period.",
|
|
9879
|
+
frequency: "ongoing",
|
|
9880
|
+
url: "https://sicktimeinfo.minneapolismn.gov/employer-resources.html",
|
|
9881
|
+
appliesTo: ["employees"]
|
|
9882
|
+
}
|
|
9883
|
+
],
|
|
9884
|
+
checkedOn: "2026-10-16"
|
|
9876
9885
|
},
|
|
9877
9886
|
{
|
|
9878
9887
|
state: "MN",
|
|
@@ -11085,13 +11094,14 @@ var TN_default2 = [
|
|
|
11085
11094
|
title: "Obtain Nashville / Davidson County business license",
|
|
11086
11095
|
category: "license",
|
|
11087
11096
|
authority: "Davidson County Clerk, Business Tax Division",
|
|
11088
|
-
description: "Businesses in Nashville-Davidson County obtain a business license from the County Clerk and
|
|
11097
|
+
description: "Businesses in Nashville-Davidson County obtain a business tax license or a minimal activity license from the County Clerk. The license fee is $30 for a business inside Nashville city limits (Urban Service District) and $15 outside city limits but within Davidson County. Report gross receipts to the Tennessee Department of Revenue with the annual business tax return.",
|
|
11089
11098
|
frequency: "once",
|
|
11090
11099
|
url: "https://www.nashville.gov/departments/county-clerk/business-services/apply-business-license",
|
|
11091
11100
|
appliesTo: ["all"]
|
|
11092
11101
|
}
|
|
11093
11102
|
],
|
|
11094
|
-
aliases: ["Nashville-Davidson", "Metro Nashville"]
|
|
11103
|
+
aliases: ["Nashville-Davidson", "Metro Nashville"],
|
|
11104
|
+
checkedOn: "2026-10-16"
|
|
11095
11105
|
}
|
|
11096
11106
|
];
|
|
11097
11107
|
|
|
@@ -11128,11 +11138,11 @@ var TX_default2 = [
|
|
|
11128
11138
|
state: "TX",
|
|
11129
11139
|
city: "Austin",
|
|
11130
11140
|
status: "unverified",
|
|
11131
|
-
note: "The city's start-a-business page
|
|
11141
|
+
note: "The city's start-a-business page says Texas has no general business license, that most Austin businesses need permits or licenses depending on type, location and activity (issued through Austin Development Services), and lists no general city business license. Business personal property tax is administered by the Travis County Appraisal District, not the city.",
|
|
11132
11142
|
counties: ["Travis"],
|
|
11133
11143
|
sourceUrl: "https://www.austintexas.gov/economic-development/start-business",
|
|
11134
11144
|
items: [],
|
|
11135
|
-
checkedOn: "2026-10-
|
|
11145
|
+
checkedOn: "2026-10-16"
|
|
11136
11146
|
},
|
|
11137
11147
|
{
|
|
11138
11148
|
state: "TX",
|
|
@@ -19083,6 +19093,11 @@ function todayIso(now = /* @__PURE__ */ new Date()) {
|
|
|
19083
19093
|
const pad3 = (n) => String(n).padStart(2, "0");
|
|
19084
19094
|
return `${now.getFullYear()}-${pad3(now.getMonth() + 1)}-${pad3(now.getDate())}`;
|
|
19085
19095
|
}
|
|
19096
|
+
function addDays(iso2, days) {
|
|
19097
|
+
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
19098
|
+
d.setUTCDate(d.getUTCDate() + days);
|
|
19099
|
+
return d.toISOString().slice(0, 10);
|
|
19100
|
+
}
|
|
19086
19101
|
|
|
19087
19102
|
// src/validate.ts
|
|
19088
19103
|
var ENUMS = {
|
|
@@ -19817,11 +19832,6 @@ function occurrencesBetween(due, ctx, from, to) {
|
|
|
19817
19832
|
|
|
19818
19833
|
// src/provenance.ts
|
|
19819
19834
|
var REVIEW_INTERVAL_DAYS = 365;
|
|
19820
|
-
function addDays(iso2, days) {
|
|
19821
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
19822
|
-
d.setUTCDate(d.getUTCDate() + days);
|
|
19823
|
-
return d.toISOString().slice(0, 10);
|
|
19824
|
-
}
|
|
19825
19835
|
function sourceKind(url) {
|
|
19826
19836
|
if (/\.pdf($|[?#])/i.test(url)) return "pdf";
|
|
19827
19837
|
if (/municode|amlegal|ordinance|codelibrary/i.test(url)) return "ordinance";
|
|
@@ -20833,7 +20843,6 @@ function resolveProfile(input) {
|
|
|
20833
20843
|
taxTreatment
|
|
20834
20844
|
};
|
|
20835
20845
|
}
|
|
20836
|
-
var today = () => todayIso();
|
|
20837
20846
|
function industryFromNaics(naics) {
|
|
20838
20847
|
if (!naics) return void 0;
|
|
20839
20848
|
if (naics.startsWith("23")) return "construction";
|
|
@@ -20849,14 +20858,9 @@ var RENEWAL_INTERVAL = {
|
|
|
20849
20858
|
every_five_years: "five years"
|
|
20850
20859
|
};
|
|
20851
20860
|
var FEEDBACK_URL = "https://github.com/Alisa007/business-obligations/issues/new?template=data-correction.yml&title=";
|
|
20852
|
-
var addDays2 = (iso2, days) => {
|
|
20853
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
20854
|
-
d.setUTCDate(d.getUTCDate() + days);
|
|
20855
|
-
return d.toISOString().slice(0, 10);
|
|
20856
|
-
};
|
|
20857
20861
|
function evaluate(input, options = {}) {
|
|
20858
20862
|
const profile = resolveProfile(input);
|
|
20859
|
-
const asOf = options.asOf ??
|
|
20863
|
+
const asOf = options.asOf ?? todayIso();
|
|
20860
20864
|
if (!isIsoDate(asOf)) throw new InvalidProfileError("`asOf` must be YYYY-MM-DD");
|
|
20861
20865
|
const rules = options.rules ?? RULE_PACKS[profile.country];
|
|
20862
20866
|
const changes = [...BUNDLED_CHANGES, ...options.changes ?? []];
|
|
@@ -20914,7 +20918,7 @@ function evaluate(input, options = {}) {
|
|
|
20914
20918
|
}
|
|
20915
20919
|
const states = /* @__PURE__ */ new Set([profile.formationState, ...profile.presence.map((x) => x.state)]);
|
|
20916
20920
|
const relevant = (c) => c.scope.state ? states.has(c.scope.state) : !c.scope.rules || items.some((it) => changeMatchesItem(c, it));
|
|
20917
|
-
const since =
|
|
20921
|
+
const since = addDays(asOf, -(options.recentDays ?? 365));
|
|
20918
20922
|
const upcomingChanges = changes.filter((c) => c.effective > asOf && relevant(c)).sort((a, b) => a.effective.localeCompare(b.effective)).map(toNotice);
|
|
20919
20923
|
const recentChanges = changes.filter((c) => c.effective <= asOf && c.effective >= since && relevant(c)).sort((a, b) => b.effective.localeCompare(a.effective)).map(toNotice);
|
|
20920
20924
|
return {
|
|
@@ -21014,12 +21018,6 @@ function estimateCosts(items, options = {}) {
|
|
|
21014
21018
|
}
|
|
21015
21019
|
|
|
21016
21020
|
// src/calendar.ts
|
|
21017
|
-
var today2 = () => todayIso();
|
|
21018
|
-
var addDays3 = (iso2, n) => {
|
|
21019
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
21020
|
-
d.setUTCDate(d.getUTCDate() + n);
|
|
21021
|
-
return d.toISOString().slice(0, 10);
|
|
21022
|
-
};
|
|
21023
21021
|
function toEvent(item, date) {
|
|
21024
21022
|
return {
|
|
21025
21023
|
date,
|
|
@@ -21037,9 +21035,9 @@ function toEvent(item, date) {
|
|
|
21037
21035
|
};
|
|
21038
21036
|
}
|
|
21039
21037
|
function buildCalendar(input, options = {}) {
|
|
21040
|
-
const from = options.from ??
|
|
21038
|
+
const from = options.from ?? todayIso();
|
|
21041
21039
|
if (!isIsoDate(from)) throw new InvalidProfileError("`from` must be YYYY-MM-DD");
|
|
21042
|
-
const to = options.to ??
|
|
21040
|
+
const to = options.to ?? addDays(from, 365);
|
|
21043
21041
|
if (!isIsoDate(to)) throw new InvalidProfileError("`to` must be YYYY-MM-DD");
|
|
21044
21042
|
if (to < from) throw new InvalidProfileError("`to` must not be before `from`");
|
|
21045
21043
|
const evalOptions = {
|
|
@@ -21055,7 +21053,7 @@ function buildCalendar(input, options = {}) {
|
|
|
21055
21053
|
snapshots.push({ start: d, result: evaluate(input, { ...evalOptions, asOf: d }) });
|
|
21056
21054
|
const events = [];
|
|
21057
21055
|
snapshots.forEach((snap, i) => {
|
|
21058
|
-
const end = i + 1 < snapshots.length ?
|
|
21056
|
+
const end = i + 1 < snapshots.length ? addDays(snapshots[i + 1].start, -1) : to;
|
|
21059
21057
|
for (const item of snap.result.items) {
|
|
21060
21058
|
if (!item.due) continue;
|
|
21061
21059
|
const dates = occurrencesBetween(
|
|
@@ -21092,7 +21090,7 @@ function fold(line) {
|
|
|
21092
21090
|
}
|
|
21093
21091
|
var compact = (iso2) => iso2.replace(/-/g, "");
|
|
21094
21092
|
function toICS(events, options = {}) {
|
|
21095
|
-
const stamp = compact(options.stamp ?? events[0]?.date ??
|
|
21093
|
+
const stamp = compact(options.stamp ?? events[0]?.date ?? todayIso());
|
|
21096
21094
|
const lines = [
|
|
21097
21095
|
"BEGIN:VCALENDAR",
|
|
21098
21096
|
"VERSION:2.0",
|
|
@@ -21114,7 +21112,7 @@ function toICS(events, options = {}) {
|
|
|
21114
21112
|
`UID:${e.itemId}-${e.date}@business-obligations`,
|
|
21115
21113
|
`DTSTAMP:${stamp}T000000Z`,
|
|
21116
21114
|
`DTSTART;VALUE=DATE:${compact(e.date)}`,
|
|
21117
|
-
`DTEND;VALUE=DATE:${compact(
|
|
21115
|
+
`DTEND;VALUE=DATE:${compact(addDays(e.date, 1))}`,
|
|
21118
21116
|
`SUMMARY:${esc(e.title)}`,
|
|
21119
21117
|
`DESCRIPTION:${esc(parts.join("\n"))}`,
|
|
21120
21118
|
...e.url ? [`URL:${e.url}`] : [],
|
|
@@ -21305,20 +21303,14 @@ function phaseOf(item) {
|
|
|
21305
21303
|
if (item.category === "recordkeeping" || item.category === "insurance") return "employ";
|
|
21306
21304
|
return "operate";
|
|
21307
21305
|
}
|
|
21308
|
-
var addDays4 = (iso2, n) => {
|
|
21309
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
21310
|
-
d.setUTCDate(d.getUTCDate() + n);
|
|
21311
|
-
return d.toISOString().slice(0, 10);
|
|
21312
|
-
};
|
|
21313
21306
|
var daysBetween = (a, b) => Math.round((Date.parse(`${b}T00:00:00Z`) - Date.parse(`${a}T00:00:00Z`)) / 864e5);
|
|
21314
|
-
var today3 = () => todayIso();
|
|
21315
21307
|
function planLaunch(input, options = {}) {
|
|
21316
|
-
const startDate = options.startDate ??
|
|
21308
|
+
const startDate = options.startDate ?? todayIso();
|
|
21317
21309
|
const allowance = { ...DEFAULT_ALLOWANCE, ...options.allowanceDays };
|
|
21318
21310
|
const windows = /* @__PURE__ */ new Map();
|
|
21319
21311
|
let cursor = startDate;
|
|
21320
21312
|
for (const id of ["prepare", "form", "identify", "register", "license", "employ"]) {
|
|
21321
|
-
const end =
|
|
21313
|
+
const end = addDays(cursor, allowance[id]);
|
|
21322
21314
|
windows.set(id, { start: cursor, end });
|
|
21323
21315
|
cursor = end;
|
|
21324
21316
|
}
|
|
@@ -21415,7 +21407,7 @@ function planLaunch(input, options = {}) {
|
|
|
21415
21407
|
// package.json
|
|
21416
21408
|
var package_default = {
|
|
21417
21409
|
name: "business-obligations",
|
|
21418
|
-
version: "0.3.
|
|
21410
|
+
version: "0.3.1",
|
|
21419
21411
|
description: "Open-source TypeScript rules engine: describe a US business, get the licenses, permits, filings and deadlines it needs, ordered and sourced. Zero dependencies.",
|
|
21420
21412
|
license: "MIT",
|
|
21421
21413
|
type: "module",
|
package/dist/index.cjs
CHANGED
|
@@ -9926,11 +9926,20 @@ var MN_default2 = [
|
|
|
9926
9926
|
{
|
|
9927
9927
|
state: "MN",
|
|
9928
9928
|
city: "Minneapolis",
|
|
9929
|
-
status: "unverified",
|
|
9930
|
-
note: "Licensing appears to be industry-specific through Business Licenses and Consumer Services; the city's own list was not confirmed.",
|
|
9931
9929
|
counties: ["Hennepin"],
|
|
9932
|
-
items: [
|
|
9933
|
-
|
|
9930
|
+
items: [
|
|
9931
|
+
{
|
|
9932
|
+
id: "minneapolis.sick-and-safe-time",
|
|
9933
|
+
title: "Provide Minneapolis sick and safe time",
|
|
9934
|
+
category: "recordkeeping",
|
|
9935
|
+
authority: "City of Minneapolis Labor Standards Enforcement",
|
|
9936
|
+
description: "Employers must give employees paid sick and safe time: 1 hour for every 30 hours worked, up to 48 hours a year and 80 hours overall, or front-load 48 hours a year. Keep a written policy and give it to new hires, display the Minneapolis labor standards poster in each language spoken by 5% or more of employees, and show employees the hours used and available each pay period.",
|
|
9937
|
+
frequency: "ongoing",
|
|
9938
|
+
url: "https://sicktimeinfo.minneapolismn.gov/employer-resources.html",
|
|
9939
|
+
appliesTo: ["employees"]
|
|
9940
|
+
}
|
|
9941
|
+
],
|
|
9942
|
+
checkedOn: "2026-10-16"
|
|
9934
9943
|
},
|
|
9935
9944
|
{
|
|
9936
9945
|
state: "MN",
|
|
@@ -11143,13 +11152,14 @@ var TN_default2 = [
|
|
|
11143
11152
|
title: "Obtain Nashville / Davidson County business license",
|
|
11144
11153
|
category: "license",
|
|
11145
11154
|
authority: "Davidson County Clerk, Business Tax Division",
|
|
11146
|
-
description: "Businesses in Nashville-Davidson County obtain a business license from the County Clerk and
|
|
11155
|
+
description: "Businesses in Nashville-Davidson County obtain a business tax license or a minimal activity license from the County Clerk. The license fee is $30 for a business inside Nashville city limits (Urban Service District) and $15 outside city limits but within Davidson County. Report gross receipts to the Tennessee Department of Revenue with the annual business tax return.",
|
|
11147
11156
|
frequency: "once",
|
|
11148
11157
|
url: "https://www.nashville.gov/departments/county-clerk/business-services/apply-business-license",
|
|
11149
11158
|
appliesTo: ["all"]
|
|
11150
11159
|
}
|
|
11151
11160
|
],
|
|
11152
|
-
aliases: ["Nashville-Davidson", "Metro Nashville"]
|
|
11161
|
+
aliases: ["Nashville-Davidson", "Metro Nashville"],
|
|
11162
|
+
checkedOn: "2026-10-16"
|
|
11153
11163
|
}
|
|
11154
11164
|
];
|
|
11155
11165
|
|
|
@@ -11186,11 +11196,11 @@ var TX_default2 = [
|
|
|
11186
11196
|
state: "TX",
|
|
11187
11197
|
city: "Austin",
|
|
11188
11198
|
status: "unverified",
|
|
11189
|
-
note: "The city's start-a-business page
|
|
11199
|
+
note: "The city's start-a-business page says Texas has no general business license, that most Austin businesses need permits or licenses depending on type, location and activity (issued through Austin Development Services), and lists no general city business license. Business personal property tax is administered by the Travis County Appraisal District, not the city.",
|
|
11190
11200
|
counties: ["Travis"],
|
|
11191
11201
|
sourceUrl: "https://www.austintexas.gov/economic-development/start-business",
|
|
11192
11202
|
items: [],
|
|
11193
|
-
checkedOn: "2026-10-
|
|
11203
|
+
checkedOn: "2026-10-16"
|
|
11194
11204
|
},
|
|
11195
11205
|
{
|
|
11196
11206
|
state: "TX",
|
|
@@ -19141,6 +19151,11 @@ function todayIso(now = /* @__PURE__ */ new Date()) {
|
|
|
19141
19151
|
const pad3 = (n) => String(n).padStart(2, "0");
|
|
19142
19152
|
return `${now.getFullYear()}-${pad3(now.getMonth() + 1)}-${pad3(now.getDate())}`;
|
|
19143
19153
|
}
|
|
19154
|
+
function addDays(iso2, days) {
|
|
19155
|
+
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
19156
|
+
d.setUTCDate(d.getUTCDate() + days);
|
|
19157
|
+
return d.toISOString().slice(0, 10);
|
|
19158
|
+
}
|
|
19144
19159
|
|
|
19145
19160
|
// src/validate.ts
|
|
19146
19161
|
var ENUMS = {
|
|
@@ -19876,11 +19891,6 @@ function occurrencesBetween(due, ctx, from, to) {
|
|
|
19876
19891
|
|
|
19877
19892
|
// src/provenance.ts
|
|
19878
19893
|
var REVIEW_INTERVAL_DAYS = 365;
|
|
19879
|
-
function addDays(iso2, days) {
|
|
19880
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
19881
|
-
d.setUTCDate(d.getUTCDate() + days);
|
|
19882
|
-
return d.toISOString().slice(0, 10);
|
|
19883
|
-
}
|
|
19884
19894
|
function sourceKind(url) {
|
|
19885
19895
|
if (/\.pdf($|[?#])/i.test(url)) return "pdf";
|
|
19886
19896
|
if (/municode|amlegal|ordinance|codelibrary/i.test(url)) return "ordinance";
|
|
@@ -20892,7 +20902,6 @@ function resolveProfile(input) {
|
|
|
20892
20902
|
taxTreatment
|
|
20893
20903
|
};
|
|
20894
20904
|
}
|
|
20895
|
-
var today = () => todayIso();
|
|
20896
20905
|
function industryFromNaics(naics) {
|
|
20897
20906
|
if (!naics) return void 0;
|
|
20898
20907
|
if (naics.startsWith("23")) return "construction";
|
|
@@ -20908,14 +20917,9 @@ var RENEWAL_INTERVAL = {
|
|
|
20908
20917
|
every_five_years: "five years"
|
|
20909
20918
|
};
|
|
20910
20919
|
var FEEDBACK_URL = "https://github.com/Alisa007/business-obligations/issues/new?template=data-correction.yml&title=";
|
|
20911
|
-
var addDays2 = (iso2, days) => {
|
|
20912
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
20913
|
-
d.setUTCDate(d.getUTCDate() + days);
|
|
20914
|
-
return d.toISOString().slice(0, 10);
|
|
20915
|
-
};
|
|
20916
20920
|
function evaluate(input, options = {}) {
|
|
20917
20921
|
const profile = resolveProfile(input);
|
|
20918
|
-
const asOf = options.asOf ??
|
|
20922
|
+
const asOf = options.asOf ?? todayIso();
|
|
20919
20923
|
if (!isIsoDate(asOf)) throw new InvalidProfileError("`asOf` must be YYYY-MM-DD");
|
|
20920
20924
|
const rules = options.rules ?? RULE_PACKS[profile.country];
|
|
20921
20925
|
const changes = [...BUNDLED_CHANGES, ...options.changes ?? []];
|
|
@@ -20973,7 +20977,7 @@ function evaluate(input, options = {}) {
|
|
|
20973
20977
|
}
|
|
20974
20978
|
const states = /* @__PURE__ */ new Set([profile.formationState, ...profile.presence.map((x) => x.state)]);
|
|
20975
20979
|
const relevant = (c) => c.scope.state ? states.has(c.scope.state) : !c.scope.rules || items.some((it) => changeMatchesItem(c, it));
|
|
20976
|
-
const since =
|
|
20980
|
+
const since = addDays(asOf, -(options.recentDays ?? 365));
|
|
20977
20981
|
const upcomingChanges = changes.filter((c) => c.effective > asOf && relevant(c)).sort((a, b) => a.effective.localeCompare(b.effective)).map(toNotice);
|
|
20978
20982
|
const recentChanges = changes.filter((c) => c.effective <= asOf && c.effective >= since && relevant(c)).sort((a, b) => b.effective.localeCompare(a.effective)).map(toNotice);
|
|
20979
20983
|
return {
|
|
@@ -21018,7 +21022,7 @@ function diffItems(before, after) {
|
|
|
21018
21022
|
};
|
|
21019
21023
|
}
|
|
21020
21024
|
function previewChanges(input, options) {
|
|
21021
|
-
const from = options.from ??
|
|
21025
|
+
const from = options.from ?? todayIso();
|
|
21022
21026
|
const base = { rules: options.rules, changes: options.changes };
|
|
21023
21027
|
const before = evaluate(input, { ...base, asOf: from });
|
|
21024
21028
|
const after = evaluate(input, { ...base, asOf: options.to });
|
|
@@ -21113,12 +21117,6 @@ function estimateCosts(items, options = {}) {
|
|
|
21113
21117
|
}
|
|
21114
21118
|
|
|
21115
21119
|
// src/calendar.ts
|
|
21116
|
-
var today2 = () => todayIso();
|
|
21117
|
-
var addDays3 = (iso2, n) => {
|
|
21118
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
21119
|
-
d.setUTCDate(d.getUTCDate() + n);
|
|
21120
|
-
return d.toISOString().slice(0, 10);
|
|
21121
|
-
};
|
|
21122
21120
|
function toEvent(item, date) {
|
|
21123
21121
|
return {
|
|
21124
21122
|
date,
|
|
@@ -21136,9 +21134,9 @@ function toEvent(item, date) {
|
|
|
21136
21134
|
};
|
|
21137
21135
|
}
|
|
21138
21136
|
function buildCalendar(input, options = {}) {
|
|
21139
|
-
const from = options.from ??
|
|
21137
|
+
const from = options.from ?? todayIso();
|
|
21140
21138
|
if (!isIsoDate(from)) throw new InvalidProfileError("`from` must be YYYY-MM-DD");
|
|
21141
|
-
const to = options.to ??
|
|
21139
|
+
const to = options.to ?? addDays(from, 365);
|
|
21142
21140
|
if (!isIsoDate(to)) throw new InvalidProfileError("`to` must be YYYY-MM-DD");
|
|
21143
21141
|
if (to < from) throw new InvalidProfileError("`to` must not be before `from`");
|
|
21144
21142
|
const evalOptions = {
|
|
@@ -21154,7 +21152,7 @@ function buildCalendar(input, options = {}) {
|
|
|
21154
21152
|
snapshots.push({ start: d, result: evaluate(input, { ...evalOptions, asOf: d }) });
|
|
21155
21153
|
const events = [];
|
|
21156
21154
|
snapshots.forEach((snap, i) => {
|
|
21157
|
-
const end = i + 1 < snapshots.length ?
|
|
21155
|
+
const end = i + 1 < snapshots.length ? addDays(snapshots[i + 1].start, -1) : to;
|
|
21158
21156
|
for (const item of snap.result.items) {
|
|
21159
21157
|
if (!item.due) continue;
|
|
21160
21158
|
const dates = occurrencesBetween(
|
|
@@ -21191,7 +21189,7 @@ function fold(line) {
|
|
|
21191
21189
|
}
|
|
21192
21190
|
var compact = (iso2) => iso2.replace(/-/g, "");
|
|
21193
21191
|
function toICS(events, options = {}) {
|
|
21194
|
-
const stamp = compact(options.stamp ?? events[0]?.date ??
|
|
21192
|
+
const stamp = compact(options.stamp ?? events[0]?.date ?? todayIso());
|
|
21195
21193
|
const lines = [
|
|
21196
21194
|
"BEGIN:VCALENDAR",
|
|
21197
21195
|
"VERSION:2.0",
|
|
@@ -21213,7 +21211,7 @@ function toICS(events, options = {}) {
|
|
|
21213
21211
|
`UID:${e.itemId}-${e.date}@business-obligations`,
|
|
21214
21212
|
`DTSTAMP:${stamp}T000000Z`,
|
|
21215
21213
|
`DTSTART;VALUE=DATE:${compact(e.date)}`,
|
|
21216
|
-
`DTEND;VALUE=DATE:${compact(
|
|
21214
|
+
`DTEND;VALUE=DATE:${compact(addDays(e.date, 1))}`,
|
|
21217
21215
|
`SUMMARY:${esc(e.title)}`,
|
|
21218
21216
|
`DESCRIPTION:${esc(parts.join("\n"))}`,
|
|
21219
21217
|
...e.url ? [`URL:${e.url}`] : [],
|
|
@@ -21528,20 +21526,14 @@ function phaseOf(item) {
|
|
|
21528
21526
|
if (item.category === "recordkeeping" || item.category === "insurance") return "employ";
|
|
21529
21527
|
return "operate";
|
|
21530
21528
|
}
|
|
21531
|
-
var addDays4 = (iso2, n) => {
|
|
21532
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
21533
|
-
d.setUTCDate(d.getUTCDate() + n);
|
|
21534
|
-
return d.toISOString().slice(0, 10);
|
|
21535
|
-
};
|
|
21536
21529
|
var daysBetween = (a, b) => Math.round((Date.parse(`${b}T00:00:00Z`) - Date.parse(`${a}T00:00:00Z`)) / 864e5);
|
|
21537
|
-
var today3 = () => todayIso();
|
|
21538
21530
|
function planLaunch(input, options = {}) {
|
|
21539
|
-
const startDate = options.startDate ??
|
|
21531
|
+
const startDate = options.startDate ?? todayIso();
|
|
21540
21532
|
const allowance = { ...DEFAULT_ALLOWANCE, ...options.allowanceDays };
|
|
21541
21533
|
const windows = /* @__PURE__ */ new Map();
|
|
21542
21534
|
let cursor = startDate;
|
|
21543
21535
|
for (const id of ["prepare", "form", "identify", "register", "license", "employ"]) {
|
|
21544
|
-
const end =
|
|
21536
|
+
const end = addDays(cursor, allowance[id]);
|
|
21545
21537
|
windows.set(id, { start: cursor, end });
|
|
21546
21538
|
cursor = end;
|
|
21547
21539
|
}
|
package/dist/index.js
CHANGED
|
@@ -9863,11 +9863,20 @@ var MN_default2 = [
|
|
|
9863
9863
|
{
|
|
9864
9864
|
state: "MN",
|
|
9865
9865
|
city: "Minneapolis",
|
|
9866
|
-
status: "unverified",
|
|
9867
|
-
note: "Licensing appears to be industry-specific through Business Licenses and Consumer Services; the city's own list was not confirmed.",
|
|
9868
9866
|
counties: ["Hennepin"],
|
|
9869
|
-
items: [
|
|
9870
|
-
|
|
9867
|
+
items: [
|
|
9868
|
+
{
|
|
9869
|
+
id: "minneapolis.sick-and-safe-time",
|
|
9870
|
+
title: "Provide Minneapolis sick and safe time",
|
|
9871
|
+
category: "recordkeeping",
|
|
9872
|
+
authority: "City of Minneapolis Labor Standards Enforcement",
|
|
9873
|
+
description: "Employers must give employees paid sick and safe time: 1 hour for every 30 hours worked, up to 48 hours a year and 80 hours overall, or front-load 48 hours a year. Keep a written policy and give it to new hires, display the Minneapolis labor standards poster in each language spoken by 5% or more of employees, and show employees the hours used and available each pay period.",
|
|
9874
|
+
frequency: "ongoing",
|
|
9875
|
+
url: "https://sicktimeinfo.minneapolismn.gov/employer-resources.html",
|
|
9876
|
+
appliesTo: ["employees"]
|
|
9877
|
+
}
|
|
9878
|
+
],
|
|
9879
|
+
checkedOn: "2026-10-16"
|
|
9871
9880
|
},
|
|
9872
9881
|
{
|
|
9873
9882
|
state: "MN",
|
|
@@ -11080,13 +11089,14 @@ var TN_default2 = [
|
|
|
11080
11089
|
title: "Obtain Nashville / Davidson County business license",
|
|
11081
11090
|
category: "license",
|
|
11082
11091
|
authority: "Davidson County Clerk, Business Tax Division",
|
|
11083
|
-
description: "Businesses in Nashville-Davidson County obtain a business license from the County Clerk and
|
|
11092
|
+
description: "Businesses in Nashville-Davidson County obtain a business tax license or a minimal activity license from the County Clerk. The license fee is $30 for a business inside Nashville city limits (Urban Service District) and $15 outside city limits but within Davidson County. Report gross receipts to the Tennessee Department of Revenue with the annual business tax return.",
|
|
11084
11093
|
frequency: "once",
|
|
11085
11094
|
url: "https://www.nashville.gov/departments/county-clerk/business-services/apply-business-license",
|
|
11086
11095
|
appliesTo: ["all"]
|
|
11087
11096
|
}
|
|
11088
11097
|
],
|
|
11089
|
-
aliases: ["Nashville-Davidson", "Metro Nashville"]
|
|
11098
|
+
aliases: ["Nashville-Davidson", "Metro Nashville"],
|
|
11099
|
+
checkedOn: "2026-10-16"
|
|
11090
11100
|
}
|
|
11091
11101
|
];
|
|
11092
11102
|
|
|
@@ -11123,11 +11133,11 @@ var TX_default2 = [
|
|
|
11123
11133
|
state: "TX",
|
|
11124
11134
|
city: "Austin",
|
|
11125
11135
|
status: "unverified",
|
|
11126
|
-
note: "The city's start-a-business page
|
|
11136
|
+
note: "The city's start-a-business page says Texas has no general business license, that most Austin businesses need permits or licenses depending on type, location and activity (issued through Austin Development Services), and lists no general city business license. Business personal property tax is administered by the Travis County Appraisal District, not the city.",
|
|
11127
11137
|
counties: ["Travis"],
|
|
11128
11138
|
sourceUrl: "https://www.austintexas.gov/economic-development/start-business",
|
|
11129
11139
|
items: [],
|
|
11130
|
-
checkedOn: "2026-10-
|
|
11140
|
+
checkedOn: "2026-10-16"
|
|
11131
11141
|
},
|
|
11132
11142
|
{
|
|
11133
11143
|
state: "TX",
|
|
@@ -19078,6 +19088,11 @@ function todayIso(now = /* @__PURE__ */ new Date()) {
|
|
|
19078
19088
|
const pad3 = (n) => String(n).padStart(2, "0");
|
|
19079
19089
|
return `${now.getFullYear()}-${pad3(now.getMonth() + 1)}-${pad3(now.getDate())}`;
|
|
19080
19090
|
}
|
|
19091
|
+
function addDays(iso2, days) {
|
|
19092
|
+
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
19093
|
+
d.setUTCDate(d.getUTCDate() + days);
|
|
19094
|
+
return d.toISOString().slice(0, 10);
|
|
19095
|
+
}
|
|
19081
19096
|
|
|
19082
19097
|
// src/validate.ts
|
|
19083
19098
|
var ENUMS = {
|
|
@@ -19813,11 +19828,6 @@ function occurrencesBetween(due, ctx, from, to) {
|
|
|
19813
19828
|
|
|
19814
19829
|
// src/provenance.ts
|
|
19815
19830
|
var REVIEW_INTERVAL_DAYS = 365;
|
|
19816
|
-
function addDays(iso2, days) {
|
|
19817
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
19818
|
-
d.setUTCDate(d.getUTCDate() + days);
|
|
19819
|
-
return d.toISOString().slice(0, 10);
|
|
19820
|
-
}
|
|
19821
19831
|
function sourceKind(url) {
|
|
19822
19832
|
if (/\.pdf($|[?#])/i.test(url)) return "pdf";
|
|
19823
19833
|
if (/municode|amlegal|ordinance|codelibrary/i.test(url)) return "ordinance";
|
|
@@ -20829,7 +20839,6 @@ function resolveProfile(input) {
|
|
|
20829
20839
|
taxTreatment
|
|
20830
20840
|
};
|
|
20831
20841
|
}
|
|
20832
|
-
var today = () => todayIso();
|
|
20833
20842
|
function industryFromNaics(naics) {
|
|
20834
20843
|
if (!naics) return void 0;
|
|
20835
20844
|
if (naics.startsWith("23")) return "construction";
|
|
@@ -20845,14 +20854,9 @@ var RENEWAL_INTERVAL = {
|
|
|
20845
20854
|
every_five_years: "five years"
|
|
20846
20855
|
};
|
|
20847
20856
|
var FEEDBACK_URL = "https://github.com/Alisa007/business-obligations/issues/new?template=data-correction.yml&title=";
|
|
20848
|
-
var addDays2 = (iso2, days) => {
|
|
20849
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
20850
|
-
d.setUTCDate(d.getUTCDate() + days);
|
|
20851
|
-
return d.toISOString().slice(0, 10);
|
|
20852
|
-
};
|
|
20853
20857
|
function evaluate(input, options = {}) {
|
|
20854
20858
|
const profile = resolveProfile(input);
|
|
20855
|
-
const asOf = options.asOf ??
|
|
20859
|
+
const asOf = options.asOf ?? todayIso();
|
|
20856
20860
|
if (!isIsoDate(asOf)) throw new InvalidProfileError("`asOf` must be YYYY-MM-DD");
|
|
20857
20861
|
const rules = options.rules ?? RULE_PACKS[profile.country];
|
|
20858
20862
|
const changes = [...BUNDLED_CHANGES, ...options.changes ?? []];
|
|
@@ -20910,7 +20914,7 @@ function evaluate(input, options = {}) {
|
|
|
20910
20914
|
}
|
|
20911
20915
|
const states = /* @__PURE__ */ new Set([profile.formationState, ...profile.presence.map((x) => x.state)]);
|
|
20912
20916
|
const relevant = (c) => c.scope.state ? states.has(c.scope.state) : !c.scope.rules || items.some((it) => changeMatchesItem(c, it));
|
|
20913
|
-
const since =
|
|
20917
|
+
const since = addDays(asOf, -(options.recentDays ?? 365));
|
|
20914
20918
|
const upcomingChanges = changes.filter((c) => c.effective > asOf && relevant(c)).sort((a, b) => a.effective.localeCompare(b.effective)).map(toNotice);
|
|
20915
20919
|
const recentChanges = changes.filter((c) => c.effective <= asOf && c.effective >= since && relevant(c)).sort((a, b) => b.effective.localeCompare(a.effective)).map(toNotice);
|
|
20916
20920
|
return {
|
|
@@ -20955,7 +20959,7 @@ function diffItems(before, after) {
|
|
|
20955
20959
|
};
|
|
20956
20960
|
}
|
|
20957
20961
|
function previewChanges(input, options) {
|
|
20958
|
-
const from = options.from ??
|
|
20962
|
+
const from = options.from ?? todayIso();
|
|
20959
20963
|
const base = { rules: options.rules, changes: options.changes };
|
|
20960
20964
|
const before = evaluate(input, { ...base, asOf: from });
|
|
20961
20965
|
const after = evaluate(input, { ...base, asOf: options.to });
|
|
@@ -21050,12 +21054,6 @@ function estimateCosts(items, options = {}) {
|
|
|
21050
21054
|
}
|
|
21051
21055
|
|
|
21052
21056
|
// src/calendar.ts
|
|
21053
|
-
var today2 = () => todayIso();
|
|
21054
|
-
var addDays3 = (iso2, n) => {
|
|
21055
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
21056
|
-
d.setUTCDate(d.getUTCDate() + n);
|
|
21057
|
-
return d.toISOString().slice(0, 10);
|
|
21058
|
-
};
|
|
21059
21057
|
function toEvent(item, date) {
|
|
21060
21058
|
return {
|
|
21061
21059
|
date,
|
|
@@ -21073,9 +21071,9 @@ function toEvent(item, date) {
|
|
|
21073
21071
|
};
|
|
21074
21072
|
}
|
|
21075
21073
|
function buildCalendar(input, options = {}) {
|
|
21076
|
-
const from = options.from ??
|
|
21074
|
+
const from = options.from ?? todayIso();
|
|
21077
21075
|
if (!isIsoDate(from)) throw new InvalidProfileError("`from` must be YYYY-MM-DD");
|
|
21078
|
-
const to = options.to ??
|
|
21076
|
+
const to = options.to ?? addDays(from, 365);
|
|
21079
21077
|
if (!isIsoDate(to)) throw new InvalidProfileError("`to` must be YYYY-MM-DD");
|
|
21080
21078
|
if (to < from) throw new InvalidProfileError("`to` must not be before `from`");
|
|
21081
21079
|
const evalOptions = {
|
|
@@ -21091,7 +21089,7 @@ function buildCalendar(input, options = {}) {
|
|
|
21091
21089
|
snapshots.push({ start: d, result: evaluate(input, { ...evalOptions, asOf: d }) });
|
|
21092
21090
|
const events = [];
|
|
21093
21091
|
snapshots.forEach((snap, i) => {
|
|
21094
|
-
const end = i + 1 < snapshots.length ?
|
|
21092
|
+
const end = i + 1 < snapshots.length ? addDays(snapshots[i + 1].start, -1) : to;
|
|
21095
21093
|
for (const item of snap.result.items) {
|
|
21096
21094
|
if (!item.due) continue;
|
|
21097
21095
|
const dates = occurrencesBetween(
|
|
@@ -21128,7 +21126,7 @@ function fold(line) {
|
|
|
21128
21126
|
}
|
|
21129
21127
|
var compact = (iso2) => iso2.replace(/-/g, "");
|
|
21130
21128
|
function toICS(events, options = {}) {
|
|
21131
|
-
const stamp = compact(options.stamp ?? events[0]?.date ??
|
|
21129
|
+
const stamp = compact(options.stamp ?? events[0]?.date ?? todayIso());
|
|
21132
21130
|
const lines = [
|
|
21133
21131
|
"BEGIN:VCALENDAR",
|
|
21134
21132
|
"VERSION:2.0",
|
|
@@ -21150,7 +21148,7 @@ function toICS(events, options = {}) {
|
|
|
21150
21148
|
`UID:${e.itemId}-${e.date}@business-obligations`,
|
|
21151
21149
|
`DTSTAMP:${stamp}T000000Z`,
|
|
21152
21150
|
`DTSTART;VALUE=DATE:${compact(e.date)}`,
|
|
21153
|
-
`DTEND;VALUE=DATE:${compact(
|
|
21151
|
+
`DTEND;VALUE=DATE:${compact(addDays(e.date, 1))}`,
|
|
21154
21152
|
`SUMMARY:${esc(e.title)}`,
|
|
21155
21153
|
`DESCRIPTION:${esc(parts.join("\n"))}`,
|
|
21156
21154
|
...e.url ? [`URL:${e.url}`] : [],
|
|
@@ -21465,20 +21463,14 @@ function phaseOf(item) {
|
|
|
21465
21463
|
if (item.category === "recordkeeping" || item.category === "insurance") return "employ";
|
|
21466
21464
|
return "operate";
|
|
21467
21465
|
}
|
|
21468
|
-
var addDays4 = (iso2, n) => {
|
|
21469
|
-
const d = /* @__PURE__ */ new Date(`${iso2}T00:00:00Z`);
|
|
21470
|
-
d.setUTCDate(d.getUTCDate() + n);
|
|
21471
|
-
return d.toISOString().slice(0, 10);
|
|
21472
|
-
};
|
|
21473
21466
|
var daysBetween = (a, b) => Math.round((Date.parse(`${b}T00:00:00Z`) - Date.parse(`${a}T00:00:00Z`)) / 864e5);
|
|
21474
|
-
var today3 = () => todayIso();
|
|
21475
21467
|
function planLaunch(input, options = {}) {
|
|
21476
|
-
const startDate = options.startDate ??
|
|
21468
|
+
const startDate = options.startDate ?? todayIso();
|
|
21477
21469
|
const allowance = { ...DEFAULT_ALLOWANCE, ...options.allowanceDays };
|
|
21478
21470
|
const windows = /* @__PURE__ */ new Map();
|
|
21479
21471
|
let cursor = startDate;
|
|
21480
21472
|
for (const id of ["prepare", "form", "identify", "register", "license", "employ"]) {
|
|
21481
|
-
const end =
|
|
21473
|
+
const end = addDays(cursor, allowance[id]);
|
|
21482
21474
|
windows.set(id, { start: cursor, end });
|
|
21483
21475
|
cursor = end;
|
|
21484
21476
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "business-obligations",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Open-source TypeScript rules engine: describe a US business, get the licenses, permits, filings and deadlines it needs, ordered and sourced. Zero dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|