@domandigital/gbp 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.
Files changed (3) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +44 -11
  3. package/package.json +6 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,104 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@domandigital/gbp`.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
6
+ this project uses [semantic versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ Releases before 0.3.1 were consumed as git dependencies pinned to a tag. This
9
+ file was written retroactively from that tag history, so entries below 0.3.1
10
+ describe what the diffs actually changed rather than what was recorded at the
11
+ time.
12
+
13
+ ## [Unreleased]
14
+
15
+ ## [0.3.1] - 2026-08-16
16
+
17
+ ### Added
18
+
19
+ - `./package.json` is now exposed in the `exports` map. Tooling that reads a
20
+ dependency's manifest previously hit `ERR_PACKAGE_PATH_NOT_EXPORTED`.
21
+ - `@types/node` is declared as a devDependency, and `tsconfig.json` sets
22
+ `"types": ["node"]`. This package uses `process.env`, `fetch`,
23
+ `URLSearchParams`, `RequestInit` and `Response`, all of which need those
24
+ types, and none of which had a declared source. `pnpm typecheck` passed only
25
+ because TypeScript walks up past the repo root and can find an `@types/node`
26
+ installed elsewhere on the machine. No consumer was affected, since published
27
+ `.d.ts` files carry their own references, but the check was not real.
28
+ - CI on every push and pull request: typecheck, test and build across Node 20,
29
+ 22 and 24. Previously the only workflow was the tag-triggered release.
30
+ - README section covering `scripts/oauth-listener.mjs`, the one-time local flow
31
+ that mints a client's `GBP_REFRESH_TOKEN` and writes it straight to Doppler.
32
+ It shipped in 0.3.0 with no documentation at all.
33
+
34
+ ### Changed
35
+
36
+ - `engines.node` raised from `>=18` to `>=20`. Node 18 reached end of life in
37
+ April 2025, and the previous range was never exercised by anything.
38
+ - README rewritten for npm distribution. The install section still described the
39
+ package as unpublished and pointed at the `#v0.1.0` git tag.
40
+
41
+ ## [0.3.0] - 2026-08-16
42
+
43
+ ### Added
44
+
45
+ - `scripts/oauth-listener.mjs`: a one-time local OAuth flow that prints a
46
+ consent URL, catches Google's redirect on a local listener, exchanges the
47
+ code, looks up the account and location IDs, and writes all three values to
48
+ Doppler. The token never passes through stdout, so it can't land in a
49
+ captured log.
50
+
51
+ This script is not part of the published package. It isn't in `files`, so it's
52
+ absent from the npm tarball: it shells out to the `doppler` binary, which has
53
+ no place in a public library's runtime contract. Clone the repo to use it.
54
+
55
+ ### Fixed
56
+
57
+ - The pagination test asserted a fixed order against a result the library
58
+ deliberately shuffles. With two reviews a shuffle returns the input order
59
+ about half the time, so the test failed roughly 50% of runs and survived two
60
+ releases because nothing ran the suite automatically. It now compares the set
61
+ of ids.
62
+
63
+ ### Changed
64
+
65
+ - Licensed Apache-2.0, with publish metadata and `publishConfig` for public
66
+ access and provenance. First version published to the npm registry.
67
+
68
+ ## [0.2.0] - 2026-07-31
69
+
70
+ ### Changed
71
+
72
+ - **`getBusinessReviews` now returns reviews in random order.** Results are
73
+ shuffled before being returned, replacing the API's own
74
+ `orderBy=updateTime desc` ordering. There is no way to opt out.
75
+
76
+ Two consequences worth knowing before you upgrade from 0.1.0: output is not
77
+ stable across builds, so a statically generated testimonial section reorders
78
+ on every rebuild; and because the shuffle runs after `limit` is applied, you
79
+ get the most recent N reviews in random order rather than a random N.
80
+
81
+ (The 0.2.0 tag message also credits min-star filtering. That's inaccurate:
82
+ `filterMinStars` shipped in 0.1.0.)
83
+
84
+ ## [0.1.0] - 2026-07-30
85
+
86
+ ### Added
87
+
88
+ - Initial release, extracted from MMM Beauty's `packages/google-apis`. Zero
89
+ runtime dependencies.
90
+ - `getGoogleOAuthAccessToken` and `hasGoogleOAuthCredentials`: user
91
+ refresh-token OAuth, with the access token cached in process and refreshed a
92
+ minute before expiry. Service accounts are rejected by the Business Profile
93
+ API entirely, so this is the only auth route.
94
+ - `getBusinessReviews` and `isBusinessProfileConfigured`: a paginated reviews
95
+ fetch (the API caps each page at 50) that decodes Google's star-rating enums,
96
+ includes the business's reply to each review, and supports `limit`,
97
+ `filterMinStars` and a Next.js `next` cache hint. Returns empty results rather
98
+ than throwing when unconfigured, so UI can render unconditionally.
99
+
100
+ [Unreleased]: https://github.com/Doman-Digital/dd-gbp/compare/v0.3.1...HEAD
101
+ [0.3.1]: https://github.com/Doman-Digital/dd-gbp/compare/v0.3.0...v0.3.1
102
+ [0.3.0]: https://github.com/Doman-Digital/dd-gbp/compare/v0.2.0...v0.3.0
103
+ [0.2.0]: https://github.com/Doman-Digital/dd-gbp/compare/v0.1.0...v0.2.0
104
+ [0.1.0]: https://github.com/Doman-Digital/dd-gbp/releases/tag/v0.1.0
package/README.md CHANGED
@@ -53,19 +53,16 @@ with the reply attached, for free.
53
53
 
