diff --git a/lib/mix/tasks/phoenix_sync.install.ex b/lib/mix/tasks/phoenix_sync.install.ex index 990656d..77bd394 100644 --- a/lib/mix/tasks/phoenix_sync.install.ex +++ b/lib/mix/tasks/phoenix_sync.install.ex @@ -300,7 +300,7 @@ if Code.ensure_loaded?(Igniter) do defp required_electric_version do Phoenix.Sync.MixProject.project() |> Keyword.fetch!(:deps) - |> Enum.find(&match?({:electric, _, _}, &1)) + |> Enum.find(&(elem(&1, 0) == :electric)) |> elem(1) end diff --git a/lib/phoenix/sync/electric.ex b/lib/phoenix/sync/electric.ex index 40693c2..87a2b06 100644 --- a/lib/phoenix/sync/electric.ex +++ b/lib/phoenix/sync/electric.ex @@ -640,8 +640,9 @@ defmodule Phoenix.Sync.Electric do end end -if Code.ensure_loaded?(Electric.Shapes.Api) && - Code.ensure_loaded?(Phoenix.Sync.Electric.ApiAdapter) do +if Code.ensure_loaded?(Electric.Shapes.Api) do + Code.ensure_loaded(Phoenix.Sync.Electric.ApiAdapter) + defimpl Phoenix.Sync.Adapter.PlugApi, for: Electric.Shapes.Api do alias Electric.Shapes @@ -701,7 +702,7 @@ if Code.ensure_loaded?(Electric.Shapes.Api) && end end - def send_response(%ApiAdapter{}, conn, {request, response}) do + def send_response(_api, conn, {request, response}) do conn |> content_type() |> Plug.Conn.assign(:request, request) diff --git a/lib/phoenix/sync/plug/cors.ex b/lib/phoenix/sync/plug/cors.ex index cc126f2..c9e7762 100644 --- a/lib/phoenix/sync/plug/cors.ex +++ b/lib/phoenix/sync/plug/cors.ex @@ -16,7 +16,8 @@ defmodule Phoenix.Sync.Plug.CORS do "electric-offset", "electric-schema", "electric-up-to-date", - "electric-internal-known-error" + "electric-internal-known-error", + "retry-after" ] @expose_headers ["transfer-encoding" | @electric_headers] diff --git a/lib/phoenix/sync/sandbox.ex b/lib/phoenix/sync/sandbox.ex index d80c1e3..652f56f 100644 --- a/lib/phoenix/sync/sandbox.ex +++ b/lib/phoenix/sync/sandbox.ex @@ -259,7 +259,11 @@ if Phoenix.Sync.sandbox_enabled?() do # mark the stack as ready Electric.StatusMonitor.mark_pg_lock_acquired(stack_id, owner) Electric.StatusMonitor.mark_replication_client_ready(stack_id, owner) - Electric.StatusMonitor.mark_connection_pool_ready(stack_id, owner) + Electric.StatusMonitor.mark_connection_pool_ready(stack_id, :admin, owner) + Electric.StatusMonitor.mark_connection_pool_ready(stack_id, :snapshot, owner) + Electric.StatusMonitor.mark_integrety_checks_passed(stack_id, owner) + Electric.StatusMonitor.mark_shape_log_collector_ready(stack_id, owner) + Electric.StatusMonitor.mark_supervisor_processes_ready(stack_id, owner) api_config = Sandbox.Stack.config(stack_id, repo) api = Electric.Application.api(api_config) @@ -292,7 +296,7 @@ if Phoenix.Sync.sandbox_enabled?() do defp generate_stack_id(opts) do tags = Keyword.get(opts, :tags, %{}) # with parameterised tests the same file:line can be running simultaneously - uid = System.unique_integer() |> to_string() + uid = System.unique_integer([:monotonic]) |> to_string() suffix = case Map.fetch(tags, :line) do diff --git a/lib/phoenix/sync/sandbox/expiry_manager.ex b/lib/phoenix/sync/sandbox/expiry_manager.ex new file mode 100644 index 0000000..6989338 --- /dev/null +++ b/lib/phoenix/sync/sandbox/expiry_manager.ex @@ -0,0 +1,11 @@ +defmodule Phoenix.Sync.Sandbox.ExpiryManager do + use GenServer + + def start_link(args) do + GenServer.start_link(__MODULE__, args, name: Electric.ShapeCache.ExpiryManager.name(args)) + end + + def init(_) do + {:ok, []} + end +end diff --git a/lib/phoenix/sync/sandbox/inspector.ex b/lib/phoenix/sync/sandbox/inspector.ex index 9e33a66..ea6ab6a 100644 --- a/lib/phoenix/sync/sandbox/inspector.ex +++ b/lib/phoenix/sync/sandbox/inspector.ex @@ -34,6 +34,13 @@ if Phoenix.Sync.sandbox_enabled?() do @impl Electric.Postgres.Inspector def list_relations_with_stale_cache(_), do: {:ok, []} + @impl Electric.Postgres.Inspector + def load_supported_features(stack_id) do + with {:ok, pid} <- validate_stack_alive(stack_id) do + GenServer.call(pid, :load_supported_features) + end + end + def start_link(args) do GenServer.start_link(__MODULE__, args, name: name(args[:stack_id])) end @@ -57,7 +64,15 @@ if Phoenix.Sync.sandbox_enabled?() do {:ok, stack_id} = Keyword.fetch(args, :stack_id) {:ok, repo} = Keyword.fetch(args, :repo) - {:ok, %{repo: repo, stack_id: stack_id, relations: %{}, columns: %{}, oids: %{}}} + {:ok, + %{ + repo: repo, + stack_id: stack_id, + relations: %{}, + columns: %{}, + oids: %{}, + supported_features: %{} + }} end @impl GenServer @@ -88,6 +103,15 @@ if Phoenix.Sync.sandbox_enabled?() do {:reply, result, state} end + def handle_call(:load_supported_features, _from, state) do + {result, state} = + fetch_lazy(state, :supported_features, nil, fn -> + Electric.Postgres.Inspector.DirectInspector.load_supported_features(pool(state)) + end) + + {:reply, result, state} + end + defp pool(state) do %{pid: pool} = Ecto.Adapter.lookup_meta(state.repo.get_dynamic_repo()) pool diff --git a/lib/phoenix/sync/sandbox/producer.ex b/lib/phoenix/sync/sandbox/producer.ex index a7f3231..b97dbc1 100644 --- a/lib/phoenix/sync/sandbox/producer.ex +++ b/lib/phoenix/sync/sandbox/producer.ex @@ -3,7 +3,8 @@ if Phoenix.Sync.sandbox_enabled?() do @moduledoc false alias Electric.Replication.Changes.{ - Transaction, + Begin, + Commit, NewRecord, UpdatedRecord, DeletedRecord, @@ -50,6 +51,12 @@ if Phoenix.Sync.sandbox_enabled?() do def init(stack_id) do state = %{txid: 10000, stack_id: stack_id} + + Electric.LsnTracker.set_last_processed_lsn( + stack_id, + Electric.Postgres.Lsn.from_integer(0) + ) + {:ok, state} end @@ -62,7 +69,7 @@ if Phoenix.Sync.sandbox_enabled?() do :ok = txid |> transaction(msgs) - |> ShapeLogCollector.store_transaction(ShapeLogCollector.name(stack_id)) + |> ShapeLogCollector.handle_operations(ShapeLogCollector.name(stack_id)) {:noreply, %{state | txid: next_txid}} end @@ -73,21 +80,20 @@ if Phoenix.Sync.sandbox_enabled?() do :ok = state.txid |> transaction(changes) - |> ShapeLogCollector.store_transaction(ShapeLogCollector.name(state.stack_id)) + |> ShapeLogCollector.handle_operations(ShapeLogCollector.name(state.stack_id)) {:noreply, %{state | txid: state.txid + 100}} end defp transaction(txid, changes) do - %Transaction{ - xid: txid, - lsn: Electric.Postgres.Lsn.from_integer(txid), - last_log_offset: Enum.at(changes, -1) |> Map.fetch!(:log_offset), - changes: changes, - num_changes: length(changes), - commit_timestamp: DateTime.utc_now(), - affected_relations: Enum.into(changes, MapSet.new(), & &1.relation) - } + [%Begin{xid: txid} | changes] ++ + [ + %Commit{ + lsn: Electric.Postgres.Lsn.from_integer(txid), + transaction_size: 100, + commit_timestamp: DateTime.utc_now() + } + ] end defp msg_from_change({{:insert, schema_meta, values}, i}, lsn, txid) do diff --git a/lib/phoenix/sync/sandbox/publication_manager.ex b/lib/phoenix/sync/sandbox/publication_manager.ex index 97ed390..6fb729c 100644 --- a/lib/phoenix/sync/sandbox/publication_manager.ex +++ b/lib/phoenix/sync/sandbox/publication_manager.ex @@ -4,57 +4,31 @@ if Phoenix.Sync.sandbox_enabled?() do use GenServer - @behaviour Electric.Replication.PublicationManager - - def start_link(_) do - :ignore - end - - def init(_arg) do - :ignore - end - - def name(stack_id) when is_binary(stack_id) do - Phoenix.Sync.Sandbox.name({__MODULE__, stack_id}) - end - - def name(opts) when is_list(opts) do - opts - |> Keyword.fetch!(:stack_id) - |> name() + def start_link(args) do + GenServer.start_link(__MODULE__, args, name: name(args)) end - def recover_shape(_shape_handle, _shape, _opts) do - :ok + def name(stack_ref) do + Electric.Replication.PublicationManager.name(stack_ref) end - def recover_shape(_shape, _opts) do - :ok + def init(opts) do + {:ok, opts} end - def add_shape(_shape_handle, _shape, opts) do - snapshotter = self() - {:ok, owner} = Keyword.fetch(opts, :owner) - {:ok, repo} = Keyword.fetch(opts, :repo) + # intercept the snapshotter process's add_shape call to add it to the allow + # list for the sandbox repo + def handle_call({:add_shape, _shape_handle, _pub_filter}, {snapshotter, _ref}, state) do + {:ok, owner} = Keyword.fetch(state, :owner) + {:ok, repo} = Keyword.fetch(state, :repo) Ecto.Adapters.SQL.Sandbox.allow(repo, owner, snapshotter) - :ok - end - - def add_shape(_shape, _opts) do - :ok - end - - def remove_shape(_shape_handle, _shape, _opts) do - :ok - end - def remove_shape(_shape, _opts) do - :ok + {:reply, :ok, state} end - def refresh_publication(_opts) do - :ok + def handle_call(_msg, _from, state) do + {:reply, :ok, state} end end end diff --git a/lib/phoenix/sync/sandbox/stack.ex b/lib/phoenix/sync/sandbox/stack.ex index e5be0f6..6348280 100644 --- a/lib/phoenix/sync/sandbox/stack.ex +++ b/lib/phoenix/sync/sandbox/stack.ex @@ -6,6 +6,8 @@ if Phoenix.Sync.sandbox_enabled?() do alias Phoenix.Sync.Sandbox + @json Phoenix.Sync.json_library() + def child_spec(opts) do {:ok, stack_id} = Keyword.fetch(opts, :stack_id) {:ok, repo} = Keyword.fetch(opts, :repo) @@ -27,43 +29,53 @@ if Phoenix.Sync.sandbox_enabled?() do Supervisor.start_link(__MODULE__, {stack_id, repo, owner}, name: name(stack_id)) end - alias Electric.Shapes.Querying alias Electric.ShapeCache.Storage + alias Electric.Shapes.Consumer.Snapshotter def snapshot_query( - parent, + task_parent, + consumer, shape_handle, shape, - db_pool, - storage, - stack_id, - chunk_bytes_threshold + %{storage: storage, stack_id: stack_id}, + sandbox_pool ) do Postgrex.transaction( - db_pool, + sandbox_pool, fn conn -> - GenServer.cast(parent, {:pg_snapshot_known, shape_handle, {1000, 1100, []}}) + xmin = 1000 + xmax = 1100 + + send(task_parent, {:ready_to_stream, self(), System.monotonic_time(:millisecond)}) + + GenServer.cast(consumer, {:pg_snapshot_known, shape_handle, {xmin, xmax, []}}) # Enforce display settings *before* querying initial data to maintain consistent # formatting between snapshot and live log entries. Enum.each(Electric.Postgres.display_settings(), &Postgrex.query!(conn, &1, [])) + # xmin/xmax/xip_list are uint64, so we need to convert them to strings for JS not to mangle them + finishing_control_message = + @json.encode!(%{ + headers: %{ + control: "snapshot-end", + xmin: to_string(xmin), + xmax: to_string(xmax), + xip_list: [] + } + }) + stream = - Querying.stream_initial_data(conn, stack_id, shape, chunk_bytes_threshold) - |> Stream.transform( - fn -> false end, - fn item, acc -> - if not acc, do: GenServer.cast(parent, {:snapshot_started, shape_handle}) - {[item], true} - end, - fn acc -> - if not acc, do: GenServer.cast(parent, {:snapshot_started, shape_handle}) - acc - end + Snapshotter.stream_initial_data( + task_parent, + consumer, + conn, + stack_id, + shape, + shape_handle ) + |> Stream.concat([finishing_control_message]) - # could pass the shape and then make_new_snapshot! can pass it to row_to_snapshot_item - # that way it has the relation, but it is still missing the pk_cols Storage.make_new_snapshot!(stream, storage) end, timeout: :infinity @@ -79,28 +91,20 @@ if Phoenix.Sync.sandbox_enabled?() do %{pid: pool} = Ecto.Adapter.lookup_meta(repo.get_dynamic_repo()) - registry = :"#{__MODULE__}.Registry-#{stack_id}" + registry = Electric.StackSupervisor.registry_name(stack_id) storage = { Electric.ShapeCache.InMemoryStorage, - %{stack_id: stack_id, table_base_name: :"#{stack_id}"} + [stack_id: stack_id, table_base_name: :"#{stack_id}"] } [ - purge_all_shapes?: false, stack_id: stack_id, storage: storage, - shape_status: - {Electric.ShapeCache.ShapeStatus, - Electric.ShapeCache.ShapeStatus.opts( - shape_meta_table: Electric.ShapeCache.ShapeStatus.shape_meta_table(stack_id), - storage: storage - )}, inspector: inspector, publication_manager: publication_manager_spec, chunk_bytes_threshold: 10_485_760, db_pool: pool, - create_snapshot_fn: &snapshot_query/7, log_producer: Electric.Replication.ShapeLogCollector.name(stack_id), consumer_supervisor: Electric.Shapes.DynamicConsumerSupervisor.name(stack_id), registry: registry, @@ -110,47 +114,49 @@ if Phoenix.Sync.sandbox_enabled?() do def init({stack_id, repo, owner}) do config = config(stack_id, repo, owner) - shape_cache_spec = {Electric.ShapeCache, config} + shape_cache_spec = {Electric.ShapeCache, stack_id: stack_id} persistent_kv = Electric.PersistentKV.Memory.new!() - shape_status_owner_spec = - {Electric.ShapeCache.ShapeStatusOwner, - [stack_id: stack_id, shape_status: config[:shape_status]]} + storage = Storage.shared_opts(config[:storage]) - consumer_supervisor_spec = {Electric.Shapes.DynamicConsumerSupervisor, [stack_id: stack_id]} + create_snapshot_fn = fn task_parent, consumer, shape_handle, shape, ctx -> + snapshot_query(task_parent, consumer, shape_handle, shape, ctx, config[:db_pool]) + end children = [ + {Electric.ProcessRegistry, partitions: 1, stack_id: stack_id}, {Registry, keys: :duplicate, name: config[:registry]}, - {Electric.ProcessRegistry, stack_id: stack_id}, - {Electric.StatusMonitor, stack_id}, - {Electric.Shapes.Monitor, + {Electric.StackConfig, stack_id: stack_id, - storage: config[:storage], - shape_status: config[:shape_status], - publication_manager: config[:publication_manager]}, - # TODO: start an electric stack, decoupled from the db connection - # with in memory storage, a mock publication_manager and inspector + seed_config: [ + inspector: config[:inspector], + create_snapshot_fn: create_snapshot_fn + ]}, + Storage.stack_child_spec(storage), + {Electric.ShapeCache.ShapeStatusOwner, stack_id: stack_id, storage: storage}, + {Electric.StatusMonitor, stack_id: stack_id}, + {Sandbox.Inspector, stack_id: stack_id, repo: repo}, + {DynamicSupervisor, + name: Phoenix.Sync.Sandbox.Fetch.name(stack_id), strategy: :one_for_one}, Supervisor.child_spec( { - Electric.Replication.Supervisor, + Electric.Shapes.Supervisor, stack_id: stack_id, - shape_status_owner: shape_status_owner_spec, + consumer_supervisor: {Electric.Shapes.DynamicConsumerSupervisor, stack_id: stack_id}, + shape_cleaner: + {Electric.ShapeCache.ShapeCleaner.CleanupTaskSupervisor, stack_id: stack_id}, shape_cache: shape_cache_spec, publication_manager: config[:publication_manager], - consumer_supervisor: consumer_supervisor_spec, log_collector: { Electric.Replication.ShapeLogCollector, stack_id: stack_id, inspector: config[:inspector], persistent_kv: persistent_kv }, schema_reconciler: {Phoenix.Sync.Sandbox.SchemaReconciler, stack_id}, - stack_events_registry: config[:registry] + expiry_manager: {Phoenix.Sync.Sandbox.ExpiryManager, stack_id: stack_id} }, restart: :temporary ), - {Sandbox.Inspector, stack_id: stack_id, repo: repo}, - {Sandbox.Producer, stack_id: stack_id}, - {DynamicSupervisor, - name: Phoenix.Sync.Sandbox.Fetch.name(stack_id), strategy: :one_for_one} + {Sandbox.Producer, stack_id: stack_id} ] Supervisor.init(children, strategy: :one_for_one) diff --git a/mix.exs b/mix.exs index 8060362..870ed4e 100644 --- a/mix.exs +++ b/mix.exs @@ -3,7 +3,8 @@ defmodule Phoenix.Sync.MixProject do # Remember to update the README when you change the version @version "0.6.1" - @electric_version ">= 1.1.9 and <= 1.1.10" + # @electric_version ">= 1.1.9 and <= 1.1.10" + @electric_version "~> 1.2.6" def project do [ @@ -45,8 +46,9 @@ defmodule Phoenix.Sync.MixProject do {:plug, "~> 1.0"}, {:jason, "~> 1.0"}, {:ecto_sql, "~> 3.10", optional: true}, - {:electric, @electric_version, optional: true}, - {:electric_client, "~> 0.7.2"}, + # {:electric, @electric_version, optional: true}, + {:electric, path: "../electric-main/packages/sync-service", override: true, optional: true}, + {:electric_client, "~> 0.8.0-beta-1"}, {:igniter, "~> 0.6", optional: true} ] ++ deps_for_env(Mix.env()) ++ json_deps() end diff --git a/mix.lock b/mix.lock index 3be4935..bd273be 100644 --- a/mix.lock +++ b/mix.lock @@ -12,10 +12,10 @@ "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "dotenvy": {:hex, :dotenvy, "1.1.0", "316aee89c11a4ec8be3d74a69d17d17ea2e21e633e0cac9f155cf420e237ccb4", [:mix], [], "hexpm", "0519bda67fdfa1c22279c2654b2f292485f0caae7360fe29205f74f28a93df18"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, - "ecto": {:hex, :ecto, "3.13.3", "6a983f0917f8bdc7a89e96f2bf013f220503a0da5d8623224ba987515b3f0d80", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1927db768f53a88843ff25b6ba7946599a8ca8a055f69ad8058a1432a399af94"}, + "ecto": {:hex, :ecto, "3.13.5", "9d4a69700183f33bf97208294768e561f5c7f1ecf417e0fa1006e4a91713a834", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "df9efebf70cf94142739ba357499661ef5dbb559ef902b68ea1f3c1fabce36de"}, "ecto_sql": {:hex, :ecto_sql, "3.13.2", "a07d2461d84107b3d037097c822ffdd36ed69d1cf7c0f70e12a3d1decf04e2e1", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "539274ab0ecf1a0078a6a72ef3465629e4d6018a3028095dc90f60a19c371717"}, - "electric": {:hex, :electric, "1.1.10", "db6a4b714d711b754aff68b456bd4065c83494277cce2143dff9a9b39273c463", [:mix], [{:backoff, "~> 1.1", [hex: :backoff, repo: "hexpm", optional: false]}, {:bandit, "~> 1.6", [hex: :bandit, repo: "hexpm", optional: false]}, {:dotenvy, "~> 1.1", [hex: :dotenvy, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:electric_cubdb, "~> 2.0", [hex: :electric_cubdb, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.5", [hex: :opentelemetry, repo: "hexpm", optional: true]}, {:opentelemetry_exporter, "~> 1.8", [hex: :opentelemetry_exporter, repo: "hexpm", optional: true]}, {:opentelemetry_semantic_conventions, "~> 1.27", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}, {:opentelemetry_telemetry, "~> 1.1", [hex: :opentelemetry_telemetry, repo: "hexpm", optional: false]}, {:otel_metric_exporter, "~> 0.3.11", [hex: :otel_metric_exporter, repo: "hexpm", optional: true]}, {:pg_query_ex, "0.9.0", [hex: :pg_query_ex, repo: "hexpm", optional: false]}, {:plug, "~> 1.17", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.20", [hex: :postgrex, repo: "hexpm", optional: false]}, {:remote_ip, "~> 1.2", [hex: :remote_ip, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:retry, "~> 0.19", [hex: :retry, repo: "hexpm", optional: false]}, {:sentry, "~> 11.0", [hex: :sentry, repo: "hexpm", optional: true]}, {:stream_split, "~> 0.1", [hex: :stream_split, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.1", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: true]}, {:telemetry_metrics_statsd, "~> 0.7", [hex: :telemetry_metrics_statsd, repo: "hexpm", optional: true]}, {:telemetry_poller, "~> 1.2", [hex: :telemetry_poller, repo: "hexpm", optional: false]}, {:tls_certificate_check, "~> 1.27", [hex: :tls_certificate_check, repo: "hexpm", optional: false]}, {:tz, "~> 0.28", [hex: :tz, repo: "hexpm", optional: false]}], "hexpm", "e62ba80b4104405490a72d09844fcf040d5da779340e212ac52804ffc1f7b46d"}, - "electric_client": {:hex, :electric_client, "0.7.2", "06f221fa7379d41ab4fb771c9cf78f26654d7c265f61faffa8c31e6b73073224", [:mix], [{:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:electric, "~> 1.1.1", [hex: :electric, repo: "hexpm", optional: true]}, {:gen_stage, "~> 1.2", [hex: :gen_stage, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "4036796cc21767917f1c1c72541b0865a5585b9b4a59ccdb15b99af9c457c97e"}, + "electric": {:hex, :electric, "1.2.4", "00ef87ad229a7eb98de8617fe2d1a6f5741b6ec74db6e7a663e2a321b92aa973", [:mix], [{:backoff, "~> 1.1", [hex: :backoff, repo: "hexpm", optional: false]}, {:bandit, "~> 1.6", [hex: :bandit, repo: "hexpm", optional: false]}, {:dotenvy, "~> 1.1", [hex: :dotenvy, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.6", [hex: :opentelemetry, repo: "hexpm", optional: true]}, {:opentelemetry_exporter, "~> 1.8", [hex: :opentelemetry_exporter, repo: "hexpm", optional: true]}, {:opentelemetry_semantic_conventions, "~> 1.27", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}, {:opentelemetry_telemetry, "~> 1.1", [hex: :opentelemetry_telemetry, repo: "hexpm", optional: false]}, {:otel_metric_exporter, "~> 0.3.11", [hex: :otel_metric_exporter, repo: "hexpm", optional: true]}, {:pg_query_ex, "0.9.0", [hex: :pg_query_ex, repo: "hexpm", optional: false]}, {:plug, "~> 1.17", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.20", [hex: :postgrex, repo: "hexpm", optional: false]}, {:remote_ip, "~> 1.2", [hex: :remote_ip, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:retry, "~> 0.19", [hex: :retry, repo: "hexpm", optional: false]}, {:sentry, "~> 11.0", [hex: :sentry, repo: "hexpm", optional: true]}, {:stream_split, "~> 0.1", [hex: :stream_split, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.1", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: true]}, {:telemetry_metrics_statsd, "~> 0.7", [hex: :telemetry_metrics_statsd, repo: "hexpm", optional: true]}, {:telemetry_poller, "~> 1.2", [hex: :telemetry_poller, repo: "hexpm", optional: false]}, {:tls_certificate_check, "~> 1.27", [hex: :tls_certificate_check, repo: "hexpm", optional: false]}, {:tz, "~> 0.28", [hex: :tz, repo: "hexpm", optional: false]}], "hexpm", "c337c620de55e52542e02cfc87b02b4b40b526ae28120bc49e50a7a6aed85e70"}, + "electric_client": {:hex, :electric_client, "0.8.0-beta-1", "d5fb545d429ff0985ab5151aa27d1848f0944d9222daf40a202093552ad54cc7", [:mix], [{:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:electric, "~> 1.1.11 or ~> 1.2.4", [hex: :electric, repo: "hexpm", optional: true]}, {:gen_stage, "~> 1.2", [hex: :gen_stage, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "32c4d7b8127b1248d1dfb6f94eaab05cf5a3b778f47241718ad0dd91c5289b49"}, "electric_cubdb": {:hex, :electric_cubdb, "2.0.2", "36f86e3c52dc26f4e077a49fbef813b1a38d3897421cece851f149190b34c16c", [:mix], [], "hexpm", "0c0e24b31fb76ad1b33c5de2ab35c41a4ff9da153f5c1f9b15e2de78575acaf2"}, "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, @@ -29,7 +29,7 @@ "grpcbox": {:hex, :grpcbox, "0.17.1", "6e040ab3ef16fe699ffb513b0ef8e2e896da7b18931a1ef817143037c454bcce", [:rebar3], [{:acceptor_pool, "~> 1.0.0", [hex: :acceptor_pool, repo: "hexpm", optional: false]}, {:chatterbox, "~> 0.15.1", [hex: :ts_chatterbox, repo: "hexpm", optional: false]}, {:ctx, "~> 0.6.0", [hex: :ctx, repo: "hexpm", optional: false]}, {:gproc, "~> 0.9.1", [hex: :gproc, repo: "hexpm", optional: false]}], "hexpm", "4a3b5d7111daabc569dc9cbd9b202a3237d81c80bf97212fbc676832cb0ceb17"}, "hpack": {:hex, :hpack_erl, "0.3.0", "2461899cc4ab6a0ef8e970c1661c5fc6a52d3c25580bc6dd204f84ce94669926", [:rebar3], [], "hexpm", "d6137d7079169d8c485c6962dfe261af5b9ef60fbc557344511c1e65e3d95fb0"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.30", "83a466369ebb8fe009e0823c7bf04314dc545122c2d48f896172fc79df33e99d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "76a14d5b7f850bb03b5243088c3649d54a2e52e34a2aa1104dee23cf50a8bae0"}, + "igniter": {:hex, :igniter, "0.7.0", "6848714fa5afa14258c82924a57af9364745316241a409435cf39cbe11e3ae80", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "1e7254780dbf4b44c9eccd6d86d47aa961efc298d7f520c24acb0258c8e90ba9"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "lazy_html": {:hex, :lazy_html, "0.1.3", "8b9c8c135e95f7bc483de6195c4e1c0b2c913a5e2c57353ef4e82703b7ac8bd1", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.9.0", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}], "hexpm", "5f96f29587dcfed8a22281e8c44c6607e958ba821d90b9dfc003d1ef610f7d07"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, @@ -44,7 +44,7 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "opentelemetry": {:hex, :opentelemetry, "1.5.0", "7dda6551edfc3050ea4b0b40c0d2570423d6372b97e9c60793263ef62c53c3c2", [:rebar3], [{:opentelemetry_api, "~> 1.4", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "cdf4f51d17b592fc592b9a75f86a6f808c23044ba7cf7b9534debbcc5c23b0ee"}, - "opentelemetry_api": {:hex, :opentelemetry_api, "1.4.1", "e071429a37441a0fe9097eeea0ff921ebadce8eba8e1ce297b05a43c7a0d121f", [:mix, :rebar3], [], "hexpm", "39bdb6ad740bc13b16215cb9f233d66796bbae897f3bf6eb77abb712e87c3c26"}, + "opentelemetry_api": {:hex, :opentelemetry_api, "1.5.0", "1a676f3e3340cab81c763e939a42e11a70c22863f645aa06aafefc689b5550cf", [:mix, :rebar3], [], "hexpm", "f53ec8a1337ae4a487d43ac89da4bd3a3c99ddf576655d071deed8b56a2d5dda"}, "opentelemetry_exporter": {:hex, :opentelemetry_exporter, "1.8.0", "5d546123230771ef4174e37bedfd77e3374913304cd6ea3ca82a2add49cd5d56", [:rebar3], [{:grpcbox, ">= 0.0.0", [hex: :grpcbox, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.5.0", [hex: :opentelemetry, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.4.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:tls_certificate_check, "~> 1.18", [hex: :tls_certificate_check, repo: "hexpm", optional: false]}], "hexpm", "a1f9f271f8d3b02b81462a6bfef7075fd8457fdb06adff5d2537df5e2264d9af"}, "opentelemetry_semantic_conventions": {:hex, :opentelemetry_semantic_conventions, "1.27.0", "acd0194a94a1e57d63da982ee9f4a9f88834ae0b31b0bd850815fe9be4bbb45f", [:mix, :rebar3], [], "hexpm", "9681ccaa24fd3d810b4461581717661fd85ff7019b082c2dff89c7d5b1fc2864"}, "opentelemetry_telemetry": {:hex, :opentelemetry_telemetry, "1.1.2", "410ab4d76b0921f42dbccbe5a7c831b8125282850be649ee1f70050d3961118a", [:mix, :rebar3], [{:opentelemetry_api, "~> 1.3", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "641ab469deb181957ac6d59bce6e1321d5fe2a56df444fc9c19afcad623ab253"}, @@ -53,8 +53,8 @@ "pg_query_ex": {:hex, :pg_query_ex, "0.9.0", "8e34bd2d0e0eb9e8d621c4697032fad4bfba46826950d3b46904a80ab589b43a", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:protox, "~> 2.0", [hex: :protox, repo: "hexpm", optional: false]}], "hexpm", "a3fada1704fa9e2bc11ff846ad545ef9a1d34f46d86206063c37128960f4f5f5"}, "phoenix": {:hex, :phoenix, "1.8.1", "865473a60a979551a4879db79fbfb4503e41cd809e77c85af79716578b6a456d", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "84d77d2b2e77c3c7e7527099bd01ef5c8560cd149c036d6b3a40745f11cd2fb2"}, "phoenix_html": {:hex, :phoenix_html, "4.3.0", "d3577a5df4b6954cd7890c84d955c470b5310bb49647f0a114a6eeecc850f7ad", [:mix], [], "hexpm", "3eaa290a78bab0f075f791a46a981bbe769d94bc776869f4f3063a14f30497ad"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "1.1.14", "cae84abc4cd00dde4bb200b8516db556704c585c267aff9cd4955ff83cceb86c", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b827980e2bc00fddd8674e3b567519a4e855b5de04bf8607140414f1101e2627"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "1.1.17", "1d782b5901cf13b137c6d8c56542ff6cb618359b2adca7e185b21df728fa0c6c", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fa82307dd9305657a8236d6b48e60ef2e8d9f742ee7ed832de4b8bcb7e0e5ed2"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.2.0", "ff3a5616e1bed6804de7773b92cbccfc0b0f473faf1f63d7daf1206c7aeaaa6f", [:mix], [], "hexpm", "adc313a5bf7136039f63cfd9668fde73bba0765e0614cba80c06ac9460ff3e96"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"}, "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, @@ -62,7 +62,7 @@ "protobuf": {:hex, :protobuf, "0.13.0", "7a9d9aeb039f68a81717eb2efd6928fdf44f03d2c0dfdcedc7b560f5f5aae93d", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "21092a223e3c6c144c1a291ab082a7ead32821ba77073b72c68515aa51fef570"}, "protox": {:hex, :protox, "2.0.4", "2a86ae3699696c5d92e15804968ce6a6827a8d9516d0bbabcf16584dec710ae1", [:mix], [], "hexpm", "8ac5a03bb84da4c75d76dc29cd46008081c2068ad0f6f0da4c051093d6e24c01"}, "remote_ip": {:hex, :remote_ip, "1.2.0", "fb078e12a44414f4cef5a75963c33008fe169b806572ccd17257c208a7bc760f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2ff91de19c48149ce19ed230a81d377186e4412552a597d6a5137373e5877cb7"}, - "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, + "req": {:hex, :req, "0.5.16", "99ba6a36b014458e52a8b9a0543bfa752cb0344b2a9d756651db1281d4ba4450", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "974a7a27982b9b791df84e8f6687d21483795882a7840e8309abdbe08bb06f09"}, "retry": {:hex, :retry, "0.19.0", "aeb326d87f62295d950f41e1255fe6f43280a1b390d36e280b7c9b00601ccbc2", [:mix], [], "hexpm", "85ef376aa60007e7bff565c366310966ec1bd38078765a0e7f20ec8a220d02ca"}, "rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"}, "sentry": {:hex, :sentry, "10.8.1", "aa45309785e1521416225adb16e0b4d8b957578804527f3c7babb6fefbc5e456", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "495b3cdadad90ba72eef973aa3dec39b3b8b2a362fe87e2f4ef32133ac3b4097"}, @@ -76,10 +76,10 @@ "telemetry_metrics_statsd": {:hex, :telemetry_metrics_statsd, "0.7.1", "3502235bb5b35ce50d608bf0f34369ef76eb92a4dbc8708c7e8780ca0da2d53e", [:mix], [{:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "06338d9dc3b4a202f11a6e706fd3feba4c46100d0aca23688dea0b8f801c361f"}, "telemetry_poller": {:hex, :telemetry_poller, "1.3.0", "d5c46420126b5ac2d72bc6580fb4f537d35e851cc0f8dbd571acf6d6e10f5ec7", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "51f18bed7128544a50f75897db9974436ea9bfba560420b646af27a9a9b35211"}, "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, - "thousand_island": {:hex, :thousand_island, "1.4.1", "8df065e627407e281f7935da5ad0f3842d10eb721afa92e760b720d71e2e37aa", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "204a8640e5d2818589b87286ae66160978628d7edf6095181cbe0440765fb6c1"}, - "tls_certificate_check": {:hex, :tls_certificate_check, "1.29.0", "4473005eb0bbdad215d7083a230e2e076f538d9ea472c8009fd22006a4cfc5f6", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "5b0d0e5cb0f928bc4f210df667304ed91c5bff2a391ce6bdedfbfe70a8f096c5"}, + "thousand_island": {:hex, :thousand_island, "1.4.2", "735fa783005d1703359bbd2d3a5a3a398075ba4456e5afe3c5b7cf4666303d36", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1c7637f16558fc1c35746d5ee0e83b18b8e59e18d28affd1f2fa1645f8bc7473"}, + "tls_certificate_check": {:hex, :tls_certificate_check, "1.30.0", "ef9bdfcb5b551b747cad231a65ebd449623628bb72471c1d2aefcbbc5730683d", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "dfbada8fddb80ae19b8aeaac34d95cfce98c91393b0db9c3ee079b488fd68d81"}, "tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"}, "uuid": {:hex, :uuid, "1.1.8", "e22fc04499de0de3ed1116b770c7737779f226ceefa0badb3592e64d5cfb4eb9", [:mix], [], "hexpm", "c790593b4c3b601f5dc2378baae7efaf5b3d73c4c6456ba85759905be792f2ac"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, - "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.9", "43dc3ba6d89ef5dec5b1d0a39698436a1e856d000d84bf31a3149862b01a287f", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5534d5c9adad3c18a0f58a9371220d75a803bf0b9a3d87e6fe072faaeed76a08"}, } diff --git a/test/phoenix/sync/controller_test.exs b/test/phoenix/sync/controller_test.exs index e4ae068..26a59f4 100644 --- a/test/phoenix/sync/controller_test.exs +++ b/test/phoenix/sync/controller_test.exs @@ -128,7 +128,8 @@ defmodule Phoenix.Sync.ControllerTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -151,7 +152,8 @@ defmodule Phoenix.Sync.ControllerTest do assert Plug.Conn.get_resp_header(resp, "electric-offset") == ["0_0"] assert [ - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -164,7 +166,8 @@ defmodule Phoenix.Sync.ControllerTest do assert Plug.Conn.get_resp_header(resp, "electric-offset") == ["0_0"] assert [ - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) resp = @@ -176,7 +179,8 @@ defmodule Phoenix.Sync.ControllerTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -191,7 +195,8 @@ defmodule Phoenix.Sync.ControllerTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -206,7 +211,8 @@ defmodule Phoenix.Sync.ControllerTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -220,7 +226,8 @@ defmodule Phoenix.Sync.ControllerTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -245,7 +252,8 @@ defmodule Phoenix.Sync.ControllerTest do %{ "headers" => %{"operation" => "insert"}, "value" => %{"title" => "three", "merged" => "mapping-insert-3-three"} - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -270,7 +278,8 @@ defmodule Phoenix.Sync.ControllerTest do %{ "headers" => %{"operation" => "insert"}, "value" => %{"title" => "three", "merged" => "mapping-insert-3-three"} - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -295,7 +304,8 @@ defmodule Phoenix.Sync.ControllerTest do %{ "headers" => %{"operation" => "insert"}, "value" => %{"title" => "two", "merged" => "mapping-insert-2-two"} - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -339,7 +349,8 @@ defmodule Phoenix.Sync.ControllerTest do "inserted_at" => "2025-01-02T12:34:14", "updated_at" => "2025-01-02T12:34:14" } - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end end @@ -384,7 +395,8 @@ defmodule Phoenix.Sync.ControllerTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end diff --git a/test/phoenix/sync/electric_test.exs b/test/phoenix/sync/electric_test.exs index 0683f33..ba92ad3 100644 --- a/test/phoenix/sync/electric_test.exs +++ b/test/phoenix/sync/electric_test.exs @@ -124,7 +124,8 @@ defmodule Phoenix.Sync.ElectricTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -180,7 +181,8 @@ defmodule Phoenix.Sync.ElectricTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"value" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end diff --git a/test/phoenix/sync/router_test.exs b/test/phoenix/sync/router_test.exs index c86a964..14260e0 100644 --- a/test/phoenix/sync/router_test.exs +++ b/test/phoenix/sync/router_test.exs @@ -173,7 +173,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -197,7 +198,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -222,7 +224,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -293,7 +296,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "world war"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "make tea"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "make tea"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -321,7 +325,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"food" => "peas"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"food" => "beans"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"food" => "sweetcorn"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"food" => "sweetcorn"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -349,7 +354,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) resp = @@ -362,7 +368,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) resp = @@ -375,7 +382,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) resp = @@ -388,7 +396,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -415,7 +424,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) resp = @@ -427,7 +437,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -516,7 +527,8 @@ defmodule Phoenix.Sync.RouterTest do %{ "headers" => %{"operation" => "insert"}, "value" => %{"merged" => "query-mfa-insert-2-two", "title" => "two"} - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -579,7 +591,8 @@ defmodule Phoenix.Sync.RouterTest do "inserted_at" => "2025-01-02T12:34:14", "updated_at" => "2025-01-02T12:34:14" } - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end end @@ -697,7 +710,8 @@ defmodule Phoenix.Sync.RouterTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end end @@ -723,7 +737,8 @@ defmodule Phoenix.Sync.RouterTest do %{ "headers" => %{"operation" => "insert"}, "value" => %{"merged" => "module-mfa-insert-3-three", "title" => "three"} - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -748,7 +763,8 @@ defmodule Phoenix.Sync.RouterTest do %{ "headers" => %{"operation" => "insert"}, "value" => %{"merged" => "capture-insert-3-three", "title" => "three"} - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -812,7 +828,8 @@ defmodule Phoenix.Sync.RouterTest do "inserted_at" => "2025-01-02T12:34:14", "updated_at" => "2025-01-02T12:34:14" } - } + }, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end diff --git a/test/phoenix/sync/sandbox_test.exs b/test/phoenix/sync/sandbox_test.exs index 5755c30..065f8bc 100644 --- a/test/phoenix/sync/sandbox_test.exs +++ b/test/phoenix/sync/sandbox_test.exs @@ -180,7 +180,8 @@ defmodule Phoenix.Sync.SandboxTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -237,7 +238,8 @@ defmodule Phoenix.Sync.SandboxTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = snapshot send(task1.pid, :request) @@ -267,7 +269,8 @@ defmodule Phoenix.Sync.SandboxTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = Jason.decode!(resp.resp_body) end @@ -325,7 +328,8 @@ defmodule Phoenix.Sync.SandboxTest do assert [ %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "one"}}, %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "two"}}, - %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}} + %{"headers" => %{"operation" => "insert"}, "value" => %{"title" => "three"}}, + %{"headers" => %{"control" => "snapshot-end"}} ] = snapshot send(task1.pid, :request) diff --git a/test/support/electric_helpers.ex b/test/support/electric_helpers.ex index 85ebf4c..df3c17f 100644 --- a/test/support/electric_helpers.ex +++ b/test/support/electric_helpers.ex @@ -68,10 +68,8 @@ defmodule Support.ElectricHelpers do } storage = - Electric.ShapeCache.Storage.shared_opts( - {Electric.ShapeCache.InMemoryStorage, - stack_id: stack_id, table_base_name: :"in_memory_storage_#{stack_id}"} - ) + {Electric.ShapeCache.InMemoryStorage, + stack_id: stack_id, table_base_name: :"in_memory_storage_#{stack_id}"} publication_name = "electric_test_pub_#{:erlang.phash2(stack_id)}"