dexiecable 1.0.0 → 2.0.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b462191000153b424593099689d503a34152404f08cd33911f8db01a61d154cf
4
- data.tar.gz: 3fd86cd2c4b9cb4a73b43fc0fee7e686a91a9c4d1a1e390cc544d87f0dddbdc0
3
+ metadata.gz: 5262c05d144bc7c002152fd8da1918e87421f4ec81a060100b71c57237c152be
4
+ data.tar.gz: 339cf7b68cd9923b0b20b4a74c0caf563699be7ff8fbaf32ace71728a87fc787
5
5
  SHA512:
6
- metadata.gz: 933c9999fa8d60d04fb3571a094568f1fe78ace8f3a13de6e48dd18d71471e647a1b33c6eb49e2ec6123321933967a8479a1fb6c10906412b5a518302b141f66
7
- data.tar.gz: 13751b561bb8f7d57d05ba7639b474c15d3077262a3ec488a8f217f1d5c20be4235757172eac5fa1b5e558af50b5c97d6d253d5a04544c60c80a768f44ab3049
6
+ metadata.gz: e315b48c4d222dd5c4fb04056dded3f61d9d76584dfc7ee02d1645b6d28521120130b945cda897ca6682b7d6483232a3f6b92a3220bc417dc9fb6d8718169416
7
+ data.tar.gz: a5c155688bd21d6970842b86f28d2f9e4d901561fb5e786a59ed3447ae7b96db083d5b63e1d724b7fc8c5b7c2428661d713b00a5dc41a5c5b0f2a0f62ca568cc
data/README.md CHANGED
@@ -1,42 +1,28 @@
1
1
  # DexieCable
2
2
 
3
3
  > [!NOTE]
4
- > The current version of DexieCable is NOT a local-first solution, because it lacks the capability to automatically sync updates back to the server. For now, think of it more as an alternative to turbo streams that works well with component frameworks.
4
+ > DexieCable is NOT meant to be a local-first solution. It has no automatic capability to sync updates back to the server. For now, think of it as an alternative to Turbo Streams built with component frameworks (Vue, React, Svelte, etc) in mind.
5
5
  >
6
- > Full synchronization utilizing event streams will arrive in DexieCable 2.0.
6
+ > Full synchronization utilizing event streams will arrive in DexieCable 3.0.
7
7
 
