Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .bumpy/_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@
"theoephraim"
]
}
]
],
"publish": {
"provenance": true,
"npmStaged": true
}
}
7 changes: 7 additions & 0 deletions .bumpy/update-deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
google-spreadsheet: minor
---

upgrade ky from v1 to v2

If you use `doc.sheetsApi` or `doc.driveApi` directly, note that ky v2 changed its hook signatures (hooks now receive state objects instead of direct Request/Error params) and renamed `prefixUrl` to `prefix`. See the [ky v2 migration guide](https://github.com/sindresorhus/ky/releases/tag/v2.0.0) for details.
6 changes: 6 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"attribution": {
"commit": "",
"pr": ""
}
}
2 changes: 1 addition & 1 deletion .env.schema
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ CI=

# Delay in ms to use when running tests
# @type=number
TEST_DELAY=200
TEST_DELAY=if($CI, 300, 200)
31 changes: 31 additions & 0 deletions .github/workflows/bumpy-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Uses `pull_request_target` so fork PR comments work — runs with write
# perms and secrets, so it MUST NOT execute PR code (no `bun install`, no
# PR-defined scripts). Bumpy only reads files; its version is resolved from
# the base branch's package.json.
name: Bumpy Check
on: pull_request_target

permissions:
pull-requests: write
contents: read

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: oven-sh/setup-bun@v2

- name: Resolve bumpy version from base
run: |
git fetch origin main --depth=1
VERSION=$(git show "origin/main:package.json" \
| jq -r '.devDependencies["@varlock/bumpy"] // .dependencies["@varlock/bumpy"]' \
| sed 's/[\^~]//')
echo "BUMPY_VERSION=$VERSION" >> "$GITHUB_ENV"

- run: bunx "@varlock/bumpy@$BUMPY_VERSION" ci check
env:
GH_TOKEN: ${{ github.token }}
4 changes: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ jobs:
- name: Lint
run: bun run lint --format junit -o reports/junit/js-lint-results.xml

- run: bunx @varlock/bumpy ci check
env:
GH_TOKEN: ${{ github.token }}

- name: Test
run: bun run test
env:
Expand Down
87 changes: 61 additions & 26 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,76 @@ on:
push:
branches: [main]

concurrency: ${{ github.workflow }}-${{ github.ref }}
concurrency:
group: bumpy-release
cancel-in-progress: false

