Repository: romanbsd/heroku-deflater
Branch: master
Commit: 2da0dcd44ed5
Files: 22
Total size: 14.9 KB
Directory structure:
gitextract_k81df0ef/
├── .gitignore
├── .rspec
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── VERSION
├── heroku-deflater.gemspec
├── lib/
│ ├── heroku-deflater/
│ │ ├── cache_control_manager.rb
│ │ ├── railtie.rb
│ │ ├── serve_zipped_assets.rb
│ │ ├── skip_binary.rb
│ │ └── version.rb
│ └── heroku-deflater.rb
└── spec/
├── cache_control_manager_spec.rb
├── fixtures/
│ ├── assets/
│ │ ├── spec.js
│ │ └── spec2.js
│ └── packs/
│ ├── spec.js
│ └── spec2.js
├── serve_zipped_assets_spec.rb
├── skip_binary_spec.rb
└── spec_helper.rb
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/
# rspec failure tracking
.rspec_status
================================================
FILE: .rspec
================================================
--colour
--format progress
--tag ~slow
================================================
FILE: Gemfile
================================================
# frozen_string_literal: true
source 'https://rubygems.org'
gemspec
gem 'rack', '>=1.4.5'
group :development do
gem 'bundler'
gem 'rspec'
gem 'rails', '~>6.1'
end
================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2012 Roman Shterenzon
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# heroku-deflater
A simple rack middleware that enables compressing of your sprockets and
webpacker assets and application responses on Heroku, while not wasting CPU
cycles on pointlessly compressing images and other binary responses.
It also includes code from https://github.com/mattolson/heroku_rails_deflate
Before serving a file from disk to a gzip-enabled client, it will look for a
precompressed file in the same location that ends in ".gz". The purpose is to
avoid compressing the same file each time it is requested.
## Installing
Add to your Gemfile:
gem 'heroku-deflater', :group => :production
## Contributing to heroku-deflater
* Check out the latest master to make sure the feature hasn't been implemented
or the bug hasn't been fixed yet.
* Check out the issue tracker to make sure someone already hasn't requested it
and/or contributed it.
* Fork the project.
* Start a feature/bugfix branch.
* Commit and push until you are happy with your contribution.
* Make sure to add tests for it. This is important so I don't break it in a
future version unintentionally.
* Please try not to mess with the Rakefile, version, or history. If you want to
have your own version, or is otherwise necessary, that is fine, but please
isolate to its own commit so I can cherry-pick around it.
## Copyright
Copyright (c) 2012 Roman Shterenzon. See LICENSE.txt for further details.
[1]: https://github.com/rack/rack/issues/349
================================================
FILE: Rakefile
================================================
# frozen_string_literal: true
require 'bundler/gem_tasks'
begin
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
rescue LoadError
end
task default: :spec
require 'rdoc/task'
Rake::RDocTask.new do |rdoc|
version = File.exist?('VERSION') ? File.read('VERSION') : ''
rdoc.rdoc_dir = 'rdoc'
rdoc.title = "heroku-deflater #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end
================================================
FILE: VERSION
================================================
0.6.3
================================================
FILE: heroku-deflater.gemspec
================================================
# frozen_string_literal: true
require_relative 'lib/heroku-deflater/version'
Gem::Specification.new do |s|
s.name = 'heroku-deflater'
s.version = HerokuDeflater::VERSION
s.authors = ['Roman Shterenzon']
s.email = 'romanbsd@yahoo.com'
s.summary = 'Deflate assets on heroku'
s.description = 'Deflate assets on Heroku'
s.homepage = 'https://github.com/romanbsd/heroku-deflater'
s.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
s.require_paths = ['lib']
s.extra_rdoc_files = [
'LICENSE.txt',
'README.md'
]
s.licenses = ['MIT']
s.files = Dir.chdir(File.expand_path(__dir__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
end
================================================
FILE: lib/heroku-deflater/cache_control_manager.rb
================================================
module HerokuDeflater
class CacheControlManager
DEFAULT_MAX_AGE = '86400'.freeze
attr_reader :app, :max_age
def initialize(app)
@app = app
@max_age = DEFAULT_MAX_AGE
end
def setup_max_age(max_age)
@max_age = max_age
end
def cache_control_headers
if HerokuDeflater.rails_version_5?
headers = app.config.public_file_server.headers ||= {}
headers['Cache-Control'] ||= "public, max-age=#{max_age}"
headers
else
app.config.static_cache_control ||= "public, max-age=#{max_age}"
end
end
end
end
================================================
FILE: lib/heroku-deflater/railtie.rb
================================================
require 'rack/deflater'
require 'heroku-deflater/skip_binary'
require 'heroku-deflater/serve_zipped_assets'
require 'heroku-deflater/cache_control_manager'
module HerokuDeflater
class Railtie < Rails::Railtie
initializer 'heroku_deflater.configure_rails_initialization' do |app|
app.middleware.insert_before ActionDispatch::Static, Rack::Deflater
app.middleware.insert_before ActionDispatch::Static, HerokuDeflater::SkipBinary
assets_prefix = app.config.assets.prefix if app.config.respond_to?(:assets)
if Object.const_defined?(:Webpacker)
public_path = Webpacker.config.public_path.to_s
public_output_path = Webpacker.config.public_output_path.to_s
webpacker_prefix = public_output_path.split(public_path).last
end
if assets_prefix || webpacker_prefix
paths = [assets_prefix, webpacker_prefix].compact
app.middleware.insert_before Rack::Deflater, HerokuDeflater::ServeZippedAssets,
app.paths['public'].first, paths, self.class.cache_control_manager(app)
end
end
def self.cache_control_manager(app)
@_cache_control_manager ||= CacheControlManager.new(app)
end
# Set default Cache-Control headers to 24 hours.
# The configuration block in config/application.rb overrides this.
config.before_initialize do |app|
cache_control = cache_control_manager(app)
cache_control.setup_max_age(86400)
end
end
end
================================================
FILE: lib/heroku-deflater/serve_zipped_assets.rb
================================================
require 'action_controller'
require 'action_dispatch/middleware/static'
if Rails::VERSION::MAJOR < 7
# Deprecated in Rails 7.0, and removed in 7.1
require 'active_support/core_ext/uri'
end
# Adapted from https://gist.github.com/guyboltonking/2152663
#
# Taken from: https://github.com/mattolson/heroku_rails_deflate
#
module HerokuDeflater
class ServeZippedAssets
def initialize(app, root, paths, cache_control_manager)
@app = app
@paths = paths.map { |p| p.chomp('/') + '/' }
if HerokuDeflater.rails_version_5?
@file_handler = ActionDispatch::FileHandler.new(root, headers: cache_control_manager.cache_control_headers)
else
@file_handler = ActionDispatch::FileHandler.new(root, cache_control_manager.cache_control_headers)
end
end
def call(env)
if env['REQUEST_METHOD'] == 'GET'
request = Rack::Request.new(env)
encoding = Rack::Utils.select_best_encoding(%w(gzip identity), request.accept_encoding)
if encoding == 'gzip'
# See if gzipped version exists in assets directory
compressed_path = env['PATH_INFO'] + '.gz'
if compressed_path.start_with?(*@paths) && (match = @file_handler.match?(compressed_path))
# Get the FileHandler to serve up the gzipped file, then strip the .gz suffix
env['PATH_INFO'] = match
status, headers, body = @file_handler.call(env)
env['PATH_INFO'].chomp!('.gz')
# Set the Vary HTTP header.
vary = headers['Vary'].to_s.split(',').map(&:strip)
unless vary.include?('*') || vary.include?('Accept-Encoding')
headers['Vary'] = vary.push('Accept-Encoding').join(',')
end
# Add encoding and type
headers['Content-Encoding'] = 'gzip'
headers['Content-Type'] = Rack::Mime.mime_type(File.extname(env['PATH_INFO']), 'text/plain')
body.close if body.respond_to?(:close)
return [status, headers, body]
end
end
end
@app.call(env)
end
end
end
================================================
FILE: lib/heroku-deflater/skip_binary.rb
================================================
module HerokuDeflater
# Add a no-transform Cache-Control header to binary types, so they won't get gzipped
class SkipBinary
def initialize(app)
@app = app
end
WHITELIST = [
%r{^text/},
'application/javascript',
%r{^application/.*?json},
%r{^application/.*?xml},
'application/x-font-ttf',
'font/opentype',
'image/svg+xml'
].freeze
def call(env)
status, headers, body = @app.call(env)
headers = Rack::Utils::HeaderHash.new(headers) if defined?(Rack::Utils::HeaderHash)
content_type = headers['content-type']
cache_control = headers['cache-control'].to_s.downcase
unless cache_control.include?('no-transform') || WHITELIST.any? { |type| type === content_type }
if cache_control.empty?
headers['cache-control'] = 'no-transform'
else
headers['cache-control'] += ', no-transform'
end
end
body.close if body.respond_to?(:close)
[status, headers.to_h, body]
end
end
end
================================================
FILE: lib/heroku-deflater/version.rb
================================================
# frozen_string_literal: true
module HerokuDeflater
VERSION = '0.7.0'
end
================================================
FILE: lib/heroku-deflater.rb
================================================
require 'heroku-deflater/railtie'
module HerokuDeflater
def self.rails_version_5?
Rails::VERSION::MAJOR >= 5
end
end
================================================
FILE: spec/cache_control_manager_spec.rb
================================================
require 'spec_helper'
describe HerokuDeflater::CacheControlManager do
subject { described_class.new(app) }
before { subject.setup_max_age(86400) }
context 'Rails 4.x and below' do
let(:app) { Rails4App.new }
before do
allow(HerokuDeflater).to receive(:rails_version_5?).and_return(false)
subject.cache_control_headers
end
it 'sets max age for static_cache_control config option' do
expect(app.config.static_cache_control).to eq('public, max-age=86400')
end
it 'cache_control_headers returns cache control option' do
expect(subject.cache_control_headers).to eq('public, max-age=86400')
end
end
context 'Rails 5' do
let(:app) { Rails5App.new }
before do
allow(HerokuDeflater).to receive(:rails_version_5?).and_return(true)
subject.cache_control_headers
end
it 'sets max age for public_file_server config option' do
expect(app.config.public_file_server.headers['Cache-Control']).to eq('public, max-age=86400')
end
it 'cache_control_headers returns hash cache control headers' do
expect(subject.cache_control_headers).to eq({'Cache-Control' =>'public, max-age=86400'})
end
end
end
================================================
FILE: spec/fixtures/assets/spec.js
================================================
// Fixture file
(function() {
console.log("Hello world");
console.log("Hello world");
console.log("Hello world");
})();
================================================
FILE: spec/fixtures/assets/spec2.js
================================================
// Fixture file
(function() {
console.log("Hello world");
})();
================================================
FILE: spec/fixtures/packs/spec.js
================================================
// Fixture file
(function() {
console.log("Hello world");
console.log("Hello world");
console.log("Hello world");
})();
================================================
FILE: spec/fixtures/packs/spec2.js
================================================
// Fixture file
(function() {
console.log("Hello world");
})();
================================================
FILE: spec/serve_zipped_assets_spec.rb
================================================
require 'spec_helper'
describe HerokuDeflater::ServeZippedAssets do
shared_examples_for 'ServeZippedAssets' do
%w(assets packs).each do |path|
it 'does nothing for clients which do not want gzip' do
status, headers, body = process("/#{path}/spec.js", nil)
expect(status).to eq(404)
end
it 'handles the pre-gzipped assets' do
status, headers, body = process("/#{path}/spec.js")
expect(status).to eq(200)
end
it 'has correct content type' do
status, headers, body = process("/#{path}/spec.js")
expect(headers['Content-Type']).to eq('application/javascript')
end
it 'has correct content encoding' do
status, headers, body = process("/#{path}/spec.js")
expect(headers['Content-Encoding']).to eq('gzip')
end
it 'has correct content length' do
status, headers, body = process("/#{path}/spec.js")
expect(headers['Content-Length']).to eq('86')
end
it 'has correct cache control' do
status, headers, body = process("/#{path}/spec.js")
expect(headers['Cache-Control']).to eq('public, max-age=86400')
end
it 'does not serve non-gzipped assets' do
status, headers, body = process("/#{path}/spec2.js")
expect(status).to eq(404)
end
it 'does not serve anything from non-asset directories' do
status, headers, body = process("/non-#{path}/spec.js")
expect(status).to eq(404)
end
end
end
describe 'Rais 4.x' do
let(:app) { Rails4App.new }
before do
allow(HerokuDeflater).to receive(:rails_version_5?) { false }
end
# FIXME: It will work only with gemfiles
# it_behaves_like 'ServeZippedAssets'
end
describe 'Rais 5.x' do
let(:app) { Rails5App.new }
before do
allow(HerokuDeflater).to receive(:rails_version_5?) { true }
end
it_behaves_like 'ServeZippedAssets'
end
def process(path, accept_encoding = 'compress, gzip, deflate')
env = Rack::MockRequest.env_for(path)
env['HTTP_ACCEPT_ENCODING'] = accept_encoding
middleware.call(env)
end
def middleware
@middleware ||= begin
root_path = File.expand_path('../fixtures', __FILE__)
cache_control_manager = HerokuDeflater::CacheControlManager.new(app)
mock = lambda { |env| [404, {'X-Cascade' => 'pass'}, []] }
described_class.new(mock, root_path, ['/assets', '/packs'], cache_control_manager)
end
end
end
================================================
FILE: spec/skip_binary_spec.rb
================================================
require 'spec_helper'
describe HerokuDeflater::SkipBinary do
let(:env) { Rack::MockRequest.env_for('/') }
def app_returning_type(type, headers = {})
lambda { |env| [200, {'Content-Type' => type}.merge(headers), ['']] }
end
def process(type, headers = {})
described_class.new(app_returning_type(type, headers)).call(env)[1]
end
it "forbids compressing of binary types" do
%w[application/gzip application/pdf image/jpeg].each do |type|
headers = process(type)
expect(headers['Cache-Control'].to_s).to include('no-transform')
end
end
it "allows compressing of text types" do
%w[text/plain text/html application/json application/javascript
application/rss+xml application/vnd.api+json].each do |type|
headers = process(type)
expect(headers['Cache-Control'].to_s).not_to include('no-transform')
end
end
it "adds to existing headers" do
headers = process('image/gif', 'Cache-Control' => 'public')
expect(headers['Cache-Control']).to eq('public, no-transform')
end
it "doesn't add 'no-transform' if it's already present" do
headers = process('image/gif', 'Cache-Control' => 'public, no-transform')
expect(headers['Cache-Control']).to eq('public, no-transform')
end
end
================================================
FILE: spec/spec_helper.rb
================================================
require 'rails'
require 'rack/mock'
require 'rack/static'
require 'heroku-deflater'
require 'heroku-deflater/serve_zipped_assets'
require 'heroku-deflater/cache_control_manager'
require 'heroku-deflater/skip_binary'
class Rails5App
def config
@_config ||= Config.new
end
class Config
attr_accessor :headers
def initialize
@headers = {}
end
def public_file_server
self
end
end
end
class Rails4App
def config
@_config ||= Config.new
end
class Config
attr_accessor :static_cache_control
end
end
gitextract_k81df0ef/
├── .gitignore
├── .rspec
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── VERSION
├── heroku-deflater.gemspec
├── lib/
│ ├── heroku-deflater/
│ │ ├── cache_control_manager.rb
│ │ ├── railtie.rb
│ │ ├── serve_zipped_assets.rb
│ │ ├── skip_binary.rb
│ │ └── version.rb
│ └── heroku-deflater.rb
└── spec/
├── cache_control_manager_spec.rb
├── fixtures/
│ ├── assets/
│ │ ├── spec.js
│ │ └── spec2.js
│ └── packs/
│ ├── spec.js
│ └── spec2.js
├── serve_zipped_assets_spec.rb
├── skip_binary_spec.rb
└── spec_helper.rb
SYMBOL INDEX (31 symbols across 9 files)
FILE: lib/heroku-deflater.rb
type HerokuDeflater (line 3) | module HerokuDeflater
function rails_version_5? (line 4) | def self.rails_version_5?
FILE: lib/heroku-deflater/cache_control_manager.rb
type HerokuDeflater (line 1) | module HerokuDeflater
class CacheControlManager (line 2) | class CacheControlManager
method initialize (line 6) | def initialize(app)
method setup_max_age (line 11) | def setup_max_age(max_age)
method cache_control_headers (line 15) | def cache_control_headers
FILE: lib/heroku-deflater/railtie.rb
type HerokuDeflater (line 6) | module HerokuDeflater
class Railtie (line 7) | class Railtie < Rails::Railtie
method cache_control_manager (line 27) | def self.cache_control_manager(app)
FILE: lib/heroku-deflater/serve_zipped_assets.rb
type HerokuDeflater (line 13) | module HerokuDeflater
class ServeZippedAssets (line 14) | class ServeZippedAssets
method initialize (line 15) | def initialize(app, root, paths, cache_control_manager)
method call (line 26) | def call(env)
FILE: lib/heroku-deflater/skip_binary.rb
type HerokuDeflater (line 1) | module HerokuDeflater
class SkipBinary (line 3) | class SkipBinary
method initialize (line 4) | def initialize(app)
method call (line 18) | def call(env)
FILE: lib/heroku-deflater/version.rb
type HerokuDeflater (line 3) | module HerokuDeflater
FILE: spec/serve_zipped_assets_spec.rb
function process (line 69) | def process(path, accept_encoding = 'compress, gzip, deflate')
function middleware (line 75) | def middleware
FILE: spec/skip_binary_spec.rb
function app_returning_type (line 6) | def app_returning_type(type, headers = {})
function process (line 10) | def process(type, headers = {})
FILE: spec/spec_helper.rb
class Rails5App (line 10) | class Rails5App
method config (line 11) | def config
class Config (line 15) | class Config
method initialize (line 18) | def initialize
method public_file_server (line 22) | def public_file_server
class Rails4App (line 28) | class Rails4App
method config (line 29) | def config
class Config (line 33) | class Config
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (17K chars).
[
{
"path": ".gitignore",
"chars": 113,
"preview": "/.bundle/\n/.yardoc\n/_yardoc/\n/coverage/\n/doc/\n/pkg/\n/spec/reports/\n/tmp/\n\n# rspec failure tracking\n.rspec_status\n"
},
{
"path": ".rspec",
"chars": 39,
"preview": "--colour\n--format progress\n--tag ~slow\n"
},
{
"path": "Gemfile",
"chars": 173,
"preview": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\ngemspec\n\ngem 'rack', '>=1.4.5'\n\ngroup :development do\n ge"
},
{
"path": "LICENSE.txt",
"chars": 1060,
"preview": "Copyright (c) 2012 Roman Shterenzon\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of thi"
},
{
"path": "README.md",
"chars": 1440,
"preview": "# heroku-deflater\n\nA simple rack middleware that enables compressing of your sprockets and\nwebpacker assets and applicat"
},
{
"path": "Rakefile",
"chars": 440,
"preview": "# frozen_string_literal: true\n\nrequire 'bundler/gem_tasks'\nbegin\n require 'rspec/core/rake_task'\n RSpec::Core::RakeTas"
},
{
"path": "VERSION",
"chars": 5,
"preview": "0.6.3"
},
{
"path": "heroku-deflater.gemspec",
"chars": 716,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'lib/heroku-deflater/version'\n\nGem::Specification.new do |s|\n s.name = "
},
{
"path": "lib/heroku-deflater/cache_control_manager.rb",
"chars": 595,
"preview": "module HerokuDeflater\n class CacheControlManager\n DEFAULT_MAX_AGE = '86400'.freeze\n attr_reader :app, :max_age\n\n "
},
{
"path": "lib/heroku-deflater/railtie.rb",
"chars": 1452,
"preview": "require 'rack/deflater'\nrequire 'heroku-deflater/skip_binary'\nrequire 'heroku-deflater/serve_zipped_assets'\nrequire 'her"
},
{
"path": "lib/heroku-deflater/serve_zipped_assets.rb",
"chars": 2098,
"preview": "require 'action_controller'\nrequire 'action_dispatch/middleware/static'\n\nif Rails::VERSION::MAJOR < 7\n # Deprecated in "
},
{
"path": "lib/heroku-deflater/skip_binary.rb",
"chars": 1036,
"preview": "module HerokuDeflater\n # Add a no-transform Cache-Control header to binary types, so they won't get gzipped\n class Ski"
},
{
"path": "lib/heroku-deflater/version.rb",
"chars": 77,
"preview": "# frozen_string_literal: true\n\nmodule HerokuDeflater\n VERSION = '0.7.0'\nend\n"
},
{
"path": "lib/heroku-deflater.rb",
"chars": 126,
"preview": "require 'heroku-deflater/railtie'\n\nmodule HerokuDeflater\n def self.rails_version_5?\n Rails::VERSION::MAJOR >= 5\n en"
},
{
"path": "spec/cache_control_manager_spec.rb",
"chars": 1202,
"preview": "require 'spec_helper'\n\ndescribe HerokuDeflater::CacheControlManager do\n subject { described_class.new(app) }\n before {"
},
{
"path": "spec/fixtures/assets/spec.js",
"chars": 126,
"preview": "// Fixture file\n(function() {\n console.log(\"Hello world\");\n console.log(\"Hello world\");\n console.log(\"Hello world\");\n"
},
{
"path": "spec/fixtures/assets/spec2.js",
"chars": 66,
"preview": "// Fixture file\n(function() {\n console.log(\"Hello world\");\n})();\n"
},
{
"path": "spec/fixtures/packs/spec.js",
"chars": 126,
"preview": "// Fixture file\n(function() {\n console.log(\"Hello world\");\n console.log(\"Hello world\");\n console.log(\"Hello world\");\n"
},
{
"path": "spec/fixtures/packs/spec2.js",
"chars": 66,
"preview": "// Fixture file\n(function() {\n console.log(\"Hello world\");\n})();\n"
},
{
"path": "spec/serve_zipped_assets_spec.rb",
"chars": 2494,
"preview": "require 'spec_helper'\n\ndescribe HerokuDeflater::ServeZippedAssets do\n shared_examples_for 'ServeZippedAssets' do\n %w"
},
{
"path": "spec/skip_binary_spec.rb",
"chars": 1263,
"preview": "require 'spec_helper'\n\ndescribe HerokuDeflater::SkipBinary do\n let(:env) { Rack::MockRequest.env_for('/') }\n\n def app_"
},
{
"path": "spec/spec_helper.rb",
"chars": 559,
"preview": "require 'rails'\nrequire 'rack/mock'\nrequire 'rack/static'\n\nrequire 'heroku-deflater'\nrequire 'heroku-deflater/serve_zipp"
}
]
About this extraction
This page contains the full source code of the romanbsd/heroku-deflater GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (14.9 KB), approximately 4.4k tokens, and a symbol index with 31 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.