···0000001## [0.0.1] - 2025-12-22
23- first working version, with streaming from Tap, support for ack and admin password options, and calling two HTTP endpoints
···1+## [0.0.2] - 2025-12-23
2+3+- added `#operation` method (aliased as `#op`) to `Operation`
4+- added `#resolve_did` for calling the `/resolve/:did` API endpoint
5+- workaround for `isActive` field sent as `is_active` in identity events
6+7## [0.0.1] - 2025-12-22
89- first working version, with streaming from Tap, support for ack and admin password options, and calling two HTTP endpoints
+7-2
README.md
···3334## Installation
3536-Add this to your `Gemfile`:
003738 gem 'tapfall'
39···116- `type` (symbol) – the message type identifier, e.g. `:record`
117- `id` (integer), aliased as `seq` – a sequential index of the message
118119-The `:record` messages have an `operations` method, which includes an array of add/remove/edit `Operation`s done on some records. Currently Tap event format only includes one single record operation in each event, but it's returned as an array here for symmetry with the `Skyfall::Firehose` stream version.
120121An `Operation` has such fields (also matching the API of `Skyfall::Firehose::Operation` and `Skyfall::Jetstream::Operation`):
122···147 end
148end
149```
000150151152### Note on custom lexicons
···3334## Installation
3536+Tapfall should run on any somewhat recent version of Ruby (3.x/4.x), although it's recommended to use one that's still getting maintenance updates, ideally the latest one. In production, it's also recommended to install it with [YJIT support](https://shopify.engineering/ruby-yjit-is-production-ready) and with [jemalloc](https://scalingo.com/blog/improve-ruby-application-memory-jemalloc). A compatible version should be available on most Linux systems, otherwise you can install one using tools such as [RVM](https://rvm.io), [asdf](https://asdf-vm.com), [ruby-install](https://github.com/postmodern/ruby-install) or [ruby-build](https://github.com/rbenv/ruby-build), or `rpm` or `apt-get` on Linux (see more installation options on [ruby-lang.org](https://www.ruby-lang.org/en/downloads/)).
37+38+To use it in your app, add this to your `Gemfile`:
3940 gem 'tapfall'
41···118- `type` (symbol) – the message type identifier, e.g. `:record`
119- `id` (integer), aliased as `seq` – a sequential index of the message
120121+The `:record` messages have an `operation` method (aliased as `op`), which returns an `Operation` object with details of an create/update/delete operation done a record. (For symmetry with the `Skyfall::Firehose` stream version, there's also an `operations` method which returns an array.)
122123An `Operation` has such fields (also matching the API of `Skyfall::Firehose::Operation` and `Skyfall::Jetstream::Operation`):
124···149 end
150end
151```
152+153+> [!NOTE]
154+> If you're doing a full network backfill of some app.bsky.* lexicons, that's going to be a *lot* of events that Tap will be sending to you, on localhost (so not limited by network bandwidth), likely in large bursts. In that case it's [recommended](https://bsky.app/profile/did:plc:ragtjsm2j2vknwkz3zp4oxrd/post/3mawmnwukws2w) to try to do as little processing as possible in the event handling loop, and especially avoid any sync network requests there. If you're working with a limited number of repos and/or with non-Bluesky lexicons only, this is probably much less of an issue.
155156157### Note on custom lexicons
+24
lib/tapfall/api.rb
···25 post_request('/repos/remove', { dids: dids })
26 end
27000028 private
2930 def build_root_url(server)
···49 end
50 end
51000000000000000052 def post_request(path, json_data)
53 uri = URI(@root_url + path)
54···64 http.request(request)
65 end
66000067 status = response.code.to_i
68 message = response.message
69 response_body = (response.content_type == 'application/json') ? JSON.parse(response.body) : response.body
···25 post_request('/repos/remove', { dids: dids })
26 end
2728+ def resolve_did(did)
29+ get_request("/resolve/#{did}")
30+ end
31+32 private
3334 def build_root_url(server)
···53 end
54 end
5556+ def get_request(path)
57+ uri = URI(@root_url + path)
58+59+ request = Net::HTTP::Get.new(uri)
60+61+ if @options[:admin_password]
62+ request.basic_auth('admin', @options[:admin_password])
63+ end
64+65+ response = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => (uri.scheme == 'https')) do |http|
66+ http.request(request)
67+ end
68+69+ handle_response(response)
70+ end
71+72 def post_request(path, json_data)
73 uri = URI(@root_url + path)
74···84 http.request(request)
85 end
8687+ handle_response(response)
88+ end
89+90+ def handle_response(response)
91 status = response.code.to_i
92 message = response.message
93 response_body = (response.content_type == 'application/json') ? JSON.parse(response.body) : response.body
+1-1
lib/tapfall/messages/identity_message.rb
···20 end
2122 def active?
23- @identity['isActive']
24 end
2526 def status
···20 end
2122 def active?
23+ @identity['isActive'] || @identity['is_active']
24 end
2526 def status
+7-1
lib/tapfall/messages/record_message.rb
···8 super
9 end
10000011 def operations
12- @operations ||= [Operation.new(json['record'])]
13 end
0014 end
15end
···8 super
9 end
1011+ def operation
12+ @operation ||= Operation.new(json['record'])
13+ end
14+15 def operations
16+ [operation]
17 end
18+19+ alias op operation
20 end
21end