jobs:
release:
plan:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
mode: ${{ steps.plan.outputs.mode }}
packages: ${{ steps.plan.outputs.packages }}
bumpy_version: ${{ steps.bumpy-version.outputs.version }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- id: bumpy-version
name: Resolve bumpy version
run: |
VERSION=$(jq -r '.devDependencies["@varlock/bumpy"] // .dependencies["@varlock/bumpy"]' package.json | sed 's/[\^~]//')
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "BUMPY_VERSION=$VERSION" >> "$GITHUB_ENV"
- id: plan
run: bunx "@varlock/bumpy@$BUMPY_VERSION" ci plan
env:
GH_TOKEN: ${{ github.token }}

version-pr:
needs: plan
if: needs.plan.outputs.mode == 'version-pr'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
id-token: write # required for trusted publishing

env:
BUMPY_VERSION: ${{ needs.plan.outputs.bumpy_version }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Use Node.js 24
uses: actions/setup-node@v6
- uses: actions/checkout@v6
with:
node-version: 24
registry-url: "https://registry.npmjs.org"

# Ensure npm 11.5.1 or later is installed (for trusted publishing)
- name: Update npm
run: npm install -g npm@latest

- name: Setup Bun
uses: oven-sh/setup-bun@v2

- name: Install dependencies
run: bun install

- name: Build
run: bun run build
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- run: bunx "@varlock/bumpy@$BUMPY_VERSION" ci release --expect-mode version-pr
env:
GH_TOKEN: ${{ github.token }}
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}

- name: Create Release PR or Publish
run: bunx @varlock/bumpy ci release
publish:
needs: plan
if: needs.plan.outputs.mode == 'publish'
runs-on: ubuntu-latest
environment: publish
permissions:
contents: write
id-token: write
env:
BUMPY_VERSION: ${{ needs.plan.outputs.bumpy_version }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v6
with:
node-version: latest
- run: npm install -g npm@latest # needed for oidc/staged
- run: bun install
- run: bun run build
- run: bunx "@varlock/bumpy@$BUMPY_VERSION" ci release --expect-mode publish
env:
GH_TOKEN: ${{ github.token }}
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}
16 changes: 8 additions & 8 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@
"test:ci": "vitest run"
},
"dependencies": {
"es-toolkit": "^1.44.0",
"ky": "^1.14.3"
"es-toolkit": "^1.47.0",
"ky": "^2.0.2"
},
"devDependencies": {
"@types/node": "^25.2.3",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"@varlock/bumpy": "^1.5.1",
"@varlock/bumpy": "^1.13.0",
"docsify-cli": "^4.4.4",
"eslint": "^8.41.0",
"eslint-config-airbnb-base": "^15.0.0",
Expand All @@ -69,7 +69,7 @@
"nock": "^14.0.11",
"tsdown": "^0.20.3",
"typescript": "^5.9.3",
"varlock": "^1.0.0",
"varlock": "^1.4.0",
"vitest": "^4.0.18"
},
"peerDependencies": {
Expand Down
39 changes: 19 additions & 20 deletions src/lib/GoogleSpreadsheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,23 @@ export class GoogleSpreadsheet {

// create a ky instance with sheet root URL and hooks to handle auth
this.sheetsApi = ky.create({
prefixUrl: `${SHEETS_API_BASE_URL}/${spreadsheetId}`,
prefix: `${SHEETS_API_BASE_URL}/${spreadsheetId}`,
timeout: 180_000,
hooks: {
beforeRequest: [(r) => this._setAuthRequestHook(r)],
beforeError: [(e) => this._errorHook(e)],
beforeRequest: [
({ request }) => this._setAuthRequestHook(request),
],
beforeError: [
({ error }) => this._errorHook(error),
],
},
retry: retryConfig,
});
this.driveApi = ky.create({
prefixUrl: `${DRIVE_API_BASE_URL}/${spreadsheetId}`,
prefix: `${DRIVE_API_BASE_URL}/${spreadsheetId}`,
hooks: {
beforeRequest: [(r) => this._setAuthRequestHook(r)],
beforeError: [(e) => this._errorHook(e)],
beforeRequest: [({ request }) => this._setAuthRequestHook(request)],
beforeError: [({ error }) => this._errorHook(error)],
},
retry: retryConfig,
});
Expand Down Expand Up @@ -185,26 +189,21 @@ export class GoogleSpreadsheet {
}

/** @internal */
async _errorHook(error: HTTPError) {
const { response } = error;
const errorDataText = await response?.text();
let errorData;
try {
errorData = JSON.parse(errorDataText);
} catch (e) {
// console.log('parsing json failed', errorDataText);
}
async _errorHook(error: Error) {
if (!(error instanceof HTTPError)) return error;

if (errorData) {
// usually the error has a code and message, but occasionally not
if (!errorData.error) return error;
// ky pre-parses the response body into error.data (the response body is already consumed)
const errorData = typeof error.data === 'string' ? (() => {
try { return JSON.parse(error.data as string); } catch { return undefined; }
})() : error.data;

if (errorData?.error) {
const { code, message } = errorData.error;
error.message = `Google API error - [${code}] ${message}`;
return error;
}

if (_.get(error, 'response.status') === 403) {
if (error.response?.status === 403) {
if ('apiKey' in this.auth) {
throw new Error('Sheet is private. Use authentication or make public. (see https://github.com/theoephraim/node-google-spreadsheet#a-note-on-authentication for details)');
}
Expand Down Expand Up @@ -494,7 +493,7 @@ export class GoogleSpreadsheet {

const exportUrl = this._spreadsheetUrl.replace('edit', 'export');
const response = await this.sheetsApi.get(exportUrl, {
prefixUrl: '', // unset baseUrl since we're not hitting the normal sheets API
prefix: '', // unset baseUrl since we're not hitting the normal sheets API
searchParams: {
id: this.spreadsheetId,
format: fileType,
Expand Down
Loading
Loading