54
54
  ## Install
55
55
 
56
- Not published to npm. Consumed as a git dependency pinned to a tag:
57
-
58
- ```json
59
- {
60
- "dependencies": {
61
- "@domandigital/gbp": "github:Doman-Digital/dd-gbp#v0.1.0"
62
- }
63
- }
56
+ ```bash
57
+ pnpm add @domandigital/gbp
64
58
  ```
65
59
 
66
- `dist/` is committed to this repo (no CI build step runs on a git-dependency
67
- install), so no build step is required in the consuming project beyond a
68
- normal `pnpm install`.
60
+ Public on npm, Apache-2.0, published with provenance from a tagged release.
61
+ Zero runtime dependencies. ESM and CJS builds ship together, each with its own
62
+ types. Requires Node 20 or newer.
63
+
64
+ Upgrading a repo that still pins `github:Doman-Digital/dd-gbp#vX.Y.Z`? Swap it
65
+ for a semver range.
69
66
 
70
67
  ## Env
71
68
 
@@ -81,6 +78,42 @@ Which actual Google Cloud OAuth client + refresh token you point at (the
81
78
  agency's shared credential, or a business's own dedicated one) is entirely a
82
79
  deployment-env decision, not a code-level one -- each app configures its own.
83
80
 
81
+ ## Minting a client's refresh token
82
+
83
+ `GBP_REFRESH_TOKEN` can only be obtained by a human completing Google's consent
84
+ flow as the business owner. `scripts/oauth-listener.mjs` in this repo automates
85
+ everything around that: it prints a consent URL, catches Google's redirect on a
86
+ local listener, exchanges the code, looks up the account and location IDs, and
87
+ writes all three values straight to Doppler.
88
+
89
+ The token and both IDs travel via argv into `doppler secrets set` and are never
90
+ printed to stdout or returned from the process, so a captured terminal log can't
91
+ leak them.
92
+
93
+ This script is repo-only. It isn't in the package's `files`, so it's absent from
94
+ the npm tarball, deliberately: it shells out to the `doppler` binary, which has
95
+ no business being a runtime expectation of a public library. Clone the repo to
96
+ use it.
97
+
98
+ Run it from inside the **client's** repo, so `doppler secrets set` targets that
99
+ client's own project and config via their local `.doppler.yaml` scoping:
100
+
101
+ ```bash
102
+ GBP_CLIENT_ID=$(doppler secrets get GBP_CLIENT_ID --plain) GBP_CLIENT_SECRET=$(doppler secrets get GBP_CLIENT_SECRET --plain) node ../dd-gbp/scripts/oauth-listener.mjs
103
+ ```
104
+
105
+ Two things that will bite you once each:
106
+
107
+ - `http://127.0.0.1:3333/oauth2callback` has to be registered as an authorised
108
+ redirect URI on the OAuth client in the GCP console. If it isn't, Google
109
+ returns `redirect_uri_mismatch`.
110
+ - If the account has already granted this app access, Google can decline to
111
+ issue a new refresh token even with `prompt=consent`. Revoke it at
112
+ https://myaccount.google.com/permissions and run the script again.
113
+
114
+ If the account has more than one location, the script uses the first and prints
115
+ every location it saw, so you can check it picked the right one.
116
+
84
117
  ## API
85
118
 
86
119
  ### `getBusinessReviews(options?): Promise<BusinessReviewsResult>`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domandigital/gbp",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "description": "Zero-dependency Google Business Profile client: OAuth refresh-token auth and a reviews (with owner replies) fetch, shared across Doman Digital / IDS client sites.",
6
6
  "license": "Apache-2.0",
@@ -16,9 +16,11 @@
16
16
  "types": "./dist/index.d.cts",
17
17
  "default": "./dist/index.cjs"
18
18
  }
19
- }
19
+ },
20
+ "./package.json": "./package.json"
20
21
  },
21
22
  "files": [
23
+ "CHANGELOG.md",
22
24
  "LICENSE",
23
25
  "README.md",
24
26
  "dist"
@@ -30,12 +32,13 @@
30
32
  "prepublishOnly": "pnpm run build"
31
33
  },
32
34
  "devDependencies": {
35
+ "@types/node": "^20",
33
36
  "tsup": "^8.3.5",
34
37
  "typescript": "^5.6.3",
35
38
  "vitest": "^2.1.9"
36
39
  },
37
40
  "engines": {
38
- "node": ">=18"
41
+ "node": ">=20"
39
42
  },
40
43
  "packageManager": "pnpm@9.15.9",
41
44
  "repository": {