@yawlabs/lemonsqueezy-webhook-sink 0.1.2 → 0.1.3

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/dist/env.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Pure environment-variable validators.
3
+ *
4
+ * Extracted from index.ts so they can be unit-tested without triggering
5
+ * index.ts's import-time side effects (reading env, opening the DB, starting
6
+ * the HTTP server, and registering signal handlers).
7
+ */
8
+ /**
9
+ * Read a required env var by name, rejecting absent / empty / whitespace-only
10
+ * values. Returns the raw (un-trimmed) value when present and non-blank.
11
+ */
12
+ export function requireEnv(name, env = process.env) {
13
+ const v = env[name];
14
+ if (!v || v.trim() === "")
15
+ throw new Error(`${name} environment variable is required`);
16
+ return v;
17
+ }
18
+ /**
19
+ * Parse a PORT string into an integer in [1, 65535], rejecting anything that
20
+ * is not an integer in range.
21
+ */
22
+ export function parsePort(raw) {
23
+ const n = Number(raw);
24
+ if (!Number.isInteger(n) || n < 1 || n > 65535) {
25
+ throw new Error(`PORT must be an integer in [1, 65535], got: ${JSON.stringify(raw)}`);
26
+ }
27
+ return n;
28
+ }
29
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAyB,OAAO,CAAC,GAAG;IAC3E,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IACpB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mCAAmC,CAAC,CAAC;IACvF,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,68 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { parsePort, requireEnv } from "./env.js";
4
+ describe("parsePort", () => {
5
+ it("accepts the index.ts default '8787'", () => {
6
+ assert.equal(parsePort("8787"), 8787);
7
+ });
8
+ it("accepts the in-range boundaries 1 and 65535", () => {
9
+ assert.equal(parsePort("1"), 1);
10
+ assert.equal(parsePort("65535"), 65535);
11
+ });
12
+ it("accepts numeric strings with surrounding whitespace (Number coercion)", () => {
13
+ // Number(" 3000 ") === 3000, and 3000 is an in-range integer.
14
+ assert.equal(parsePort(" 3000 "), 3000);
15
+ });
16
+ it("rejects 0 (below range)", () => {
17
+ assert.throws(() => parsePort("0"), /PORT must be an integer in \[1, 65535\]/);
18
+ });
19
+ it("rejects 65536 (above range)", () => {
20
+ assert.throws(() => parsePort("65536"), /PORT must be an integer in \[1, 65535\]/);
21
+ });
22
+ it("rejects a negative port", () => {
23
+ assert.throws(() => parsePort("-1"), /PORT must be an integer in \[1, 65535\]/);
24
+ });
25
+ it("rejects a non-integer (fractional) value", () => {
26
+ assert.throws(() => parsePort("3000.5"), /PORT must be an integer in \[1, 65535\]/);
27
+ });
28
+ it("rejects a non-numeric string", () => {
29
+ assert.throws(() => parsePort("abc"), /PORT must be an integer in \[1, 65535\]/);
30
+ });
31
+ it("rejects an empty string (Number('') === 0, out of range)", () => {
32
+ assert.throws(() => parsePort(""), /PORT must be an integer in \[1, 65535\]/);
33
+ });
34
+ it("rejects whitespace-only (Number(' ') === 0, out of range)", () => {
35
+ assert.throws(() => parsePort(" "), /PORT must be an integer in \[1, 65535\]/);
36
+ });
37
+ it("rejects 'NaN'-producing input like 'Infinity'", () => {
38
+ assert.throws(() => parsePort("Infinity"), /PORT must be an integer in \[1, 65535\]/);
39
+ });
40
+ it("includes the offending raw value (JSON-quoted) in the error", () => {
41
+ assert.throws(() => parsePort("nope"), /got: "nope"/);
42
+ });
43
+ });
44
+ describe("requireEnv", () => {
45
+ it("returns the value when present and non-blank", () => {
46
+ assert.equal(requireEnv("MY_SECRET", { MY_SECRET: "whsec_live" }), "whsec_live");
47
+ });
48
+ it("returns the raw (un-trimmed) value when it has non-blank content", () => {
49
+ // The validator only rejects fully-blank values; it does not trim the result.
50
+ assert.equal(requireEnv("MY_SECRET", { MY_SECRET: " padded " }), " padded ");
51
+ });
52
+ it("throws when the var is absent", () => {
53
+ assert.throws(() => requireEnv("MY_SECRET", {}), /MY_SECRET environment variable is required/);
54
+ });
55
+ it("throws when the var is an empty string", () => {
56
+ assert.throws(() => requireEnv("MY_SECRET", { MY_SECRET: "" }), /MY_SECRET environment variable is required/);
57
+ });
58
+ it("throws when the var is whitespace-only", () => {
59
+ assert.throws(() => requireEnv("MY_SECRET", { MY_SECRET: " " }), /MY_SECRET environment variable is required/);
60
+ });
61
+ it("throws when the var is a tab/newline-only string", () => {
62
+ assert.throws(() => requireEnv("MY_SECRET", { MY_SECRET: "\t\n" }), /MY_SECRET environment variable is required/);
63
+ });
64
+ it("interpolates the requested name into the error message", () => {
65
+ assert.throws(() => requireEnv("LEMONSQUEEZY_SIGNING_SECRET", {}), /LEMONSQUEEZY_SIGNING_SECRET environment variable is required/);
66
+ });
67
+ });
68
+ //# sourceMappingURL=env.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.test.js","sourceRoot":"","sources":["../src/env.test.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,20 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { serve } from "@hono/node-server";
3
3
  import { createApp } from "./app.js";
