From 3524361740c94a0fd59fe53bdf4cbdf0b25020b9 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Fri, 23 Jan 2026 16:03:39 -0700 Subject: [PATCH 1/5] Make enhanced the default for us_street_api --- src/us_street/Client.js | 6 +-- src/util/apiToSDKKeyMap.js | 3 +- src/util/buildUsStreetInputData.js | 35 ++++++++++++++++ src/util/sendBatch.js | 5 ++- tests/us_street/test_Client.js | 64 ++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 src/util/buildUsStreetInputData.js diff --git a/src/us_street/Client.js b/src/us_street/Client.js index 3449278..e9ab0e5 100644 --- a/src/us_street/Client.js +++ b/src/us_street/Client.js @@ -3,7 +3,7 @@ const Lookup = require("./Lookup"); const Batch = require("../Batch"); const UndefinedLookupError = require("../Errors").UndefinedLookupError; const sendBatch = require("../util/sendBatch"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").usStreet; +const buildUsStreetInputData = require("../util/buildUsStreetInputData"); /** * This client sends lookups to the Smarty US Street API,
@@ -28,15 +28,13 @@ class Client { let batch; if (dataIsLookup) { - if (data.maxCandidates == null && data.match == "enhanced") - data.maxCandidates = 5; batch = new Batch(); batch.add(data); } else { batch = data; } - return sendBatch(batch, this.sender, Candidate, keyTranslationFormat); + return sendBatch(batch, this.sender, Candidate, null, buildUsStreetInputData); } } diff --git a/src/util/apiToSDKKeyMap.js b/src/util/apiToSDKKeyMap.js index ea947c5..6201311 100644 --- a/src/util/apiToSDKKeyMap.js +++ b/src/util/apiToSDKKeyMap.js @@ -12,7 +12,8 @@ module.exports = { "match": "match", "format": "format", "candidates": "maxCandidates", - "county_source": "countySource" + "county_source": "countySource", + "input_id": "inputId" }, usAutocompletePro: { search: "search", diff --git a/src/util/buildUsStreetInputData.js b/src/util/buildUsStreetInputData.js new file mode 100644 index 0000000..21ef695 --- /dev/null +++ b/src/util/buildUsStreetInputData.js @@ -0,0 +1,35 @@ +const buildInputData = require("./buildInputData"); +const keyTranslationFormat = require("./apiToSDKKeyMap").usStreet; + +module.exports = (lookup) => { + // Apply default match strategy and candidates logic per Go SDK behavior + let effectiveMatch = lookup.match; + let effectiveCandidates = lookup.maxCandidates; + + // Default match strategy is "enhanced" + if (!effectiveMatch) { + effectiveMatch = "enhanced"; + } + + // If match is "strict", don't send match parameter or default candidates + if (effectiveMatch === "strict") { + effectiveMatch = undefined; + // Only send candidates if explicitly set + if (!effectiveCandidates) { + effectiveCandidates = undefined; + } + } else { + // For non-strict (including default "enhanced"), set default candidates to 5 if not specified + if (!effectiveCandidates) { + effectiveCandidates = 5; + } + } + + // Create a lookup copy with effective values for serialization + const effectiveLookup = Object.assign({}, lookup, { + match: effectiveMatch, + maxCandidates: effectiveCandidates, + }); + + return buildInputData(effectiveLookup, keyTranslationFormat); +}; diff --git a/src/util/sendBatch.js b/src/util/sendBatch.js index eca89a1..a32ab63 100644 --- a/src/util/sendBatch.js +++ b/src/util/sendBatch.js @@ -2,7 +2,7 @@ const Request = require("../Request"); const Errors = require("../Errors"); const buildInputData = require("../util/buildInputData"); -module.exports = (batch, sender, Result, keyTranslationFormat) => { +module.exports = (batch, sender, Result, keyTranslationFormat, customBuildInputData) => { if (batch.isEmpty()) throw new Errors.BatchEmptyError; let request = new Request(); @@ -22,6 +22,9 @@ module.exports = (batch, sender, Result, keyTranslationFormat) => { function generateRequestPayload(batch) { return batch.lookups.map((lookup) => { + if (customBuildInputData) { + return customBuildInputData(lookup); + } return buildInputData(lookup, keyTranslationFormat); }); } diff --git a/tests/us_street/test_Client.js b/tests/us_street/test_Client.js index 4864845..e39e195 100644 --- a/tests/us_street/test_Client.js +++ b/tests/us_street/test_Client.js @@ -42,6 +42,23 @@ describe("A US Street client", function () { urbanization: "9", match: "10", candidates: "11", + input_id: "12", + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("defaults to enhanced match with 5 candidates when no match type specified.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.street = "123 Main St"; + let expectedParameters = { + street: "123 Main St", + match: "enhanced", + candidates: 5, }; client.send(lookup); @@ -64,6 +81,53 @@ describe("A US Street client", function () { expect(mockSender.request.parameters).to.deep.equal(expectedParameters); }); + it("sends no match or candidates when match type is strict.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.street = "123 Main St"; + lookup.match = "strict"; + let expectedParameters = { + street: "123 Main St", + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("sends candidates but not match when match is strict with explicit candidates.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.street = "123 Main St"; + lookup.match = "strict"; + lookup.maxCandidates = 3; + let expectedParameters = { + street: "123 Main St", + candidates: 3, + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("sends match invalid when explicitly set.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.match = "invalid"; + let expectedParameters = { + match: "invalid", + candidates: 5, + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + it("doesn't send an empty batch.", function () { let mockSender = new MockSender(); const client = new Client(mockSender); From 68dc0c42374bf47c9e94c7f1b7f214c4dae5e1be Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 26 Jan 2026 11:50:11 -0700 Subject: [PATCH 2/5] Only default candidates to 5 for enhanced match mode Previously, candidates defaulted to 5 for all non-strict match modes. Now it only defaults to 5 when the match mode is specifically "enhanced" and maxCandidates is 0 or undefined. Co-Authored-By: Claude Opus 4.5 --- src/util/buildUsStreetInputData.js | 16 +++--- tests/us_street/test_Client.js | 80 ++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/src/util/buildUsStreetInputData.js b/src/util/buildUsStreetInputData.js index 21ef695..a122803 100644 --- a/src/util/buildUsStreetInputData.js +++ b/src/util/buildUsStreetInputData.js @@ -11,18 +11,14 @@ module.exports = (lookup) => { effectiveMatch = "enhanced"; } - // If match is "strict", don't send match parameter or default candidates + // If match is "strict", don't send match parameter if (effectiveMatch === "strict") { effectiveMatch = undefined; - // Only send candidates if explicitly set - if (!effectiveCandidates) { - effectiveCandidates = undefined; - } - } else { - // For non-strict (including default "enhanced"), set default candidates to 5 if not specified - if (!effectiveCandidates) { - effectiveCandidates = 5; - } + } + + // For "enhanced" match mode, set default candidates to 5 if not specified + if (effectiveMatch === "enhanced" && !effectiveCandidates) { + effectiveCandidates = 5; } // Create a lookup copy with effective values for serialization diff --git a/tests/us_street/test_Client.js b/tests/us_street/test_Client.js index e39e195..703000c 100644 --- a/tests/us_street/test_Client.js +++ b/tests/us_street/test_Client.js @@ -120,6 +120,37 @@ describe("A US Street client", function () { lookup.match = "invalid"; let expectedParameters = { match: "invalid", + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("sends match invalid with explicit candidates.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.match = "invalid"; + lookup.maxCandidates = 3; + let expectedParameters = { + match: "invalid", + candidates: 3, + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("defaults maxCandidates to 5 when enhanced and maxCandidates is 0.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.match = "enhanced"; + lookup.maxCandidates = 0; + let expectedParameters = { + match: "enhanced", candidates: 5, }; @@ -128,6 +159,55 @@ describe("A US Street client", function () { expect(mockSender.request.parameters).to.deep.equal(expectedParameters); }); + it("uses explicit maxCandidates when enhanced and maxCandidates is set.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.match = "enhanced"; + lookup.maxCandidates = 10; + let expectedParameters = { + match: "enhanced", + candidates: 10, + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("does not default candidates for non-enhanced match modes.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.street = "123 Main St"; + lookup.match = "invalid"; + // maxCandidates left undefined - should NOT default to 5 for non-enhanced + let expectedParameters = { + street: "123 Main St", + match: "invalid", + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("passes through explicit zero candidates for non-enhanced match modes.", function () { + let mockSender = new MockSender(); + const client = new Client(mockSender); + let lookup = new Lookup(); + lookup.match = "invalid"; + lookup.maxCandidates = 0; + let expectedParameters = { + match: "invalid", + candidates: 0, + }; + + client.send(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + it("doesn't send an empty batch.", function () { let mockSender = new MockSender(); const client = new Client(mockSender); From 384452c59336c3da04231c4aa9dfb91b1ae4bd1f Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 26 Jan 2026 11:57:25 -0700 Subject: [PATCH 3/5] Add GitHub Actions publish workflow and update Makefile - Add publish.yml workflow to automatically publish to npm on tag push - Update Makefile to match Go SDK structure (fmt, clean, cover, integrate targets) - Update node-tests.yml to use actions/checkout@v4 and actions/setup-node@v4 Co-Authored-By: Claude Opus 4.5 --- .github/workflows/node-tests.yml | 4 +-- .github/workflows/publish.yml | 39 ++++++++++++++++++++++++++++ Makefile | 44 ++++++++++++++++++++++---------- 3 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/node-tests.yml b/.github/workflows/node-tests.yml index 53476e5..d3ba409 100644 --- a/.github/workflows/node-tests.yml +++ b/.github/workflows/node-tests.yml @@ -16,9 +16,9 @@ jobs: node-version: [20.x, 22.x, 24.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm ci diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a7a141b --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,39 @@ +name: Publish to npm + +on: + push: + tags: + - '*' + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Build + run: npm run build + + - name: Set version from tag + run: | + VERSION=${GITHUB_REF#refs/tags/} + sed -i 's/"version": "0\.0\.0"/"version": "'"$VERSION"'"/g' package.json + sed -i 's/"version": "0\.0\.0"/"version": "'"$VERSION"'"/g' package-lock.json + + - name: Publish to npm + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/Makefile b/Makefile index 6904171..f772222 100644 --- a/Makefile +++ b/Makefile @@ -1,31 +1,49 @@ #!/usr/bin/make -f -VERSION := $(shell tagit -p --dry-run) -VERSION_FILE1 := package.json -VERSION_FILE2 := package-lock.json +VERSION := $(shell tagit -p --dry-run) +VERSION_FILE1 := package.json +VERSION_FILE2 := package-lock.json -test: node_modules +test: node_modules fmt npm run test node_modules: npm install -build: +fmt: + npx prettier --write . + +clean: + @git checkout "$(VERSION_FILE1)" "$(VERSION_FILE2)" + +build: node_modules npm run build -publish: test version build upload unversion - tagit -p - git push origin --tags +compile: build -upload: - npm publish +cover: node_modules + npm run test -- --reporter=spec + +integrate: build + @echo "Running integration examples..." + @node examples/us_street.mjs > /dev/null || true + @node examples/us_zipcode.mjs > /dev/null || true + @node examples/us_autocomplete_pro.mjs > /dev/null || true + @node examples/us_extract.mjs > /dev/null || true + @node examples/us_reverse_geo.mjs > /dev/null || true + @node examples/us_enrichment.mjs > /dev/null || true + @node examples/international_street.mjs > /dev/null || true + @node examples/international_address_autocomplete.mjs > /dev/null || true + @node examples/international_postal_code.mjs > /dev/null || true version: sed -i.bak -e 's/^ "version": "0\.0\.0",/ "version": "$(VERSION)",/g' "$(VERSION_FILE1)" && rm -f "$(VERSION_FILE1).bak" sed -i.bak -e 's/^ "version": "0\.0\.0",/ "version": "$(VERSION)",/g' "$(VERSION_FILE2)" && rm -f "$(VERSION_FILE2).bak" -unversion: +publish: test build version + npm publish git checkout "$(VERSION_FILE1)" "$(VERSION_FILE2)" + tagit -p + git push origin --tags -# node_modules is a real directory target -.PHONY: test publish upload version unversion +.PHONY: test fmt clean build compile cover integrate version publish From 152a5671b106ae90433111d77818004751097a76 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 26 Jan 2026 14:51:32 -0700 Subject: [PATCH 4/5] Update GitHub Actions to v6 Co-Authored-By: Claude Opus 4.5 --- .github/workflows/node-tests.yml | 4 ++-- .github/workflows/publish.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/node-tests.yml b/.github/workflows/node-tests.yml index d3ba409..fdafee4 100644 --- a/.github/workflows/node-tests.yml +++ b/.github/workflows/node-tests.yml @@ -16,9 +16,9 @@ jobs: node-version: [20.x, 22.x, 24.x] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - run: npm ci diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a7a141b..ce16469 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '20.x' registry-url: 'https://registry.npmjs.org' From fa51795ddcf2f3b83e6ccda4024018ca626b435f Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 26 Jan 2026 15:02:22 -0700 Subject: [PATCH 5/5] Version is taken care of in the github action. --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index f772222..496ea68 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ #!/usr/bin/make -f -VERSION := $(shell tagit -p --dry-run) VERSION_FILE1 := package.json VERSION_FILE2 := package-lock.json @@ -42,8 +41,5 @@ version: publish: test build version npm publish - git checkout "$(VERSION_FILE1)" "$(VERSION_FILE2)" - tagit -p - git push origin --tags .PHONY: test fmt clean build compile cover integrate version publish