8
- DexieCable augments ActionCable channels with a query DSL that mirrors the Dexie.js API, letting you push database mutations from the server to the client in real time. It also gives you a [`streams_via`](#streams_via--automatic-model-syncing) ActiveRecord macro for automatic change syncing.
8
+ DexieCable ships a single `DexieChannel` with a query DSL that mirrors the Dexie.js API, letting you push database mutations from the server to the client in real time. It also gives you a [`syncs_to_dexie`](#syncs_to_dexie--automatic-model-syncing) ActiveRecord macro for automatic change syncing.
9
9
 
10
- You can run any Dexie table update directly inside a channel:
11
-
12
- ```ruby
13
- class UserChannel < ApplicationCable::Channel
14
- include DexieCable
15
-
16
- def subscribed
17
- stream_for current_user
18
- recent_notifications = current_user.notifications.last(10)
19
- table("notifications").bulkAdd(recent_notifications)
20
- end
21
- end
22
- ```
23
-
24
- Or from inside a controller:
10
+ Push Dexie table updates to a client from anywhere on the server:
25
11
 
26
12
  ```ruby
27
13
  class NotificationsController < ApplicationController
28
14
  def create
29
15
  notification = current_user.notifications.create!(notification_params)
30
- UserChannel[current_user].table("notifications").add(notification)
16
+ DexieChannel[current_user].table("notifications").add(notification)
31
17
  end
32
18
  end
33
19
  ```
34
20
 
35
- An even more convenient way is to use the `streams_via` macro (more info [below](#streams_via--automatic-model-syncing))
21
+ Or sync model changes automatically with the `syncs_to_dexie` macro (more info [below](#syncs_to_dexie--automatic-model-syncing))
36
22
 
37
23
  ```ruby
38
24
  class Notification < ApplicationRecord
39
- streams_via UserChannel, to: :user
25
+ syncs_to_dexie via: :user
40
26
  end
41
27
  ```
42
28
 
@@ -50,7 +36,7 @@ Add to your `Gemfile`:
50
36
  gem "dexiecable"
51
37
  ```
52
38
 
53
- Then `bundle install`. The Railtie automatically extends `ActiveRecord::Base` with `streams_via`.
39
+ Then `bundle install`. The Railtie automatically extends `ActiveRecord::Base` with `syncs_to_dexie`.
54
40
 
55
41
  ### npm package
56
42
 
@@ -66,7 +52,9 @@ Pass your Dexie database as the first argument to `subscribe()`:
66
52
  import { subscribe } from "dexiecable";
67
53
  import { db } from "./db";
68
54
 
69
- subscribe(db, "UserChannel");
55
+ const subscription = subscribe(db);
56
+ // Stream tokens come from the server: DexieChannel.stream_token_for(target)
57
+ subscription.addStream(streamToken);
70
58
  ```
71
59
 
72
60
  A consumer is lazily created on the first `subscribe()` call. If you need to access or set the consumer explicitly, use `getConsumer()` and `setConsumer()`:
@@ -83,24 +71,69 @@ setConsumer(createConsumer("wss://example.com/cable"));
83
71
 
84
72
  ## Usage
85
73
 
86
- ### `include DexieCable` in a channel
74
+ ### DexieChannel
75
+
76
+ DexieCable ships one channel — `DexieChannel` — so you never define your own channels or include anything. Every Dexie broadcast goes through it.
77
+
78
+ Stream tokens are signed with the application secret, so a client can only subscribe to streams the server has issued for it:
87
79
 
88
80
  ```ruby
89
- class UserChannel < ApplicationCable::Channel
90
- include DexieCable
81
+ DexieChannel.stream_token_for(target)
82
+ ```
91
83
 
92
- def subscribed
93
- stream_for current_user
94
- end
84
+ For an ActiveRecord model it signs the record's GlobalID:
85
+
86
+ ```ruby
87
+ DexieChannel.stream_token_for(current_user)
88
+ # => "eyJkYXRhIjoiZGV4aWVfY2FibGU6ZGV4aWVfY2hhbm5lbDpnaWQ6Ly9hcHAvVXNlci8xIn0=--signature"
89
+ ```
90
+
91
+ Send that token to the client (render it in a view, return it from an endpoint, etc.) and add it to the subscription:
92
+
93
+ ```js
94
+ const subscription = subscribe(db);
95
+ subscription.addStream(userStream);
96
+ ```
97
+
98
+ The client now receives every mutation broadcast to `current_user`. To stop listening:
99
+
100
+ ```js
101
+ subscription.removeStream(userStream);
102
+ ```
103
+
104
+ `addStream`/`removeStream` perform `add_stream`/`remove_stream` on `DexieChannel`, which verifies the token and then `stream_from`/`stop_stream_from` the decoded identifier. `removeAllStreams()` performs `remove_all_streams`, stopping every current stream — handy on logout:
105
+
106
+ ```js
107
+ subscription.removeAllStreams();
108
+ ```
109
+
110
+ #### Public streams
111
+
112
+ For data that's public (a global feed, announcements, etc.), skip the signature. Use a string target — it's namespaced under `public:` automatically:
113
+
114
+ ```ruby
115
+ DexieChannel["feed"].table("announcements").add(announcement)
116
+
117
+ # or, on a model:
118
+ class Announcement < ApplicationRecord
119
+ syncs_to_dexie via: "feed"
95
120
  end
96
121
  ```
97
122
 
98
- This gives you:
123
+ Then subscribe by name — no token required:
99
124
 
100
- | Method | Description |
101
- |---|---|
102
- | `self.[](to)` | Returns a `ScopedChannel` bound to a recipient. `UserChannel[current_user]` |
103
- | `table(name)` | Starts a query chain. `table("messages")` |
125
+ ```js
126
+ subscription.addPublicStream("feed");
127
+ subscription.removePublicStream("feed");
128
+ ```
129
+
130
+ Public streams are namespaced under `public:`, so this path can never reach a signed (private) stream.
131
+
132
+ `DexieChannel[target]` returns a scoped channel for broadcasting to one recipient:
133
+
134
+ ```ruby
135
+ DexieChannel[current_user].table("notifications").add(notification)
136
+ ```
104
137
 
105
138
  ### Chaining Dexie operations
106
139
 
@@ -108,24 +141,24 @@ Any Dexie.js write operation triggers an immediate broadcast:
108
141
 
109
142
  ```ruby
110
143
  # Single insert
111
- UserChannel[current_user].table("messages").add(id: 1, text: "hello")
144
+ DexieChannel[current_user].table("messages").add(id: 1, text: "hello")
112
145
 
113
146
  # Bulk insert
114
- UserChannel[current_user].table("messages").bulkAdd(messages)
147
+ DexieChannel[current_user].table("messages").bulkAdd(messages)
115
148
 
116
149
  # Update (using modify)
117
- UserChannel[current_user]
150
+ DexieChannel[current_user]
118
151
  .table("messages")
119
152
  .where(:id).equals(msg.id)
120
153
  .modify(read: true)
121
154
 
122
155
  # Update (using update)
123
- UserChannel[current_user]
156
+ DexieChannel[current_user]
124
157
  .table("messages")
125
158
  .update(msg.id, text: "updated text")
126
159
 
127
160
  # Delete
128
- UserChannel[current_user]
161
+ DexieChannel[current_user]
129
162
  .table("messages")
130
163
  .where(:room_id).equals(room.id)
131
164
  .delete()
@@ -133,25 +166,32 @@ UserChannel[current_user]
133
166
 
134
167
  The full query chain is serialized as JSON and sent over ActionCable. The JS client replays every method call against the local Dexie database in order.
135
168
 
136
- ### `streams_via` — automatic model streaming
169
+ ### `syncs_to_dexie` — automatic model streaming
137
170
 
138
- Add to any ActiveRecord model. Just provide the channel class and, optionally, the broadcast target.
171
+ Add to any ActiveRecord model. Optionally provide the broadcast target.
139
172
 
140
173
  ```ruby
141
174
  class Message < ApplicationRecord
142
- # Calls send(:receiver), then broadcasts: UserChannel.broadcast_to(receiver, ...)
143
- streams_via UserChannel, to: :receiver
175
+ # Calls send(:receiver), then broadcasts: DexieChannel.broadcast_to(receiver, ...)
176
+ syncs_to_dexie via: :receiver
144
177
 
145
- # String used directly: RoomChannel.broadcast_to("public", ...)
146
- streams_via RoomChannel, to: "public"
178
+ # String = public stream (subscribe via addPublicStream("public"))
179
+ syncs_to_dexie via: "public"
147
180
 
148
181
  # Procs are also supported. If an array is returned, multiple broadcasts are made
149
- # conversation.users.each { |u| UserChannel.broadcast_to(u, ...) }
150
- streams_via UserChannel, to: -> { conversation.users }
182
+ # conversation.users.each { |u| DexieChannel.broadcast_to(u, ...) }
183
+ syncs_to_dexie via: -> { conversation.users }
151
184
  end
152
185
  ```
153
186
 
154
- Internally, `streams_via` sets up the following ActiveRecord callbacks:
187
+ Broadcasts go out over `DexieChannel`, the channel DexieCable provides. On the client, subscribe to it and add the stream token returned by `DexieChannel.stream_token_for(target)`:
188
+
189
+ ```js
190
+ const subscription = subscribe(db);
191
+ subscription.addStream(streamIdentifier);
192
+ ```
193
+
194
+ Internally, `syncs_to_dexie` sets up the following ActiveRecord callbacks:
155
195
 
156
196
  | Event | Action |
157
197
  |---|---|
@@ -163,23 +203,21 @@ Internally, `streams_via` sets up the following ActiveRecord callbacks:
163
203
 
164
204
  | Option | Default | Description |
165
205
  |---|---|---|
166
- | *(first argument)* | *(required)* | A DexieCable channel class |
167
- | `to:` | the record itself | The stream target passed to `broadcast_to`. Symbol → calls `send`. String → used as-is. Proc → evaluated in record context. Returns a single recipient or collection. |
206
+ | `via:` | the record itself | The stream target. Symbol → calls `send` (a record, signed). String public stream name. Proc → evaluated in record context. Returns a single recipient or collection. |
168
207
  | `table:` | model's `table_name` | Override the Dexie table name. A Proc is evaluated in the record's context. |
169
208
  | `only:` | `[:create, :update, :destroy]` | Limit which events trigger a sync |
170
209
  | `with:` | `:as_json_for_dexie` | Method name (Symbol) or Proc for serializing records |
171
210
  | `if:` | *(none)* | Symbol (method name) or Proc — only sync when it returns truthy |
172
211
  | `unless:` | *(none)* | Symbol (method name) or Proc — skip sync when it returns truthy |
173
212
 
174
- You can combine multiple `streams_via` declarations, each with different conditions:
213
+ You can combine multiple `syncs_to_dexie` declarations, each with different conditions:
175
214
 
176
215
  ```ruby
177
216
  class Message < ApplicationRecord
178
- streams_via UserChannel, to: -> { sender },
179
- if: :published?
217
+ syncs_to_dexie via: -> { sender },
218
+ if: :published?
180
219
 
181
- streams_via AdminChannel,
182
- unless: -> { draft? }
220
+ syncs_to_dexie unless: -> { draft? }
183
221
  end
184
222
  ```
185
223
 
@@ -190,23 +228,22 @@ Override `as_json_for_dexie` in your model, or use the `with` option to specify
190
228
  ```ruby
191
229
  class Message < ApplicationRecord
192
230
  # Using the default as_json_for_dexie override:
193
- streams_via UserChannel, to: :sender
231
+ syncs_to_dexie via: :sender
194
232
 
195
233
  def as_json_for_dexie
196
234
  super.merge(room_name: room.name)
197
235
  end
198
236
 
199
237
  # Or use a custom serializer method:
200
- streams_via AdminChannel, to: :admin,
201
- with: :admin_payload
238
+ syncs_to_dexie via: :admin,
239
+ with: :admin_payload
202
240
 
203
241
  def admin_payload
204
242
  attributes.slice("id", "body", "flagged")
205
243
  end
206
244
 
207
245
  # Or a Proc:
208
- streams_via PublicChannel,
209
- with: -> { { id: id, summary: body.truncate(100) } }
246
+ syncs_to_dexie with: -> { { id: id, summary: body.truncate(100) } }
210
247
  end
211
248
  ```
212
249
 
@@ -247,60 +284,6 @@ The JS side replays it as:
247
284
  dexie.messages.where("room_id").equals(5).add({ id: 1, text: "hello" })
248
285
  ```
249
286
 
250
- ## Recipies
251
-
252
- ### Use sequence IDs to avoid data loss
253
-
254
- A common pattern to avoid data loss during transient disconnections is using sequence IDs to bridge the offline gap and detect gaps in transmitted records. When a connection drops, updates continue on the server. Sending the client’s latest known sequence ID upon reconnect allows the backend to query and stream only the records missed while offline.
255
-
256
- To enable this, DexieCable ships its own version of the ActionCable client with one key
257
- extension: **channel params can be functions**. When a param value is a
258
- function, it is called and awaited at subscribe time — use this to submit the latest known sequence ID on connection:
259
-
260
- ```js
261
- import { subscribe } from "dexiecable";
262
- import { db, getLastSeqId } from './database';
263
-
264
- const roomId = 123;
265
-
266
- subscribe(db, {
267
- channel: "RoomChannel",
268
- room_id: roomId,
269
- seq_id: () => getLastSeqId(roomId) // evaluated fresh on each reconnect
270
- });
271
- ```
272
-
273
- Send missed messages on reconnection:
274
-
275
- ```ruby
276
- class RoomChannel < ApplicationChannel:Base
277
- def subscribed
278
- stream_from "room:#{params[:room_id]}"
279
- missed_messages = room.messages.where("seq_id > ?", params[:seq_id])
280
- table("messages").bulkAdd(missed_messages)
281
- end
282
- end
283
- ```
284
-
285
- To add Sequence IDs, you might want to have look at the [Sequenced](https://github.com/derrickreimer/sequenced). Another option is to use [AnyCable](https://docs.anycable.io/rails/getting_started) since it guarantees deliveries of ActionCable messages.
286
-
287
- ### Multi-user environments
288
-
289
- In multi-user or multi-tenant applications, you can isolate records by binding different subscription channels to separate Dexie database instances. This prevents local data leaks between user accounts and keeps private user data separate from public or shared feeds.
290
-
291
- ```js
292
-
293
- import Dexie from 'dexie'
294
- import { subscribe } from 'dexiecable'
295
-
296
- const userDB = new Dexie("user_"+userId)
297
- const sharedDB = new Dexie("shared")
298
-
299
- subscribe(userDB, 'UserChannel')
300
- subscribe(sharedDB, 'PublicChannel')
301
-
302
- ```
303
-
304
287
  ## License
305
288
 
306
289
  MIT
@@ -5,25 +5,21 @@ module DexieCable
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  class_methods do
8
- # Declares that this model syncs changes to Dexie (IndexedDB) via a
9
- # DexieCable channel.
8
+ # Declares that this model syncs changes to Dexie (IndexedDB) via
9
+ # DexieChannel.
10
10
  #
11
11
  # class Message < ApplicationRecord
12
- # streams_via UserChannel, to: :sender
13
- # streams_via UserChannel, to: "global_feed"
14
- # streams_via UserChannel, to: -> { conversation.users }
15
- # streams_via PublicChannel
12
+ # syncs_to_dexie via: :sender
13
+ # syncs_to_dexie via: "global_feed"
14
+ # syncs_to_dexie via: -> { conversation.users }
15
+ # syncs_to_dexie
16
16
  # end
17
17
  #
18
- # @param via [Class] A DexieCable channel class, passed as the
19
- # first positional argument. Each recipient is
20
- # mapped through +via[to]+ to produce scoped
21
- # channels.
22
- # @param to [Proc, Symbol, String] A Proc evaluated in record
18
+ # @param via [Proc, Symbol, String] A Proc evaluated in record
23
19
  # context, a Symbol to call via +send+, or a String
24
- # used directly as the stream name for +broadcast_to+.
25
- # Must return a single recipient or collection of
26
- # recipients. Defaults to the record itself.
20
+ # naming a public stream. Must return a single
21
+ # recipient or collection of recipients. Defaults to
22
+ # the record itself.
27
23
  # @param table [String, Symbol, Proc] Override the Dexie table name
28
24
  # (defaults to the model's table_name). A Proc is
29
25
  # evaluated in the record's context.
@@ -35,19 +31,19 @@ module DexieCable
35
31
  # returns truthy (evaluated in the record's context).
36
32
  # @param unless [Symbol, Proc] Skip sync if the given method or proc
37
33
  # returns truthy (evaluated in the record's context).
38
- def streams_via(via, to: nil, table: nil, only: nil, with: nil, **options)
34
+ def syncs_to_dexie(via: nil, table: nil, only: nil, with: nil, **options)
39
35
  events = Array(only || %i[create update destroy])
40
36
  conditions = options.slice(:if, :unless)
41
37
  serializer = with || :as_json_for_dexie
42
38
 
43
39
  @dexie_sync_configs ||= []
44
- @dexie_sync_configs << { via: via, to: to, table: table, only: events, with: serializer, **conditions }
40
+ @dexie_sync_configs << { via: via, table: table, only: events, with: serializer, **conditions }
45
41
 
46
42
  if events.include?(:destroy)
47
43
  before_destroy :dexie_sync_before_destroy
48
44
 
49
45
  after_commit on: :destroy, **conditions do
50
- resolve_channels(via, to).each do |channel|
46
+ resolve_channels(via).each do |channel|
51
47
  next unless channel
52
48
  channel.table(resolve_table(table)).delete(dexie_destroy_id)
53
49
  end
@@ -56,7 +52,7 @@ module DexieCable
56
52
 
57
53
  if events.include?(:create)
58
54
  after_commit on: :create, **conditions do
59
- resolve_channels(via, to).each do |channel|
55
+ resolve_channels(via).each do |channel|
60
56
  next unless channel
61
57
  channel.table(resolve_table(table)).add(resolve(serializer))
62
58
  end
@@ -65,7 +61,7 @@ module DexieCable
65
61
 
66
62
  if events.include?(:update)
67
63
  after_commit on: :update, **conditions do
68
- resolve_channels(via, to).each do |channel|
64
+ resolve_channels(via).each do |channel|
69
65
  next unless channel
70
66
 
71
67
  changes = resolve(serializer).slice(*saved_changes.keys)
@@ -78,9 +74,9 @@ module DexieCable
78
74
 
79
75
  private
80
76
 
81
- def resolve_channels(via, to = nil)
82
- recipients = to ? resolve(to) : self
83
- Array(recipients).map { |r| via[r] }
77
+ def resolve_channels(via = nil)
78
+ recipients = via ? resolve(via) : self
79
+ Array(recipients).map { |r| DexieChannel[r] }
84
80
  end
85
81
 
86
82
  def resolve(val)
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexieCable
4
+ # The single channel through which all Dexie transfer happens.
5
+ #
6
+ # Broadcasts are scoped to a recipient with +DexieChannel[recipient]+ or
7
+ # +DexieChannel.broadcast_to+. String recipients are public stream names;
8
+ # any other recipient (e.g. a record) targets a private, signed stream.
9
+ #
10
+ # # private (signed)
11
+ # subscription.addStream(DexieChannel.stream_token_for(current_user))
12
+ #
13
+ # # public (no signature, namespaced under "public:")
14
+ # subscription.addPublicStream("feed")
15
+ #
16
+ class DexieChannel < ActionCable::Channel::Base
17
+ PUBLIC_STREAM_PREFIX = "public:"
18
+
19
+ public :transmit
20
+
21
+ # Open a scoped channel for broadcasting to a specific recipient.
22
+ #
23
+ # A String recipient is a public stream name (namespaced under
24
+ # +public:+); any other recipient targets that recipient's own stream.
25
+ #
26
+ # DexieChannel[current_user].table("notifications").add(notification)
27
+ # DexieChannel["feed"].table("announcements").add(announcement)
28
+ #
29
+ def self.[](recipient)
30
+ target = recipient.is_a?(String) ? "#{PUBLIC_STREAM_PREFIX}#{recipient}" : recipient
31
+ ScopedChannel.new(self, target)
32
+ end
33
+
34
+ # Build a query against a Dexie table, transmitted to all subscribers
35
+ # of this channel.
36
+ #
37
+ # table("messages").where(:room_id).equals(room.id).add(message)
38
+ #
39
+ def table(name)
40
+ Query.new(self, name)
41
+ end
42
+
43
+ # Returns a signed token for the stream identifier of +target+ (private
44
+ # record-based streams). Send it to the client, which passes it to
45
+ # +subscription.addStream+.
46
+ def self.stream_token_for(target)
47
+ verifier.generate(broadcasting_for(target))
48
+ end
49
+
50
+ def self.verifier
51
+ @verifier ||= Rails.application.message_verifier("dexiecable:streams")
52
+ end
53
+
54
+ def subscribed
55
+ # Streams are added dynamically via +add_stream+.
56
+ end
57
+
58
+ def add_stream(data)
59
+ stream = verified_stream(data["stream"])
60
+ stream_from stream if stream
61
+ end
62
+
63
+ def remove_stream(data)
64
+ stream = verified_stream(data["stream"])
65
+ stop_stream_from stream if stream
66
+ end
67
+
68
+ def remove_all_streams(_data)
69
+ stop_all_streams
70
+ end
71
+
72
+ def add_public_stream(data)
73
+ name = data["stream"].to_s
74
+ stream_from public_stream_name(name) if name.present?
75
+ end
76
+
77
+ def remove_public_stream(data)
78
+ name = data["stream"].to_s
79
+ stop_stream_from public_stream_name(name) if name.present?
80
+ end
81
+
82
+ private
83
+
84
+ def public_stream_name(name)
85
+ self.class.broadcasting_for("#{PUBLIC_STREAM_PREFIX}#{name}")
86
+ end
87
+
88
+ def verified_stream(token)
89
+ return unless token.present?
90
+
91
+ self.class.verifier.verify(token)
92
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
93
+ nil
94
+ end
95
+ end
96
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DexieCable
4
- VERSION = "1.0.0"
4
+ VERSION = "2.0.0.alpha1"
5
5
  end
data/lib/dexiecable.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "dexiecable/version"
4
- require_relative "dexiecable/concern"
5
4
  require_relative "dexiecable/scoped_channel"
6
5
  require_relative "dexiecable/query"
7
6
  require_relative "dexiecable/active_record_ext"
7
+ require_relative "dexiecable/dexie_channel" if defined?(ActionCable::Channel::Base)
8
8
  require_relative "dexiecable/railtie" if defined?(Rails::Railtie)
9
9
 
10
10
  module DexieCable
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dexiecable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Buhrmester
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: '7.0'
40
40
  description: DexieCable augments ActionCable channels with a query DSL that mirrors
41
41
  the Dexie.js API, letting you push database mutations from the server to the client
42
- in real time. Includes an ActiveRecord macro (streams_via) for automatic change
42
+ in real time. Includes an ActiveRecord macro (syncs_to_dexie) for automatic change
43
43
  syncing.
44
44
  email:
45
45
  - stefan@buhrmi.de
@@ -50,7 +50,7 @@ files:
50
50
  - README.md
51
51
  - lib/dexiecable.rb
52
52
  - lib/dexiecable/active_record_ext.rb
53
- - lib/dexiecable/concern.rb
53
+ - lib/dexiecable/dexie_channel.rb
54
54
  - lib/dexiecable/query.rb
55
55
  - lib/dexiecable/railtie.rb
56
56
  - lib/dexiecable/scoped_channel.rb
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DexieCable
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- public :transmit
8
-
9
- # Open a scoped channel for broadcasting to a specific recipient.
10
- #
11
- # UserChannel[current_user].table("notifications").add(notification)
12
- #
13
- def self.[](recipient)
14
- ScopedChannel.new(self, recipient)
15
- end
16
-
17
- # Build a query against a Dexie table, transmitted to all subscribers
18
- # of this channel.
19
- #
20
- # table("messages").where(:room_id).equals(room.id).add(message)
21
- #
22
- def table(name)
23
- Query.new(self, name)
24
- end
25
- end
26
- end