{"id":3340,"date":"2026-07-02T03:37:57","date_gmt":"2026-07-02T03:37:57","guid":{"rendered":"https:\/\/tucumandevelopers.com\/index.php\/2026\/07\/02\/glasp-v0-3-0-v0-4-0-pkce-support-timeouts-and-retries\/"},"modified":"2026-07-02T03:37:57","modified_gmt":"2026-07-02T03:37:57","slug":"glasp-v0-3-0-v0-4-0-pkce-support-timeouts-and-retries","status":"publish","type":"post","link":"https:\/\/tucumandevelopers.com\/index.php\/2026\/07\/02\/glasp-v0-3-0-v0-4-0-pkce-support-timeouts-and-retries\/","title":{"rendered":"glasp v0.3.0 &#038; v0.4.0 \u2014 PKCE Support, Timeouts, and Retries"},"content":{"rendered":"<div>\n<div><\/header>\n<div data-article-id=\"4046647\" id=\"article-body\">\n<p>Last time I wrote about using glasp, a Go-based, npm-free CLI for Google Apps Script (GAS), in GitHub Actions.<\/p>\n<p><strong>Previous post:<\/strong> <a href=\"https:\/\/dev.to\/takihito\/lean-fast-simple-npm-free-gas-deployment-on-github-actions-with-glasp-3eaj\">Lean, Fast, Simple \u2014 npm-free GAS Deployment on GitHub Actions with glasp<\/a><\/p>\n<p>This time, a quick rundown of what landed in <a href=\"https:\/\/github.com\/takihito\/glasp\/releases\/tag\/v0.3.0\" target=\"_blank\" rel=\"noopener noreferrer\">v0.3.0<\/a> and <a href=\"https:\/\/github.com\/takihito\/glasp\/releases\/tag\/v0.4.0\" target=\"_blank\" rel=\"noopener noreferrer\">v0.4.0<\/a>.<\/p>\n<hr>\n<h2> <a name=\"v030-pkce-support\" href=\"#v030-pkce-support\"> <\/a> v0.3.0: PKCE support <\/h2>\n<p><code>glasp login<\/code> now supports PKCE (RFC 7636) as an opt-in. <\/p>\n<div>\n<pre><code>glasp login <span>--pkce<\/span> <span># or<\/span> <span>GLASP_USE_PKCE<\/span><span>=<\/span>1 glasp login <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>Each login generates a <code>code_verifier<\/code> and sends an <code>S256<\/code> <code>code_challenge<\/code> to Google. It&#8217;s a defense against authorization code interception, and it coexists fine with the existing <code>client_secret<\/code> flow. It only applies to the interactive login \u2014 <code>--auth<\/code> \/ <code>GLASP_AUTH<\/code> for CI is untouched.<\/p>\n<p>Off by default. Worth turning on if you&#8217;re in a stricter security environment.<\/p>\n<hr>\n<h2> <a name=\"v040-timeouts-and-retries\" href=\"#v040-timeouts-and-retries\"> <\/a> v0.4.0: Timeouts and retries <\/h2>\n<p>The focus here is basically &#8220;can this run unattended in CI\/CD without falling over.&#8221;<\/p>\n<h3> <a name=\"timeouts\" href=\"#timeouts\"> <\/a> Timeouts <\/h3>\n<p>Script API requests previously had no timeout \u2014 a stuck request could hang the job indefinitely. v0.4.0 adds a 180s default. <\/p>\n<div>\n<pre><code>glasp push <span>--timeout<\/span> 60 <span># set to 60s<\/span> glasp push <span>--no-timeout<\/span> <span># disable<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>Also configurable via <code>GLASP_TIMEOUT<\/code> \/ <code>GLASP_NO_TIMEOUT<\/code> env vars or <code>timeoutSeconds<\/code> in <code>.glasp\/config.json<\/code>. Priority: <code>--no-timeout<\/code> &gt; flag\/env &gt; config &gt; default. If the config file is broken, it warns instead of silently falling back.<\/p>\n<h3> <a name=\"retries\" href=\"#retries\"> <\/a> Retries <\/h3>\n<p>Transient failures (5xx, 429) now get retried automatically. <\/p>\n<div>\n<pre><code>glasp push <span>--max-retries<\/span> 5 glasp push <span>--no-retries<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<ul>\n<li>3 retries by default (up to 4 attempts total)<\/li>\n<li>Only applies to idempotent commands: <code>push<\/code>, <code>pull<\/code>, <code>clone<\/code>, <code>list-deployments<\/code> <\/li>\n<li>Commands with side effects (<code>create-script<\/code>, <code>run-function<\/code>, etc.) are never retried<\/li>\n<li>Exponential backoff with jitter, respecting <code>Retry-After<\/code> <\/li>\n<\/ul>\n<p>It&#8217;s implemented as a single <code>http.RoundTripper<\/code> wrapper, so the Google SDK itself isn&#8217;t touched \u2014 same pattern as the timeout implementation. <\/p>\n<div>\n<pre><code>retryTransport \u2192 oauth2.Transport \u2192 http.DefaultTransport <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<h3> <a name=\"some-refactoring-too\" href=\"#some-refactoring-too\"> <\/a> Some refactoring, too <\/h3>\n<p>Internal packages got reorganized (<a href=\"https:\/\/github.com\/takihito\/glasp\/pull\/107\" target=\"_blank\" rel=\"noopener noreferrer\">#107<\/a>), and the hand-rolled retry transport was swapped for <a href=\"https:\/\/github.com\/hashicorp\/go-retryablehttp\" target=\"_blank\" rel=\"noopener noreferrer\">go-retryablehttp<\/a> (<a href=\"https:\/\/github.com\/takihito\/glasp\/pull\/112\" target=\"_blank\" rel=\"noopener noreferrer\">#112<\/a>). No behavior change, just easier to maintain going forward.<\/p>\n<hr>\n<h2> <a name=\"in-github-actions\" href=\"#in-github-actions\"> <\/a> In GitHub Actions <\/h2>\n<p>Bump to <code>v0.4.0<\/code> and the timeout\/retry defaults just apply. Nothing else to do. <\/p>\n<div>\n<pre><code><span>-<\/span> <span>uses<\/span><span>:<\/span> <span>actions\/checkout@v4<\/span> <span>-<\/span> <span>uses<\/span><span>:<\/span> <span>takihito\/glasp@v0.4.0<\/span> <span>with<\/span><span>:<\/span> <span>version<\/span><span>:<\/span> <span>'<\/span><span>v0.4.0'<\/span> <span>auth<\/span><span>:<\/span> <span>${{ secrets.CLASPRC_JSON }}<\/span> <span>-<\/span> <span>run<\/span><span>:<\/span> <span>glasp push<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>If you&#8217;re hitting rate limits often, bumping <code>--max-retries<\/code> helps.<\/p>\n<hr>\n<h2> <a name=\"wrapping-up\" href=\"#wrapping-up\"> <\/a> Wrapping up <\/h2>\n<ul>\n<li>v0.3.0: PKCE if you want a slightly harder login flow<\/li>\n<li>v0.4.0: no more hanging, no more failing on transient errors<\/li>\n<\/ul>\n<p>No flashy new commands here \u2014 just reliability improvements that quietly matter.<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/takihito\/glasp\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub Repository: takihito\/glasp<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/takihito\/glasp\/releases\/tag\/v0.3.0\" target=\"_blank\" rel=\"noopener noreferrer\">Release v0.3.0<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/takihito\/glasp\/releases\/tag\/v0.4.0\" target=\"_blank\" rel=\"noopener noreferrer\">Release v0.4.0<\/a><\/li>\n<li><a href=\"https:\/\/takihito.github.io\/glasp\/\" target=\"_blank\" rel=\"noopener noreferrer\">glasp Documentation<\/a><\/li>\n<\/ul><\/div>\n<\/article>\n<p> <!-- Bottom content skipped via SKIP_BOTTOM_CONTENT config --> <\/div>\n<p> <\/main> <\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Fuente: <a href=\"https:\/\/dev.to\/takihito\/glasp-v030-v040-pkce-support-timeouts-and-retries-op6\">Art\u00edculo original<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time I wrote about using glasp, a Go-based, npm-free CLI for Google Apps Script (GAS), in GitHub Actions. Previous post: Lean, Fast, Simple \u2014 npm-free GAS Deployment on GitHub Actions with glasp This time, a quick rundown of what landed in v0.3.0 and v0.4.0. v0.3.0: PKCE support glasp login now supports PKCE (RFC 7636) [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3339,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[41],"tags":[],"class_list":["post-3340","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devto"],"jetpack_publicize_connections":[],"_links":{"self":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/3340","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/comments?post=3340"}],"version-history":[{"count":0,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/3340\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media\/3339"}],"wp:attachment":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media?parent=3340"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/categories?post=3340"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/tags?post=3340"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}