4
+ import { parsePort, requireEnv } from "./env.js";
4
5
  import { EventStore } from "./store.js";
5
- function requireEnv(name) {
6
- const v = process.env[name];
7
- if (!v || v.trim() === "")
8
- throw new Error(`${name} environment variable is required`);
9
- return v;
10
- }
11
- function parsePort(raw) {
12
- const n = Number(raw);
13
- if (!Number.isInteger(n) || n < 1 || n > 65535) {
14
- throw new Error(`PORT must be an integer in [1, 65535], got: ${JSON.stringify(raw)}`);
15
- }
16
- return n;
17
- }
18
6
  const SHUTDOWN_TIMEOUT_MS = 10_000;
19
7
  const SIGNING_SECRET = requireEnv("LEMONSQUEEZY_SIGNING_SECRET");
20
8
  const DB_PATH = process.env.WEBHOOK_SINK_DB ?? "./events.db";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mCAAmC,CAAC,CAAC;IACvF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC,MAAM,cAAc,GAAG,UAAU,CAAC,6BAA6B,CAAC,CAAC;AACjE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,aAAa,CAAC;AAC7D,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC;AACnD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;AAEzD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;AACtC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;AAEzF,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;IAC9D,OAAO,CAAC,GAAG,CAAC,2CAA2C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC;AAEH,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,MAAM,QAAQ,GAAG,GAAG,EAAE;IACpB,IAAI,YAAY;QAAE,OAAO;IACzB,YAAY,GAAG,IAAI,CAAC;IACpB,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,OAAO,CAAC,KAAK,CAAC,4BAA4B,mBAAmB,kBAAkB,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,EAAE,mBAAmB,CAAC,CAAC;IACxB,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;QAChB,YAAY,CAAC,SAAS,CAAC,CAAC;QACxB,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC,MAAM,cAAc,GAAG,UAAU,CAAC,6BAA6B,CAAC,CAAC;AACjE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,aAAa,CAAC;AAC7D,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC;AACnD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;AAEzD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;AACtC,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;AAEzF,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;IAC9D,OAAO,CAAC,GAAG,CAAC,2CAA2C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC;AAEH,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,MAAM,QAAQ,GAAG,GAAG,EAAE;IACpB,IAAI,YAAY;QAAE,OAAO;IACzB,YAAY,GAAG,IAAI,CAAC;IACpB,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,OAAO,CAAC,KAAK,CAAC,4BAA4B,mBAAmB,kBAAkB,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,EAAE,mBAAmB,CAAC,CAAC;IACxB,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;QAChB,YAAY,CAAC,SAAS,CAAC,CAAC;QACxB,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/lemonsqueezy-webhook-sink",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Durable webhook receiver for LemonSqueezy — verifies signatures, deduplicates events, and persists them for replay and reconciliation",
5
5
  "license": "MIT",
6
6
  "author": "YawLabs <contact@yaw.sh>",