Skip to content

Commit 9fb9bdd

Browse files
release: 1.2.0 (#57)
* fix: publish script — handle NPM errors correctly * chore(internal): add pure annotations, make base APIResource abstract * chore(client): refactor imports * feat(client): add support for endpoint-specific base URLs * chore(ci): enable for pull requests * chore(readme): update badges * chore(readme): use better example snippet for undocumented params * fix(client): explicitly copy fetch in withOptions * release: 1.2.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent 27aafd8 commit 9fb9bdd

19 files changed

Lines changed: 137 additions & 39 deletions

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ on:
77
- 'integrated/**'
88
- 'stl-preview-head/**'
99
- 'stl-preview-base/**'
10+
pull_request:
11+
branches-ignore:
12+
- 'stl-preview-head/**'
13+
- 'stl-preview-base/**'
1014

1115
jobs:
1216
lint:

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.1.3"
2+
".": "1.2.0"
33
}

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
# Changelog
22

3+
## 1.2.0 (2025-06-21)
4+
5+
Full Changelog: [v1.1.3...v1.2.0](https://github.com/GRID-is/api-sdk-ts/compare/v1.1.3...v1.2.0)
6+
7+
### Features
8+
9+
* **client:** add support for endpoint-specific base URLs ([46555cb](https://github.com/GRID-is/api-sdk-ts/commit/46555cbbc1a0c26644fedf60f830917fe0e0b624))
10+
11+
12+
### Bug Fixes
13+
14+
* **client:** explicitly copy fetch in withOptions ([d6b7a69](https://github.com/GRID-is/api-sdk-ts/commit/d6b7a69d4c66070e24c2ce92b5de049040c77d86))
15+
* publish script — handle NPM errors correctly ([1103e61](https://github.com/GRID-is/api-sdk-ts/commit/1103e616bd7f44660c7e31abc29812b0280734a8))
16+
17+
18+
### Chores
19+
20+
* **ci:** enable for pull requests ([51cc2e8](https://github.com/GRID-is/api-sdk-ts/commit/51cc2e84cf1dd20a9d7b2aaa2f1ee7ff724076f9))
21+
* **client:** refactor imports ([d540a0b](https://github.com/GRID-is/api-sdk-ts/commit/d540a0b6fca44bc2f57654092d66401ca73646fa))
22+
* **internal:** add pure annotations, make base APIResource abstract ([a2cc35d](https://github.com/GRID-is/api-sdk-ts/commit/a2cc35dce1e54638b7308c75027560428f24f29b))
23+
* **readme:** update badges ([19f82c2](https://github.com/GRID-is/api-sdk-ts/commit/19f82c249cb2d2de73698042303519d466807967))
24+
* **readme:** use better example snippet for undocumented params ([92ba27b](https://github.com/GRID-is/api-sdk-ts/commit/92ba27b2aa2834180767c0649b61ae6d3eb80bea))
25+
326
## 1.1.3 (2025-06-07)
427

528
Full Changelog: [v1.1.2...v1.1.3](https://github.com/GRID-is/api-sdk-ts/compare/v1.1.2...v1.1.3)

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# GRID Spreadsheet API Library
22

3-
[![NPM version](https://img.shields.io/npm/v/@grid-is/api.svg)](https://npmjs.org/package/@grid-is/api) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/@grid-is/api)
3+
[![NPM version](<https://img.shields.io/npm/v/@grid-is/api.svg?label=npm%20(stable)>)](https://npmjs.org/package/@grid-is/api) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/@grid-is/api)
44

55
This library provides convenient access to the GRID REST API from server-side TypeScript or JavaScript.
66

@@ -308,9 +308,8 @@ parameter. This library doesn't validate at runtime that the request matches the
308308
send will be sent as-is.
309309

310310
```ts
311-
client.foo.create({
312-
foo: 'my_param',
313-
bar: 12,
311+
client.workbooks.query({
312+
// ...
314313
// @ts-expect-error baz is not yet public
315314
baz: 'undocumented option',
316315
});

bin/publish-npm

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,35 @@ npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN"
77
yarn build
88
cd dist
99

10+
# Get package name and version from package.json
11+
PACKAGE_NAME="$(jq -r -e '.name' ./package.json)"
12+
VERSION="$(jq -r -e '.version' ./package.json)"
13+
1014
# Get latest version from npm
1115
#
12-
# If the package doesn't exist, yarn will return
13-
# {"type":"error","data":"Received invalid response from npm."}
14-
# where .data.version doesn't exist so LAST_VERSION will be an empty string.
15-
LAST_VERSION="$(yarn info --json 2> /dev/null | jq -r '.data.version')"
16-
17-
# Get current version from package.json
18-
VERSION="$(node -p "require('./package.json').version")"
16+
# If the package doesn't exist, npm will return:
17+
# {
18+
# "error": {
19+
# "code": "E404",
20+
# "summary": "Unpublished on 2025-06-05T09:54:53.528Z",
21+
# "detail": "'the_package' is not in this registry..."
22+
# }
23+
# }
24+
NPM_INFO="$(npm view "$PACKAGE_NAME" version --json 2>/dev/null || true)"
25+
26+
# Check if we got an E404 error
27+
if echo "$NPM_INFO" | jq -e '.error.code == "E404"' > /dev/null 2>&1; then
28+
# Package doesn't exist yet, no last version
29+
LAST_VERSION=""
30+
elif echo "$NPM_INFO" | jq -e '.error' > /dev/null 2>&1; then
31+
# Report other errors
32+
echo "ERROR: npm returned unexpected data:"
33+
echo "$NPM_INFO"
34+
exit 1
35+
else
36+
# Success - get the version
37+
LAST_VERSION=$(echo "$NPM_INFO" | jq -r '.') # strip quotes
38+
fi
1939

2040
# Check if current version is pre-release (e.g. alpha / beta / rc)
2141
CURRENT_IS_PRERELEASE=false

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grid-is/api",
3-
"version": "1.1.3",
3+
"version": "1.2.0",
44
"description": "The official TypeScript library for the Grid API",
55
"author": "Grid <info@grid.is>",
66
"types": "dist/index.d.ts",
@@ -42,7 +42,7 @@
4242
"publint": "^0.2.12",
4343
"ts-jest": "^29.1.0",
4444
"ts-node": "^10.5.0",
45-
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz",
45+
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz",
4646
"tsconfig-paths": "^4.0.0",
4747
"typescript": "5.8.3"
4848
},

scripts/build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fi
3131
node scripts/utils/make-dist-package-json.cjs > dist/package.json
3232

3333
# build to .js/.mjs/.d.ts files
34-
npm exec tsc-multi
34+
./node_modules/.bin/tsc-multi
3535
# we need to patch index.js so that `new module.exports()` works for cjs backwards
3636
# compat. No way to get that from index.ts because it would cause compile errors
3737
# when building .mjs

src/client.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type { HTTPMethod, PromiseOrValue, MergedRequestInit, FinalizedRequestIni
55
import { uuid4 } from './internal/utils/uuid';
66
import { validatePositiveInteger, isAbsoluteURL, safeJSON } from './internal/utils/values';
77
import { sleep } from './internal/utils/sleep';
8-
import { type Logger, type LogLevel, parseLogLevel } from './internal/utils/log';
98
export type { Logger, LogLevel } from './internal/utils/log';
109
import { castToError, isAbortError } from './internal/errors';
1110
import type { APIResponseProps } from './internal/parse';
@@ -19,9 +18,6 @@ import { AbstractPage, type CursorPaginationParams, CursorPaginationResponse } f
1918
import * as Uploads from './core/uploads';
2019
import * as API from './resources/index';
2120
import { APIPromise } from './core/api-promise';
22-
import { type Fetch } from './internal/builtin-types';
23-
import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
24-
import { FinalRequestOptions, RequestOptions } from './internal/request-options';
2521
import {
2622
Beta,
2723
BetaGetWorkbookLabelsResponse,
@@ -45,8 +41,17 @@ import {
4541
WorkbookValuesResponse,
4642
Workbooks,
4743
} from './resources/workbooks';
44+
import { type Fetch } from './internal/builtin-types';
45+
import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
46+
import { FinalRequestOptions, RequestOptions } from './internal/request-options';
4847
import { readEnv } from './internal/utils/env';
49-
import { formatRequestDetails, loggerFor } from './internal/utils/log';
48+
import {
49+
type LogLevel,
50+
type Logger,
51+
formatRequestDetails,
52+
loggerFor,
53+
parseLogLevel,
54+
} from './internal/utils/log';
5055
import { isEmptyObj } from './internal/utils/values';
5156

5257
export interface ClientOptions {
@@ -200,12 +205,20 @@ export class Grid {
200205
timeout: this.timeout,
201206
logger: this.logger,
202207
logLevel: this.logLevel,
208+
fetch: this.fetch,
203209
fetchOptions: this.fetchOptions,
204210
apiKey: this.apiKey,
205211
...options,
206212
});
207213
}
208214

215+
/**
216+
* Check whether the base URL is set to its default.
217+
*/
218+
#baseURLOverridden(): boolean {
219+
return this.baseURL !== 'https://api.grid.is';
220+
}
221+
209222
protected defaultQuery(): Record<string, string | undefined> | undefined {
210223
return this._options.defaultQuery;
211224
}
@@ -255,11 +268,16 @@ export class Grid {
255268
return Errors.APIError.generate(status, error, message, headers);
256269
}
257270

258-
buildURL(path: string, query: Record<string, unknown> | null | undefined): string {
271+
buildURL(
272+
path: string,
273+
query: Record<string, unknown> | null | undefined,
274+
defaultBaseURL?: string | undefined,
275+
): string {
276+
const baseURL = (!this.#baseURLOverridden() && defaultBaseURL) || this.baseURL;
259277
const url =
260278
isAbsoluteURL(path) ?
261279
new URL(path)
262-
: new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
280+
: new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
263281

264282
const defaultQuery = this.defaultQuery();
265283
if (!isEmptyObj(defaultQuery)) {
@@ -619,9 +637,9 @@ export class Grid {
619637
{ retryCount = 0 }: { retryCount?: number } = {},
620638
): { req: FinalizedRequestInit; url: string; timeout: number } {
621639
const options = { ...inputOptions };
622-
const { method, path, query } = options;
640+
const { method, path, query, defaultBaseURL } = options;
623641

624-
const url = this.buildURL(path!, query as Record<string, unknown>);
642+
const url = this.buildURL(path!, query as Record<string, unknown>, defaultBaseURL);
625643
if ('timeout' in options) validatePositiveInteger('timeout', options.timeout);
626644
options.timeout = options.timeout ?? this.timeout;
627645
const { bodyHeaders, body } = this.buildBody({ options });

src/core/resource.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import type { Grid } from '../client';
44

5-
export class APIResource {
5+
export abstract class APIResource {
66
protected _client: Grid;
77

88
constructor(client: Grid) {

src/internal/headers.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

3+
import { isReadonlyArray } from './utils/values';
4+
35
type HeaderValue = string | undefined | null;
46
export type HeadersLike =
57
| Headers
@@ -9,7 +11,7 @@ export type HeadersLike =
911
| null
1012
| NullableHeaders;
1113

12-
const brand_privateNullableHeaders = Symbol('brand.privateNullableHeaders');
14+
const brand_privateNullableHeaders = /* @__PURE__ */ Symbol('brand.privateNullableHeaders');
1315

1416
/**
1517
* @internal
@@ -25,8 +27,6 @@ export type NullableHeaders = {
2527
nulls: Set<string>;
2628
};
2729

28-
const isArray = Array.isArray as (val: unknown) => val is readonly unknown[];
29-
3030
function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [string, string | null]> {
3131
if (!headers) return;
3232

@@ -43,7 +43,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [strin
4343
let iter: Iterable<readonly (HeaderValue | readonly HeaderValue[])[]>;
4444
if (headers instanceof Headers) {
4545
iter = headers.entries();
46-
} else if (isArray(headers)) {
46+
} else if (isReadonlyArray(headers)) {
4747
iter = headers;
4848
} else {
4949
shouldClear = true;
@@ -52,7 +52,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [strin
5252
for (let row of iter) {
5353
const name = row[0];
5454
if (typeof name !== 'string') throw new TypeError('expected header name to be a string');
55-
const values = isArray(row[1]) ? row[1] : [row[1]];
55+
const values = isReadonlyArray(row[1]) ? row[1] : [row[1]];
5656
let didClear = false;
5757
for (const value of values) {
5858
if (value === undefined) continue;

0 commit comments

Comments
 (0)