{"_id":"@ambersecurityinc/notifly","_rev":"10-7f6dcb7ae14b96674436a94085f728a9","name":"@ambersecurityinc/notifly","dist-tags":{"latest":"0.7.2"},"versions":{"0.1.0":{"name":"@ambersecurityinc/notifly","version":"0.1.0","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.1.0","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"b6a5490d02a1bfa0f9ca65b709005b7524c07354","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.1.0.tgz","fileCount":6,"integrity":"sha512-QDd2PKdje9mmNswXZeDVXf7t8UeHCe1eUM+p9p/OKIWdhAGDXNtqaptR2HunZYTdqGpqbY1HAPD1w7q0ptMDSw==","signatures":[{"sig":"MEUCIQC7cYusjMlsXp81+ob5Vb6nNX3VjrUmVbtKzrrFR7/TMgIgPEKcOtB9F7vAFbh/HSMnMHDb3a1Rap1Tu+4MJAGzDCM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26274},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"464e86e927bf51e66838c2b978fe4a992d74582f","scripts":{"dev":"tsup src/index.ts --format esm,cjs --dts --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"00o-sh","email":"elibrody2@gmail.com"},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"10.8.2","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.2","typescript":"^6.0.2","@vitest/coverage-v8":"^4.1.2"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.1.0_1774543095156_0.6863828522522633","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ambersecurityinc/notifly","version":"0.2.0","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.2.0","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"f8dcd8112119373f89eb6f6e5d7c847d36c15610","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.2.0.tgz","fileCount":10,"integrity":"sha512-RoGGfWbhhzHKWMLMyV82cBukkO/z7SxB3h5mO5ONiCICw+rm+kq8DUcMgGQuS/4CxG5HevFcohobmkjlSi84QQ==","signatures":[{"sig":"MEUCIQCuibNr9XPIktA2ohsZ3vxrQTZ/UyDx7E+4nE44yk/DVQIgGBA0LXbSzJcP19ZCvhsxkPvJaarSugtT93ymALWj7x8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":117990},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"e431f704644fa31eb51505763a3af0e30d6c8441","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"00o-sh","email":"elibrody2@gmail.com"},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.11.0","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.2","typescript":"^6.0.2","@vitest/coverage-v8":"^4.1.2"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.2.0_1774545448817_0.34217750291494564","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ambersecurityinc/notifly","version":"0.3.0","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.3.0","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"7e60d2e140ff5a5de34580810f76ba01e3f4c44e","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.3.0.tgz","fileCount":10,"integrity":"sha512-U3r60GShx1YLJIfUzpUJLS0wddWBt6Ot2bk/o/RxPmwO+ht7TjHXO7Q84Uf6O7UiFwRYAjXcWv1LEN7tFxYYzw==","signatures":[{"sig":"MEYCIQDVei4zu2sPxFde3HmdCbt43YJ0SqiMxd/Wc0G/3nnXDAIhANo8HIqemAZ5z31b4N2XXcb7oOgvcE5Nwn31ZR0mqXrB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":117986},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"b1a2207c76e38ed0ced13e990fad1929e2ca0438","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"00o-sh","email":"elibrody2@gmail.com"},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.11.0","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","vitest":"4.1.2","typescript":"6.0.2","@vitest/coverage-v8":"4.1.2"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.3.0_1774653091969_0.3966544590619794","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ambersecurityinc/notifly","version":"0.4.0","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.4.0","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"ed950e83605085c8b6cb9d5c72e80a07c1d3fbe9","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.4.0.tgz","fileCount":10,"integrity":"sha512-zR/xxDYRW7eCQxk6fUw4oMU258XlS89JlRqS9To0vAoxYnOQW99+uCYyzQ57WiKcQWClBtu6ugZQBgh9mgx8fA==","signatures":[{"sig":"MEYCIQD0sXMxO6sOfzCXmFq0nWRbRdpkMvVDj00fy7Fwa4+pzwIhAIIKjRZlZmawXGq8lz9eBTAaCiRjvdfurHstnwhh4LOe","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambersecurityinc%2fnotifly@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132870},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"8288dded8460df0134cfe4995b87e12722fff68b","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --clean","release":"changeset publish","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d4cfc0c1-48ed-4821-bca2-af62b0941e2d"}},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.11.0","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","vitest":"4.1.4","typescript":"6.0.2","@changesets/cli":"^2.30.0","@vitest/coverage-v8":"4.1.4"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.4.0_1776094378796_0.2631252020096153","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@ambersecurityinc/notifly","version":"0.5.0","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.5.0","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"c7ef7f389a0bbb9e12d30bf3054009119df41299","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.5.0.tgz","fileCount":10,"integrity":"sha512-6DHzUkoyDO/itMzai60FnPol8o4RhUU8u1yzdmbzoigqaDvxXiyukSh8THuz90RomNUeIz7hwgFHOEhAHx/+jw==","signatures":[{"sig":"MEQCIGIXlkUqRRssmFG4oVfqk39jqXtBg4Z+FMNgiUbPiRnPAiBojyFqHeWZtmjcnB+fm60nn2Brq9rldptoiTRTpTAUNA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambersecurityinc%2fnotifly@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132869},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"9c6d83392dce8005cf46e003374554cb9bac1247","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --clean","release":"changeset publish","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d4cfc0c1-48ed-4821-bca2-af62b0941e2d"}},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.11.0","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","vitest":"4.1.4","typescript":"6.0.2","@changesets/cli":"2.30.0","@vitest/coverage-v8":"4.1.4"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.5.0_1776095433295_0.9491608309444368","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@ambersecurityinc/notifly","version":"0.5.1","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.5.1","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"70b4fd563ecf469b04cc8b17831c580b2eae43cd","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.5.1.tgz","fileCount":10,"integrity":"sha512-I547csI+aBwIgUx3cqtZAWINNJPPXwu/6dsHJfAso+FpLE7CKVbVVkHkEifSIJzOFvIEUTIftnWjoRb8Sy41iA==","signatures":[{"sig":"MEUCIHrVWA2fnGwBmXklJwEemtarUwlnxVI6cs6gB36eE+ykAiEA2ClpYxt6TlL9jaQm9S2xiB5jFwCm0Qc+OHJ/8DY3Ho4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambersecurityinc%2fnotifly@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132869},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"24f9e2bb18e915ca702dd86bf79052c4cd63f730","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --dts --clean","release":"changeset publish","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d4cfc0c1-48ed-4821-bca2-af62b0941e2d"}},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.12.1","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","vitest":"4.1.7","typescript":"6.0.3","@changesets/cli":"2.31.0","@vitest/coverage-v8":"4.1.7"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.5.1_1779312787381_0.3913777649534682","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@ambersecurityinc/notifly","version":"0.6.0","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.6.0","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"d18d0890700d2a8f297a588ad62c6b70c148c503","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.6.0.tgz","fileCount":32,"integrity":"sha512-6MepLQrOc6KzYAzth9k+5qo+uAAFSIMqW2ad0tY4Z/wJ6rmxTu4mo62Erg0KCzK+iM/3Vgx2UQCe8TcbWmfmSw==","signatures":[{"sig":"MEYCIQD4/27sqvhW0o6qppk7HvCPi9B57Rl3MOLwD+RbJOX3eQIhAJvj1/EMD/Oxh5AJQBES+/RPcczzb4S25duE4p26QAqZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambersecurityinc%2fnotifly@0.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":151332},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"196ebdd04fd081be2b640d5ea1e26a043150e26f","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --clean && tsc -p tsconfig.build.json","release":"changeset publish","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d4cfc0c1-48ed-4821-bca2-af62b0941e2d"}},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.16.0","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","vitest":"4.1.10","typescript":"7.0.2","@changesets/cli":"2.31.0","@vitest/coverage-v8":"4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.6.0_1783643060295_0.36434449474254116","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@ambersecurityinc/notifly","version":"0.7.0","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.7.0","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"b27fe59f29cfbcadfb9c5d8aaeb8f6f5189bbdfa","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.7.0.tgz","fileCount":32,"integrity":"sha512-uqwZseaYYvLrRZoJmURQwuNXttPyouD8LTVxlFG1YTm3xFOyF/6rG7GGqn+pB6qo7QBduFrn05ctuxboubpk7g==","signatures":[{"sig":"MEUCIQDhXdV7lyWPFxeLEc7tBuehU/XSlPlPsN4tLoYfDF70OwIgCSJuO6m4sGDXhVPdDOjMinNA0z4EZgsjoYvjf5Ivtv8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambersecurityinc%2fnotifly@0.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":159062},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"aab3431399a849889c90fa26e38e5f785ea79533","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --clean && tsc -p tsconfig.build.json","release":"changeset publish","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d4cfc0c1-48ed-4821-bca2-af62b0941e2d"}},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.16.0","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","vitest":"4.1.10","typescript":"7.0.2","@changesets/cli":"2.31.0","@vitest/coverage-v8":"4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.7.0_1783646383520_0.9767076371053842","host":"s3://npm-registry-packages-npm-production"}},"0.7.1":{"name":"@ambersecurityinc/notifly","version":"0.7.1","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","_id":"@ambersecurityinc/notifly@0.7.1","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"homepage":"https://github.com/ambersecurityinc/notifly#readme","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"dist":{"shasum":"7c7033bbca966d178398007c4627d16c40376fb6","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.7.1.tgz","fileCount":32,"integrity":"sha512-RxUXYWQeHkufLau6cNAWF43AoFIzOqLpPK6ZI4dI4l84rV3ZD8+M9izGxpjw/w3Zpy/k2P189/fntig+0tasHg==","signatures":[{"sig":"MEYCIQCNaNVOXy87pYIMOSk70qJ5lHRTNIxqS1t6w4HByh2GqAIhAJbM/gD0PNss4pWHv2bc0U0H3MlbEnQ2GV+OcSYajh/K","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambersecurityinc%2fnotifly@0.7.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":159128},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"gitHead":"978e7f9ef096655676c8780e0a24ee944ebee048","scripts":{"dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --clean && tsc -p tsconfig.build.json","release":"changeset publish","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d4cfc0c1-48ed-4821-bca2-af62b0941e2d"}},"overrides":{"esbuild":"0.28.1"},"repository":{"url":"git+https://github.com/ambersecurityinc/notifly.git","type":"git"},"_npmVersion":"11.16.0","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","vitest":"4.1.10","typescript":"7.0.2","@changesets/cli":"2.31.1","@vitest/coverage-v8":"4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/notifly_0.7.1_1785276011612_0.36211385848268174","host":"s3://npm-registry-packages-npm-production"}},"0.7.2":{"name":"@ambersecurityinc/notifly","version":"0.7.2","description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./builder":{"types":"./dist/builder/index.d.ts","import":"./dist/builder/index.js","require":"./dist/builder/index.cjs"}},"scripts":{"build":"tsup src/index.ts src/builder/index.ts --format esm,cjs --clean && tsc -p tsconfig.build.json","dev":"tsup src/index.ts src/builder/index.ts --format esm,cjs --watch","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","lint":"tsc --noEmit","release":"changeset publish"},"keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"author":"","license":"MIT","repository":{"type":"git","url":"git+https://github.com/ambersecurityinc/notifly.git"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"devDependencies":{"@changesets/cli":"3.0.2","@vitest/coverage-v8":"5.0.0","tsup":"8.5.1","typescript":"7.0.2","vitest":"5.0.0"},"overrides":{"esbuild":"0.28.2"},"gitHead":"d953d92ca250581780f71afebe8a7ae6b61c5d4f","_id":"@ambersecurityinc/notifly@0.7.2","bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"homepage":"https://github.com/ambersecurityinc/notifly#readme","_nodeVersion":"24.21.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-wAq84hzcstAENPEPsD7EL5b7eakZRLk5lzumVPUT8ucQJReEeOMtTvs//8rlmyekqF21R06r6EA53QdFCuPGvA==","shasum":"8b1256cd12c81eb6c78fac969e3837ead9464467","tarball":"https://registry.npmjs.org/@ambersecurityinc/notifly/-/notifly-0.7.2.tgz","fileCount":32,"unpackedSize":159125,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambersecurityinc%2fnotifly@0.7.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCcoL/StiF80o6onV18ZUVlMYXSUYinl2BDEQkfWCECEQIgGP77AEGIrq5SytHDctj2JAVxbF41hiEQpt6AhOADPUA="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d4cfc0c1-48ed-4821-bca2-af62b0941e2d"}},"directories":{},"maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/notifly_0.7.2_1788970860619_0.14553399805177403"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-26T16:38:15.092Z","modified":"2026-09-09T16:21:01.164Z","0.1.0":"2026-03-26T16:38:15.312Z","0.2.0":"2026-03-26T17:17:28.978Z","0.3.0":"2026-03-27T23:11:32.180Z","0.4.0":"2026-04-13T15:32:58.929Z","0.5.0":"2026-04-13T15:50:33.419Z","0.5.1":"2026-05-20T21:33:07.551Z","0.6.0":"2026-07-10T00:24:20.424Z","0.7.0":"2026-07-10T01:19:43.664Z","0.7.1":"2026-07-28T22:00:11.763Z","0.7.2":"2026-09-09T16:21:00.759Z"},"bugs":{"url":"https://github.com/ambersecurityinc/notifly/issues"},"license":"MIT","homepage":"https://github.com/ambersecurityinc/notifly#readme","keywords":["notifications","discord","slack","telegram","ntfy","gotify","apprise"],"repository":{"type":"git","url":"git+https://github.com/ambersecurityinc/notifly.git"},"description":"Send notifications to multiple services from a single API using Apprise-compatible URLs","maintainers":[{"name":"00o-sh","email":"elibrody2@gmail.com"}],"readme":"# notifly\n\nSend notifications to multiple services from a single API using Apprise-compatible URLs.\n\n[![npm version](https://img.shields.io/npm/v/@ambersecurityinc/notifly)](https://www.npmjs.com/package/@ambersecurityinc%2fnotifly)\n[![CI](https://github.com/ambersecurityinc/notifly/actions/workflows/ci.yml/badge.svg)](https://github.com/ambersecurityinc/notifly/actions)\n[![License: MIT](https://img.shields.io/npm/l/@ambersecurityinc/notifly)](LICENSE)\n[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@ambersecurityinc/notifly)](https://bundlephobia.com/package/@ambersecurityinc%2fnotifly)\n\n## Features\n\n- **Web API only** — built on `fetch`, no Node.js-specific dependencies\n- **Multi-runtime** — works on Cloudflare Workers, Bun, Deno, and Node 18+\n- **Apprise-compatible URLs** — one URL string encodes all connection details\n- **Concurrent dispatch** — sends to all services in parallel via `Promise.allSettled()`\n- **Plugin system** — register custom services with `registerService()`\n\n## Install\n\n```sh\nnpm install @ambersecurityinc/notifly\n```\n\n## Quick Start\n\n```ts\nimport { notify } from '@ambersecurityinc/notifly';\n\nconst results = await notify(\n  {\n    urls: [\n      'discord://1234567890/abcdefghijklmnop',\n      'ntfy://my-alerts',\n      'tgram://bot123456/987654321',\n    ],\n  },\n  {\n    title: 'Deployment complete',\n    body: 'v1.2.3 is live!',\n    type: 'success',\n  },\n);\n\nconsole.log(results);\n// [\n//   { success: true, service: 'discord' },\n//   { success: true, service: 'ntfy' },\n//   { success: true, service: 'telegram' },\n// ]\n```\n\n## Supported Services\n\n| Service            | URL Scheme(s)               | Example URL                                                                  |\n|--------------------|-----------------------------|------------------------------------------------------------------------------|\n| Discord            | `discord`                   | `discord://webhook_id/webhook_token`                                         |\n| Slack              | `slack`                     | `slack://token_a/token_b/token_c/%23channel`                                 |\n| Telegram           | `tgram`                     | `tgram://bot_token/chat_id`                                                  |\n| ntfy               | `ntfy`                      | `ntfy://topic` or `ntfy://host/topic`                                        |\n| Gotify             | `gotify`                    | `gotify://host/token`                                                        |\n| Email (via gateway)| `mailto`                    | `mailto://user:apikey@host/?to=addr@example.com&gateway=resend`              |\n| Microsoft Teams    | `msteams`, `teams`          | `msteams://group_id@tenant_id/channel_id/webhook_id`                         |\n| Teams (Workflows)  | `workflows`, `workflow`     | `workflows://host/powerautomate/.../triggers/manual/paths/invoke?...&sig=...` |\n| Pushover           | `pover`                     | `pover://user_key/api_token` or `pover://user_key/api_token/device`          |\n| Pushbullet         | `pbul`                      | `pbul://access_token` or `pbul://access_token/device_id`                     |\n| Custom Webhook     | `json`, `jsons`, `form`, `forms` | `jsons://example.com/hook` or `forms://example.com/hook?method=PUT`     |\n\n## URL Builder\n\nA headless, framework-agnostic URL builder module ships as a separate subpath export. It provides service schemas, field definitions, validation, and URL generation — the logic layer for building notification URL configuration UIs without coupling to any framework.\n\n### Import\n\n```ts\nimport {\n  getServiceSchemas,\n  getServiceSchema,\n  searchServices,\n  getServicesByCategory,\n  getCategories,\n  validateFields,\n  buildUrl,\n  decomposeUrl,\n} from '@ambersecurityinc/notifly/builder';\n```\n\n### 3-Step Form Flow\n\n```ts\nimport { searchServices, validateFields, buildUrl } from '@ambersecurityinc/notifly/builder';\n\n// Step 1 — Search and select a service\nconst results = searchServices('discord');\nconst schema = results[0]; // { service: 'discord', label: 'Discord', fields: [...], ... }\n\n// Step 2 — Render a form using schema.fields, collect user input\nconst userInput = {\n  webhook_id: '1234567890',\n  webhook_token: 'abcdefghijklmnop',\n};\n\n// Step 3 — Validate and generate the URL\nconst errors = validateFields('discord', userInput);\nif (errors.length === 0) {\n  const { url } = buildUrl('discord', userInput);\n  console.log(url); // discord://1234567890/abcdefghijklmnop\n}\n```\n\n### Smart URL Paste\n\nUsers can paste the raw webhook URL they copied from a service's settings page — no manual conversion needed:\n\n```ts\nimport { smartParse } from '@ambersecurityinc/notifly/builder';\n\n// User pastes their raw Discord webhook URL\nconst result = smartParse('https://discord.com/api/webhooks/1234567890/abcdefghijklmnop');\n// → { service: 'discord', notiflyUrl: 'discord://1234567890/abcdefghijklmnop',\n//     fields: { webhook_id: '1234567890', webhook_token: 'abcdefghijklmnop' } }\n\n// Also works with existing notifly URLs\nconst result2 = smartParse('discord://1234567890/abcdefghijklmnop');\n// → { service: 'discord', notiflyUrl: 'discord://1234567890/abcdefghijklmnop',\n//     fields: { webhook_id: '1234567890', webhook_token: 'abcdefghijklmnop' } }\n\n// Unknown URLs return null\nconst result3 = smartParse('https://example.com/unknown');\n// → null\n```\n\n`smartParse` tries `detectAndConvert` first (for raw provider URLs), then falls back to `decomposeUrl` (for existing Apprise URLs). You can also use each individually:\n\n```ts\nimport { detectAndConvert, isRawServiceUrl } from '@ambersecurityinc/notifly/builder';\n\n// Check if a pasted string is a raw provider URL before processing\nif (isRawServiceUrl(input)) {\n  const converted = detectAndConvert(input);\n  // converted?.notiflyUrl — the notifly URL to store\n}\n```\n\n**Detection patterns supported:**\n\n| Raw URL pattern | Detected as |\n|---|---|\n| `https://discord.com/api/webhooks/{id}/{token}` | `discord` |\n| `https://hooks.slack.com/services/{a}/{b}/{c}` | `slack` |\n| `https://*.webhook.office.com/webhookb2/.../IncomingWebhook/...` | `msteams` |\n| `https://*/.../triggers/manual/paths/invoke?...&sig=...` | `workflows` (Teams Power Automate) |\n| `https://api.telegram.org/bot{token}/...` | `telegram` (chat_id left empty) |\n| `https://ntfy.sh/{topic}` | `ntfy` |\n| `https://{host}/message?token={token}` | `gotify` |\n\n### Editing Existing URLs\n\n```ts\nimport { decomposeUrl, buildUrl } from '@ambersecurityinc/notifly/builder';\n\n// Load an existing URL into field values (for editing)\nconst { service, fields } = decomposeUrl('discord://1234567890/abcdefghijklmnop');\n// { service: 'discord', fields: { webhook_id: '1234567890', webhook_token: 'abcdefghijklmnop' } }\n\n// Modify a field and rebuild\nconst { url } = buildUrl(service, { ...fields, webhook_token: 'newtoken' });\n```\n\n### Browsing by Category\n\n```ts\nimport { getCategories, getServicesByCategory } from '@ambersecurityinc/notifly/builder';\n\nconst categories = getCategories();\n// [{ key: 'chat', label: 'Chat & Messaging', count: 4 }, ...]\n\nconst chatServices = getServicesByCategory('chat');\n// schemas for Discord, Slack, Telegram, Microsoft Teams\n```\n\n### Service Schema Shape\n\nEach schema describes all fields a user needs to fill in:\n\n```ts\ninterface ServiceSchema {\n  service: string;      // registry key, e.g. 'discord'\n  label: string;        // display name\n  description: string;  // one-liner\n  schemes: string[];    // URL schemes, e.g. ['discord']\n  category: 'chat' | 'push' | 'email' | 'webhook' | 'self-hosted';\n  iconHint: string;     // icon name hint for your UI\n  fields: ServiceField[];\n}\n\ninterface ServiceField {\n  key: string;\n  label: string;\n  type: 'text' | 'number' | 'select' | 'boolean';\n  required: boolean;\n  sensitive: boolean;   // true for tokens/passwords — UI should mask these\n  placeholder?: string;\n  helpText?: string;    // where to find the value (very useful for users)\n  defaultValue?: string | number | boolean;\n  options?: { label: string; value: string }[];  // for 'select' type\n  validation?: { pattern?: string; minLength?: number; maxLength?: number };\n}\n```\n\nThis module is entirely framework-agnostic — bring your own UI (React, Vue, Svelte, plain HTML, etc.).\n\n## Custom Services\n\n```ts\nimport { registerService } from '@ambersecurityinc/notifly';\nimport type { ServiceDefinition, ServiceConfig, NotiflyMessage } from '@ambersecurityinc/notifly';\n\nconst myService: ServiceDefinition = {\n  schemas: ['myscheme'],\n\n  parseUrl(url: URL): ServiceConfig {\n    return { service: 'myscheme', host: url.hostname, token: url.pathname.slice(1) };\n  },\n\n  async send(config: ServiceConfig, message: NotiflyMessage) {\n    // send the notification...\n    return { success: true, service: 'myscheme' };\n  },\n};\n\nregisterService(myService);\n\n// Now use it\nawait notify({ urls: ['myscheme://host/token'] }, { body: 'Hello!' });\n```\n\n## API Reference\n\n### `notify(options, message)`\n\nSends a notification to all URLs concurrently. Never throws — failures are captured in results.\n\n```ts\nfunction notify(options: NotiflyOptions, message: NotiflyMessage): Promise<NotiflyResult[]>\n```\n\n### `parseUrl(url)`\n\nParses an Apprise-compatible URL string into a `ServiceConfig` object. Throws `ParseError` for malformed or unknown URLs. Useful for validation before sending.\n\n```ts\nfunction parseUrl(url: string): ServiceConfig\n```\n\n### `registerService(service)`\n\nRegisters a custom service plugin. Overwrites any existing service registered for the same URL scheme(s).\n\n```ts\nfunction registerService(service: ServiceDefinition): void\n```\n\n### Types\n\n```ts\ninterface NotiflyMessage {\n  title?: string;\n  body: string;\n  type?: 'info' | 'success' | 'warning' | 'failure';\n}\n\ninterface NotiflyResult {\n  success: boolean;\n  service: string;\n  error?: string;\n}\n\ninterface NotiflyOptions {\n  urls: string[];\n}\n\ninterface ServiceConfig {\n  service: string;\n  [key: string]: unknown;\n}\n\ninterface ServiceDefinition {\n  schemas: string[];\n  parseUrl(url: URL): ServiceConfig;\n  send(config: ServiceConfig, message: NotiflyMessage): Promise<NotiflyResult>;\n}\n```\n\n## URL Format\n\n### Discord\n\n```\ndiscord://webhook_id/webhook_token\n```\n\n### Slack\n\n```\nslack://token_a/token_b/token_c/%23channel\n```\n\nThe channel segment is optional and should be URL-encoded (e.g. `%23general` for `#general`).\n\n### Telegram\n\n```\ntgram://bot_token/chat_id\n```\n\n### ntfy\n\n```\nntfy://topic                  # uses ntfy.sh\nntfy://your-host.com/topic    # self-hosted\n```\n\n### Gotify\n\n```\ngotify://your-host.com/app_token\n```\n\n### Email (via HTTP gateway)\n\nRaw SMTP requires TCP sockets not available in Web API environments. Use an HTTP gateway instead:\n\n```\n# MailChannels (free on Cloudflare Workers)\nmailto://user@host/?to=recipient@example.com&gateway=mailchannels\n\n# Resend (free tier — password is your API key)\nmailto://user:re_apikey@host/?to=recipient@example.com&gateway=resend\n```\n\nOptional query params: `from`, `cc`, `bcc`.\n\n### Microsoft Teams\n\nTokens come from the Teams webhook URL:\n`https://outlook.webhook.office.com/webhookb2/{group_id}@{tenant_id}/IncomingWebhook/{channel_id}/{webhook_id}`\n\n```\nmsteams://group_id@tenant_id/channel_id/webhook_id\n```\n\nAlso registered as `teams://` alias.\n\n### Microsoft Teams (Workflows / Power Automate)\n\nMicrosoft is [retiring the Office 365 connectors](https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/) used by `msteams://` in favour of the **Workflows** app (powered by Power Automate). In Teams, open a channel → **More options (⋯)** → **Workflows** → *\"Post to a channel when a webhook request is received\"*, then copy the generated URL. It looks like:\n\n```\nhttps://<env>.environment.api.powerplatform.com/powerautomate/automations/direct/workflows/<id>/triggers/manual/paths/invoke?api-version=1&sp=...&sv=1.0&sig=...\n```\n\n(Older flows issue `https://<host>.logic.azure.com:443/workflows/.../triggers/manual/paths/invoke?...` URLs — both are supported.)\n\nBecause the URL carries a cryptographic `sig` token that must be preserved exactly, notifly stores the whole URL by swapping the scheme from `https` to `workflows`:\n\n```\nworkflows://<env>.environment.api.powerplatform.com/powerautomate/.../triggers/manual/paths/invoke?...&sig=...\n```\n\nThe easiest way to produce this is `smartParse()` (or `detectAndConvert()`) — paste the raw HTTPS URL and it converts automatically. Also registered as `workflow://` alias.\n\n#### Payload format\n\nTeams Workflows templates disagree on what the request body must look like, depending on how the flow's **\"Post card in a chat or channel\"** action binds its input. notifly supports all three, selected via a `#format=` fragment on the URL (kept in the fragment so it never touches the signed query string and is never sent over the wire):\n\n| `#format=` | Body sent | Use when |\n|---|---|---|\n| *(default)* / `card` | a bare Adaptive Card `{ \"type\": \"AdaptiveCard\", … }` | the flow binds the whole trigger body into \"Post card\" (the flowbot deserializes the body as an Adaptive Card and requires top-level `type: \"AdaptiveCard\"`) |\n| `message` | `{ \"type\": \"message\", \"attachments\": [{ contentType, content: <card> }] }` | the flow reads `triggerBody()?['attachments']` |\n| `text` | `{ \"text\": \"**title**\\n\\nbody\" }` | the basic *\"Send webhook alerts to a channel\"* template |\n\n```\nworkflows://…/triggers/manual/paths/invoke?…&sig=…            # Adaptive Card (default)\nworkflows://…/triggers/manual/paths/invoke?…&sig=…#format=message\nworkflows://…/triggers/manual/paths/invoke?…&sig=…#format=text\n```\n\nThe message `title` becomes a bold heading; message `type` colours it (`success`→Good, `warning`→Warning, `failure`→Attention).\n\n> If you see `AdaptiveSerializationException: Property 'type' must be 'AdaptiveCard'`, your flow needs the default `card` format (which this ships). If you see an empty/failed card, try `#format=message`.\n\n### Pushover\n\n```\npover://user_key/api_token           # send to all devices\npover://user_key/api_token/device    # send to a specific device\n```\n\nMessage `type` maps to Pushover priority: `info`/`success`=0, `warning`=1, `failure`=2.\n\n### Pushbullet\n\n```\npbul://access_token                  # push to all devices\npbul://access_token/device_iden      # push to specific device\npbul://access_token/%23channel_tag   # push to a channel\n```\n\n### Custom Webhook\n\n```\njson://host/path    # HTTP POST with JSON body\njsons://host/path   # HTTPS POST with JSON body\nform://host/path    # HTTP POST with form-encoded body\nforms://host/path   # HTTPS POST with form-encoded body\n```\n\nDefault JSON body: `{ \"title\": \"...\", \"body\": \"...\", \"type\": \"...\" }`\n\nQuery parameter prefixes for customisation:\n- `?+HeaderName=value` — add a custom request header\n- `?-fieldname=value` — add/override a body field\n- `?method=PUT` — override the HTTP method (default: POST)\n\n## Error Handling\n\n`notify()` never throws. All errors are returned as failed results:\n\n```ts\nconst results = await notify({ urls: ['discord://bad/token'] }, { body: 'test' });\n// [{ success: false, service: 'discord', error: 'HTTP 401 from ...' }]\n```\n\n`parseUrl()` throws `ParseError` for invalid or unknown URLs:\n\n```ts\nimport { parseUrl, ParseError } from '@ambersecurityinc/notifly';\n\ntry {\n  parseUrl('not-a-url');\n} catch (err) {\n  if (err instanceof ParseError) {\n    console.error('Bad URL:', err.message);\n  }\n}\n```\n\nHTTP failures are exposed as `ServiceError` (with `.status` and `.body` properties) — these are caught internally and returned as failed `NotiflyResult` objects.\n\n## Runtime Compatibility\n\n| Runtime            | Supported |\n|--------------------|-----------|\n| Node.js 18+        | ✅        |\n| Bun                | ✅        |\n| Deno               | ✅        |\n| Cloudflare Workers | ✅        |\n| Browser            | ✅        |\n\nNo Node.js-specific APIs are used. Only `fetch` and the `URL` constructor are required.\n\n## Publishing\n\n### First Publish\n\nThis project uses a two-workflow setup for npm publishing.\n\n**First publish** is done via `first-publish.yml` using a granular npm access token:\n\n1. Create a granular npm token scoped to the `@ambersecurityinc/notifly` package (read-write access)\n2. Add it as `NPM_TOKEN` in your GitHub repo → Settings → Secrets → Actions\n3. Go to Actions tab → \"First Publish\" → \"Run workflow\"\n4. Verify the package appears at https://www.npmjs.com/package/@ambersecurityinc%2fnotifly\n\n### Ongoing Releases (OIDC Trusted Publishing)\n\nAfter the first publish, switch to keyless publishing via OIDC:\n\n1. Go to https://www.npmjs.com/package/@ambersecurityinc%2fnotifly/access\n2. Under \"Trusted Publisher\", select **GitHub Actions**\n3. Fill in: org `ambersecurityinc`, repository `notifly`, workflow filename `release.yml`\n4. Enable \"Require two-factor authentication and disallow tokens\" (recommended)\n5. In your GitHub repo: disable `first-publish.yml` and delete the `NPM_TOKEN` secret\n\nReleases are triggered by pushing a git tag (`v*`) or via the `release.yml` workflow dispatch.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nMIT\n","readmeFilename":"README.md"}