Skip to content

Commit 7b0b781

Browse files
Merge pull request #18 from CASParser/release-please--branches--main--changes--next
release: 0.9.0
2 parents c4a6c2b + af93587 commit 7b0b781

9 files changed

Lines changed: 108 additions & 37 deletions

File tree

.release-please-manifest.json

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

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 21
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser/cas-parser-2fd773786951b723a5d7d7342bf1c6ab46f08bd2851e916d188faae379d5aa4c.yml
3-
openapi_spec_hash: 7515d1e5fe3130b9f5411f7aacbc8a64
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser/cas-parser-e572d88c2af6e4d7bc4f7e119357fd3f68b1e67d612fd1d3a657d916cde0087c.yml
3+
openapi_spec_hash: a9fc7d947111bffa9184f8ca8be4a579
44
config_hash: 5509bb7a961ae2e79114b24c381606d4

CHANGELOG.md

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

3+
## 0.9.0 (2026-05-08)
4+
5+
Full Changelog: [v0.8.0...v0.9.0](https://github.com/CASParser/cas-parser-go/compare/v0.8.0...v0.9.0)
6+
7+
### Features
8+
9+
* **api:** api update ([1383709](https://github.com/CASParser/cas-parser-go/commit/1383709c5b1b49ffd5fcb142c8abd73f2f6728be))
10+
* **api:** api update ([6e974d9](https://github.com/CASParser/cas-parser-go/commit/6e974d99b79519daa77c5266f54077b5d41cc580))
11+
12+
13+
### Bug Fixes
14+
15+
* **go:** avoid panic when http.DefaultTransport is wrapped ([a0df656](https://github.com/CASParser/cas-parser-go/commit/a0df65678c6806e6c95ad992087c857275c0cdac))
16+
17+
18+
### Chores
19+
20+
* redact api-key headers in debug logs ([8cf162d](https://github.com/CASParser/cas-parser-go/commit/8cf162dc65df24e5f4ab99b8423d42c72c5ac70d))
21+
322
## 0.8.0 (2026-05-01)
423

524
Full Changelog: [v0.7.0...v0.8.0](https://github.com/CASParser/cas-parser-go/compare/v0.7.0...v0.8.0)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Or to pin the version:
3737
<!-- x-release-please-start-version -->
3838

3939
```sh
40-
go get -u 'github.com/CASParser/cas-parser-go@v0.8.0'
40+
go get -u 'github.com/CASParser/cas-parser-go@v0.9.0'
4141
```
4242

4343
<!-- x-release-please-end -->

default_http_client.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,17 @@ import (
1414
const defaultResponseHeaderTimeout = 10 * time.Minute
1515

1616
// defaultHTTPClient returns an [*http.Client] used when the caller does not
17-
// supply one via [option.WithHTTPClient]. It clones [http.DefaultTransport]
18-
// and adds a [http.Transport.ResponseHeaderTimeout] so stuck connections
19-
// fail fast instead of compounding across retries.
17+
// supply one via [option.WithHTTPClient]. When [http.DefaultTransport] is the
18+
// stdlib [*http.Transport], it is cloned and a [http.Transport.ResponseHeaderTimeout]
19+
// is set so stuck connections fail fast instead of compounding across retries.
20+
// If [http.DefaultTransport] has been wrapped (for example by otelhttp for
21+
// distributed tracing), the wrapping is preserved and the header timeout is
22+
// skipped.
2023
func defaultHTTPClient() *http.Client {
21-
transport := http.DefaultTransport.(*http.Transport).Clone()
22-
transport.ResponseHeaderTimeout = defaultResponseHeaderTimeout
23-
return &http.Client{Transport: transport}
24+
if t, ok := http.DefaultTransport.(*http.Transport); ok {
25+
t = t.Clone()
26+
t.ResponseHeaderTimeout = defaultResponseHeaderTimeout
27+
return &http.Client{Transport: t}
28+
}
29+
return &http.Client{Transport: http.DefaultTransport}
2430
}

inboundemail.go

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func (r *InboundEmailService) New(ctx context.Context, body InboundEmailNewParam
8282
return res, err
8383
}
8484

85-
// Retrieve details of a specific mailbox including statistics.
85+
// Retrieve details of a specific inbound email including statistics.
8686
func (r *InboundEmailService) Get(ctx context.Context, inboundEmailID string, opts ...option.RequestOption) (res *InboundEmailGetResponse, err error) {
8787
opts = slices.Concat(r.Options, opts)
8888
if inboundEmailID == "" {
@@ -94,8 +94,8 @@ func (r *InboundEmailService) Get(ctx context.Context, inboundEmailID string, op
9494
return res, err
9595
}
9696

97-
// List all mailboxes associated with your API key. Returns active and inactive
98-
// mailboxes (deleted mailboxes are excluded).
97+
// List all inbound emails associated with your API key. Returns active and paused
98+
// inbound emails (deleted ones are excluded).
9999
func (r *InboundEmailService) List(ctx context.Context, query InboundEmailListParams, opts ...option.RequestOption) (res *InboundEmailListResponse, err error) {
100100
opts = slices.Concat(r.Options, opts)
101101
path := "v4/inbound-email"
@@ -124,10 +124,10 @@ type InboundEmailNewResponse struct {
124124
//
125125
// Any of "cdsl", "nsdl", "cams", "kfintech".
126126
AllowedSources []string `json:"allowed_sources"`
127-
// Webhook URL for email notifications. `null` means files are only retrievable via
128-
// `GET /v4/inbound-email/{id}/files` (pull delivery).
129-
CallbackURL string `json:"callback_url" api:"nullable" format:"uri"`
130-
// When the mailbox was created
127+
// Webhook URL for email notifications. If set, we POST each parsed email here. If
128+
// omitted, files are only retrievable via `GET /v4/inbound-email/{id}/files`.
129+
CallbackURL string `json:"callback_url" format:"uri"`
130+
// When the inbound email was created
131131
CreatedAt time.Time `json:"created_at" format:"date-time"`
132132
// The inbound email address to forward CAS statements to
133133
Email string `json:"email" format:"email"`
@@ -137,11 +137,11 @@ type InboundEmailNewResponse struct {
137137
Metadata map[string]string `json:"metadata"`
138138
// Your internal reference identifier
139139
Reference string `json:"reference" api:"nullable"`
140-
// Current mailbox status
140+
// Current inbound email lifecycle status
141141
//
142142
// Any of "active", "paused".
143143
Status InboundEmailNewResponseStatus `json:"status"`
144-
// When the mailbox was last updated
144+
// When the inbound email was last updated
145145
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
146146
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
147147
JSON struct {
@@ -165,7 +165,7 @@ func (r *InboundEmailNewResponse) UnmarshalJSON(data []byte) error {
165165
return apijson.UnmarshalRoot(data, r)
166166
}
167167

168-
// Current mailbox status
168+
// Current inbound email lifecycle status
169169
type InboundEmailNewResponseStatus string
170170

171171
const (
@@ -179,10 +179,10 @@ type InboundEmailGetResponse struct {
179179
//
180180
// Any of "cdsl", "nsdl", "cams", "kfintech".
181181
AllowedSources []string `json:"allowed_sources"`
182-
// Webhook URL for email notifications. `null` means files are only retrievable via
183-
// `GET /v4/inbound-email/{id}/files` (pull delivery).
184-
CallbackURL string `json:"callback_url" api:"nullable" format:"uri"`
185-
// When the mailbox was created
182+
// Webhook URL for email notifications. If set, we POST each parsed email here. If
183+
// omitted, files are only retrievable via `GET /v4/inbound-email/{id}/files`.
184+
CallbackURL string `json:"callback_url" format:"uri"`
185+
// When the inbound email was created
186186
CreatedAt time.Time `json:"created_at" format:"date-time"`
187187
// The inbound email address to forward CAS statements to
188188
Email string `json:"email" format:"email"`
@@ -192,11 +192,11 @@ type InboundEmailGetResponse struct {
192192
Metadata map[string]string `json:"metadata"`
193193
// Your internal reference identifier
194194
Reference string `json:"reference" api:"nullable"`
195-
// Current mailbox status
195+
// Current inbound email lifecycle status
196196
//
197197
// Any of "active", "paused".
198198
Status InboundEmailGetResponseStatus `json:"status"`
199-
// When the mailbox was last updated
199+
// When the inbound email was last updated
200200
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
201201
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
202202
JSON struct {
@@ -220,7 +220,7 @@ func (r *InboundEmailGetResponse) UnmarshalJSON(data []byte) error {
220220
return apijson.UnmarshalRoot(data, r)
221221
}
222222

223-
// Current mailbox status
223+
// Current inbound email lifecycle status
224224
type InboundEmailGetResponseStatus string
225225

226226
const (
@@ -259,10 +259,10 @@ type InboundEmailListResponseInboundEmail struct {
259259
//
260260
// Any of "cdsl", "nsdl", "cams", "kfintech".
261261
AllowedSources []string `json:"allowed_sources"`
262-
// Webhook URL for email notifications. `null` means files are only retrievable via
263-
// `GET /v4/inbound-email/{id}/files` (pull delivery).
264-
CallbackURL string `json:"callback_url" api:"nullable" format:"uri"`
265-
// When the mailbox was created
262+
// Webhook URL for email notifications. If set, we POST each parsed email here. If
263+
// omitted, files are only retrievable via `GET /v4/inbound-email/{id}/files`.
264+
CallbackURL string `json:"callback_url" format:"uri"`
265+
// When the inbound email was created
266266
CreatedAt time.Time `json:"created_at" format:"date-time"`
267267
// The inbound email address to forward CAS statements to
268268
Email string `json:"email" format:"email"`
@@ -272,11 +272,11 @@ type InboundEmailListResponseInboundEmail struct {
272272
Metadata map[string]string `json:"metadata"`
273273
// Your internal reference identifier
274274
Reference string `json:"reference" api:"nullable"`
275-
// Current mailbox status
275+
// Current inbound email lifecycle status
276276
//
277277
// Any of "active", "paused".
278278
Status string `json:"status"`
279-
// When the mailbox was last updated
279+
// When the inbound email was last updated
280280
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
281281
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
282282
JSON struct {

inbox.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,11 @@ type InboxListCasFilesResponseFile struct {
220220
//
221221
// Any of "cdsl", "nsdl", "cams", "kfintech".
222222
CasType string `json:"cas_type"`
223-
// URL expiration time in seconds (default 86400 = 24 hours)
223+
// URL expiration time in seconds. Defaults vary by source:
224+
//
225+
// - Gmail Inbox Import: 86400 (24h)
226+
// - Inbound Email with `callback_url` set: 172800 (48h)
227+
// - Inbound Email without `callback_url`: aligned with the session TTL (~30 min)
224228
ExpiresIn int64 `json:"expires_in"`
225229
// Standardized filename (provider_YYYYMMDD_uniqueid.pdf)
226230
Filename string `json:"filename"`

internal/version.go

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

33
package internal
44

5-
const PackageVersion = "0.8.0" // x-release-please-version
5+
const PackageVersion = "0.9.0" // x-release-please-version

option/middleware.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import (
88
"net/http/httputil"
99
)
1010

11+
// sensitiveLogHeaders are redacted before request and response content is
12+
// written to the debug logger.
13+
var sensitiveLogHeaders = []string{"authorization", "api-key", "x-api-key", "cookie", "set-cookie"}
14+
1115
// WithDebugLog logs the HTTP request and response content.
1216
// If the logger parameter is nil, it uses the default logger.
1317
//
@@ -20,7 +24,7 @@ func WithDebugLog(logger *log.Logger) RequestOption {
2024
logger = log.Default()
2125
}
2226

23-
if reqBytes, err := httputil.DumpRequest(req, true); err == nil {
27+
if reqBytes, err := dumpRedactedRequest(req); err == nil {
2428
logger.Printf("Request Content:\n%s\n", reqBytes)
2529
}
2630

@@ -29,10 +33,48 @@ func WithDebugLog(logger *log.Logger) RequestOption {
2933
return resp, err
3034
}
3135

32-
if respBytes, err := httputil.DumpResponse(resp, true); err == nil {
36+
if respBytes, err := dumpRedactedResponse(resp); err == nil {
3337
logger.Printf("Response Content:\n%s\n", respBytes)
3438
}
3539

3640
return resp, err
3741
})
3842
}
43+
44+
// dumpRedactedRequest dumps req with sensitive headers replaced. The
45+
// original headers are restored via defer so a panic in DumpRequest cannot
46+
// leak the placeholder map into the live request sent downstream.
47+
func dumpRedactedRequest(req *http.Request) ([]byte, error) {
48+
origHeaders := req.Header
49+
req.Header = redactDebugHeaders(origHeaders)
50+
defer func() { req.Header = origHeaders }()
51+
return httputil.DumpRequest(req, true)
52+
}
53+
54+
func dumpRedactedResponse(resp *http.Response) ([]byte, error) {
55+
origHeaders := resp.Header
56+
resp.Header = redactDebugHeaders(origHeaders)
57+
defer func() { resp.Header = origHeaders }()
58+
return httputil.DumpResponse(resp, true)
59+
}
60+
61+
func redactDebugHeaders(headers http.Header) http.Header {
62+
var redacted http.Header
63+
for _, name := range sensitiveLogHeaders {
64+
values := headers.Values(name)
65+
if len(values) == 0 {
66+
continue
67+
}
68+
if redacted == nil {
69+
redacted = headers.Clone()
70+
}
71+
redacted.Del(name)
72+
for range values {
73+
redacted.Add(name, "***")
74+
}
75+
}
76+
if redacted == nil {
77+
return headers
78+
}
79+
return redacted
80+
}

0 commit comments

Comments
 (0)