restate-sdk 0.7.0 → 0.9.0

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.
data/lib/restate.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'sorbet-runtime'
5
4
  require_relative 'restate/version'
6
5
  require_relative 'restate/errors'
7
6
  require_relative 'restate/serde'
@@ -31,8 +30,6 @@ require_relative 'restate/client'
31
30
  # because +Thread.current[]+ is NOT inherited by child fibers, which prevents
32
31
  # accidental context leaks when Async spawns child tasks for run blocks.
33
32
  module Restate # rubocop:disable Metrics/ModuleLength
34
- extend T::Sig
35
-
36
33
  module_function
37
34
 
38
35
  # Create an endpoint, optionally binding services.
@@ -40,13 +37,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
40
37
  #
41
38
  # @param services [Array<Class>] service classes or instances to bind
42
39
  # @return [Endpoint]
43
- sig do
44
- params(
45
- services: T.untyped,
46
- protocol: T.nilable(String),
47
- identity_keys: T.nilable(T::Array[String])
48
- ).returns(Endpoint)
49
- end
50
40
  def endpoint(*services, protocol: nil, identity_keys: nil)
51
41
  ep = Endpoint.new
52
42
  ep.streaming_protocol if protocol == 'bidi'
@@ -65,15 +55,13 @@ module Restate # rubocop:disable Metrics/ModuleLength
65
55
  # c.ingress_url = "http://localhost:8080"
66
56
  # c.admin_url = "http://localhost:9070"
67
57
  # end
68
- sig { params(_block: T.proc.params(arg0: Config).void).void }
69
- def configure(&_block)
58
+ def configure(&)
70
59
  yield config
71
60
  end
72
61
 
73
62
  # Returns the global configuration. Creates a default one on first access.
74
- sig { returns(Config) }
75
63
  def config
76
- @config = T.let(@config, T.nilable(Config)) unless defined?(@config)
64
+ @config = nil unless defined?(@config)
77
65
  @config ||= Config.new
78
66
  end
79
67
 
@@ -84,7 +72,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
84
72
  # Restate.client.service(Greeter).greet("World")
85
73
  # Restate.client.resolve_awakeable(id, payload)
86
74
  # Restate.client.create_deployment("http://localhost:9080")
87
- sig { returns(Client) }
88
75
  def client
89
76
  cfg = config
90
77
  Client.new(ingress_url: cfg.ingress_url, admin_url: cfg.admin_url,
@@ -94,9 +81,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
94
81
  # ── Context accessor (internal) ──
95
82
 
96
83
  # @!visibility private
97
- sig do
98
- params(service_kind: T.nilable(String), handler_kind: T.nilable(String)).returns(ServerContext)
99
- end
100
84
  def fetch_context!(service_kind: nil, handler_kind: nil) # rubocop:disable Metrics
101
85
  ctx = Thread.current[:restate_context]
102
86
  unless ctx
@@ -118,32 +102,23 @@ module Restate # rubocop:disable Metrics/ModuleLength
118
102
  end
119
103
  end
120
104
 
121
- T.cast(ctx, ServerContext)
105
+ ctx
122
106
  end
123
107
 
124
108
  # ── Durable execution ──
125
109
 
126
110
  # Execute a durable side effect. The block runs at most once; the result
127
111
  # is journaled and replayed on retries. Returns a DurableFuture.
128
- sig do
129
- params(name: String, serde: T.untyped, retry_policy: T.nilable(RunRetryPolicy),
130
- background: T::Boolean, action: T.proc.returns(T.untyped)).returns(DurableFuture)
131
- end
132
112
  def run(name, serde: JsonSerde, retry_policy: nil, background: false, &action)
133
113
  fetch_context!.run(name, serde: serde, retry_policy: retry_policy, background: background, &action)
134
114
  end
135
115
 
136
116
  # Convenience shortcut for +run(...).await+. Returns the result directly.
137
- sig do
138
- params(name: String, serde: T.untyped, retry_policy: T.nilable(RunRetryPolicy),
139
- background: T::Boolean, action: T.proc.returns(T.untyped)).returns(T.untyped)
140
- end
141
117
  def run_sync(name, serde: JsonSerde, retry_policy: nil, background: false, &action)
142
118
  fetch_context!.run_sync(name, serde: serde, retry_policy: retry_policy, background: background, &action)
143
119
  end
144
120
 
145
121
  # Durable timer that survives handler restarts.
146
- sig { params(seconds: Numeric).returns(DurableFuture) }
147
122
  def sleep(seconds)
148
123
  fetch_context!.sleep(seconds)
149
124
  end
@@ -151,43 +126,36 @@ module Restate # rubocop:disable Metrics/ModuleLength
151
126
  # ── State operations (VirtualObject / Workflow) ──
152
127
 
153
128
  # Durably retrieve a state entry. Returns nil if unset.
154
- sig { params(name: String, serde: T.untyped).returns(T.untyped) }
155
129
  def get(name, serde: JsonSerde)
156
130
  fetch_context!.get(name, serde: serde)
157
131
  end
158
132
 
159
133
  # Durably retrieve a state entry, returning a DurableFuture instead of blocking.
160
- sig { params(name: String, serde: T.untyped).returns(DurableFuture) }
161
134
  def get_async(name, serde: JsonSerde)
162
135
  fetch_context!.get_async(name, serde: serde)
163
136
  end
164
137
 
165
138
  # Durably set a state entry.
166
- sig { params(name: String, value: T.untyped, serde: T.untyped).void }
167
139
  def set(name, value, serde: JsonSerde)
168
140
  fetch_context!.set(name, value, serde: serde)
169
141
  end
170
142
 
171
143
  # Durably remove a single state entry.
172
- sig { params(name: String).void }
173
144
  def clear(name)
174
145
  fetch_context!.clear(name)
175
146
  end
176
147
 
177
148
  # Durably remove all state entries.
178
- sig { void }
179
149
  def clear_all
180
150
  fetch_context!.clear_all
181
151
  end
182
152
 
183
153
  # List all state entry names.
184
- sig { returns(T.untyped) }
185
154
  def state_keys
186
155
  fetch_context!.state_keys
187
156
  end
188
157
 
189
158
  # List all state entry names, returning a DurableFuture.
190
- sig { returns(DurableFuture) }
191
159
  def state_keys_async
192
160
  fetch_context!.state_keys_async
193
161
  end
@@ -195,12 +163,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
195
163
  # ── Service communication ──
196
164
 
197
165
  # Durably call a handler on a Restate service.
198
- sig do
199
- params(service: T.any(String, T::Class[T.anything]), handler: T.any(String, Symbol),
200
- arg: T.untyped, key: T.nilable(String), idempotency_key: T.nilable(String),
201
- headers: T.nilable(T::Hash[String, String]),
202
- input_serde: T.untyped, output_serde: T.untyped).returns(DurableCallFuture)
203
- end
204
166
  def service_call(service, handler, arg, key: nil, idempotency_key: nil, headers: nil,
205
167
  input_serde: NOT_SET, output_serde: NOT_SET)
206
168
  ctx = fetch_context!
@@ -209,12 +171,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
209
171
  end
210
172
 
211
173
  # Fire-and-forget send to a Restate service handler.
212
- sig do
213
- params(service: T.any(String, T::Class[T.anything]), handler: T.any(String, Symbol),
214
- arg: T.untyped, key: T.nilable(String), delay: T.nilable(Numeric),
215
- idempotency_key: T.nilable(String), headers: T.nilable(T::Hash[String, String]),
216
- input_serde: T.untyped).returns(SendHandle)
217
- end
218
174
  def service_send(service, handler, arg, key: nil, delay: nil, idempotency_key: nil,
219
175
  headers: nil, input_serde: NOT_SET)
220
176
  ctx = fetch_context!
@@ -223,12 +179,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
223
179
  end
224
180
 
225
181
  # Durably call a handler on a Restate virtual object.
226
- sig do
227
- params(service: T.any(String, T::Class[T.anything]), handler: T.any(String, Symbol),
228
- key: String, arg: T.untyped, idempotency_key: T.nilable(String),
229
- headers: T.nilable(T::Hash[String, String]),
230
- input_serde: T.untyped, output_serde: T.untyped).returns(DurableCallFuture)
231
- end
232
182
  def object_call(service, handler, key, arg, idempotency_key: nil, headers: nil,
233
183
  input_serde: NOT_SET, output_serde: NOT_SET)
234
184
  ctx = fetch_context!
@@ -237,12 +187,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
237
187
  end
238
188
 
239
189
  # Fire-and-forget send to a Restate virtual object handler.
240
- sig do
241
- params(service: T.any(String, T::Class[T.anything]), handler: T.any(String, Symbol),
242
- key: String, arg: T.untyped, delay: T.nilable(Numeric),
243
- idempotency_key: T.nilable(String), headers: T.nilable(T::Hash[String, String]),
244
- input_serde: T.untyped).returns(SendHandle)
245
- end
246
190
  def object_send(service, handler, key, arg, delay: nil, idempotency_key: nil,
247
191
  headers: nil, input_serde: NOT_SET)
248
192
  ctx = fetch_context!
@@ -251,12 +195,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
251
195
  end
252
196
 
253
197
  # Durably call a handler on a Restate workflow.
254
- sig do
255
- params(service: T.any(String, T::Class[T.anything]), handler: T.any(String, Symbol),
256
- key: String, arg: T.untyped, idempotency_key: T.nilable(String),
257
- headers: T.nilable(T::Hash[String, String]),
258
- input_serde: T.untyped, output_serde: T.untyped).returns(DurableCallFuture)
259
- end
260
198
  def workflow_call(service, handler, key, arg, idempotency_key: nil, headers: nil,
261
199
  input_serde: NOT_SET, output_serde: NOT_SET)
262
200
  ctx = fetch_context!
@@ -266,12 +204,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
266
204
  end
267
205
 
268
206
  # Fire-and-forget send to a Restate workflow handler.
269
- sig do
270
- params(service: T.any(String, T::Class[T.anything]), handler: T.any(String, Symbol),
271
- key: String, arg: T.untyped, delay: T.nilable(Numeric),
272
- idempotency_key: T.nilable(String), headers: T.nilable(T::Hash[String, String]),
273
- input_serde: T.untyped).returns(SendHandle)
274
- end
275
207
  def workflow_send(service, handler, key, arg, delay: nil, idempotency_key: nil,
276
208
  headers: nil, input_serde: NOT_SET)
277
209
  ctx = fetch_context!
@@ -280,22 +212,12 @@ module Restate # rubocop:disable Metrics/ModuleLength
280
212
  end
281
213
 
282
214
  # Durably call a handler using raw bytes (no serialization).
283
- sig do
284
- params(service: String, handler: String, arg: String,
285
- key: T.nilable(String), idempotency_key: T.nilable(String),
286
- headers: T.nilable(T::Hash[String, String])).returns(DurableCallFuture)
287
- end
288
215
  def generic_call(service, handler, arg, key: nil, idempotency_key: nil, headers: nil)
289
216
  fetch_context!.generic_call(service, handler, arg, key: key,
290
217
  idempotency_key: idempotency_key, headers: headers)
291
218
  end
292
219
 
293
220
  # Fire-and-forget send using raw bytes (no serialization).
294
- sig do
295
- params(service: String, handler: String, arg: String,
296
- key: T.nilable(String), delay: T.nilable(Numeric),
297
- idempotency_key: T.nilable(String), headers: T.nilable(T::Hash[String, String])).returns(SendHandle)
298
- end
299
221
  def generic_send(service, handler, arg, key: nil, delay: nil, idempotency_key: nil, headers: nil)
300
222
  fetch_context!.generic_send(service, handler, arg, key: key, delay: delay,
301
223
  idempotency_key: idempotency_key, headers: headers)
@@ -304,19 +226,16 @@ module Restate # rubocop:disable Metrics/ModuleLength
304
226
  # ── Awakeables ──
305
227
 
306
228
  # Create an awakeable for external callbacks. Returns [awakeable_id, DurableFuture].
307
- sig { params(serde: T.untyped).returns([String, DurableFuture]) }
308
229
  def awakeable(serde: JsonSerde)
309
230
  fetch_context!.awakeable(serde: serde)
310
231
  end
311
232
 
312
233
  # Resolve an awakeable with a success value.
313
- sig { params(awakeable_id: String, payload: T.untyped, serde: T.untyped).void }
314
234
  def resolve_awakeable(awakeable_id, payload, serde: JsonSerde)
315
235
  fetch_context!.resolve_awakeable(awakeable_id, payload, serde: serde)
316
236
  end
317
237
 
318
238
  # Reject an awakeable with a terminal failure.
319
- sig { params(awakeable_id: String, message: String, code: Integer).void }
320
239
  def reject_awakeable(awakeable_id, message, code: 500)
321
240
  fetch_context!.reject_awakeable(awakeable_id, message, code: code)
322
241
  end
@@ -324,25 +243,21 @@ module Restate # rubocop:disable Metrics/ModuleLength
324
243
  # ── Promises (Workflow only) ──
325
244
 
326
245
  # Get a durable promise value, blocking until resolved.
327
- sig { params(name: String, serde: T.untyped).returns(T.untyped) }
328
246
  def promise(name, serde: JsonSerde)
329
247
  fetch_context!.promise(name, serde: serde)
330
248
  end
331
249
 
332
250
  # Peek at a durable promise without blocking. Returns nil if not yet resolved.
333
- sig { params(name: String, serde: T.untyped).returns(T.untyped) }
334
251
  def peek_promise(name, serde: JsonSerde)
335
252
  fetch_context!.peek_promise(name, serde: serde)
336
253
  end
337
254
 
338
255
  # Resolve a durable promise with a value.
339
- sig { params(name: String, payload: T.untyped, serde: T.untyped).void }
340
256
  def resolve_promise(name, payload, serde: JsonSerde)
341
257
  fetch_context!.resolve_promise(name, payload, serde: serde)
342
258
  end
343
259
 
344
260
  # Reject a durable promise with a terminal failure.
345
- sig { params(name: String, message: String, code: Integer).void }
346
261
  def reject_promise(name, message, code: 500)
347
262
  fetch_context!.reject_promise(name, message, code: code)
348
263
  end
@@ -350,21 +265,18 @@ module Restate # rubocop:disable Metrics/ModuleLength
350
265
  # ── Futures ──
351
266
 
352
267
  # Wait until any of the given futures completes. Returns [completed, remaining].
353
- sig { params(futures: T::Array[DurableFuture]).returns([T::Array[DurableFuture], T::Array[DurableFuture]]) }
354
268
  def wait_any(*futures)
355
- T.unsafe(fetch_context!).wait_any(*futures)
269
+ fetch_context!.wait_any(*futures)
356
270
  end
357
271
 
358
272
  # ── Request metadata ──
359
273
 
360
274
  # Returns metadata about the current invocation (id, headers, raw body).
361
- sig { returns(T.untyped) }
362
275
  def request
363
276
  fetch_context!.request
364
277
  end
365
278
 
366
279
  # Returns the key for this virtual object or workflow invocation.
367
- sig { returns(String) }
368
280
  def key
369
281
  fetch_context!.key
370
282
  end
@@ -372,7 +284,6 @@ module Restate # rubocop:disable Metrics/ModuleLength
372
284
  # ── Invocation control ──
373
285
 
374
286
  # Request cancellation of another invocation.
375
- sig { params(invocation_id: String).void }
376
287
  def cancel_invocation(invocation_id)
377
288
  fetch_context!.cancel_invocation(invocation_id)
378
289
  end
data/sig/restate.rbs ADDED
@@ -0,0 +1,202 @@
1
+ # Public API type signatures for the Restate Ruby SDK.
2
+ # Used by Steep for static type checking and by Ruby LSP for IDE completion.
3
+
4
+ module Restate
5
+ # ── Endpoint ──
6
+
7
+ def self.endpoint: (*untyped services, ?protocol: String?, ?identity_keys: Array[String]?) -> Endpoint
8
+ def self.configure: () { (Config) -> void } -> void
9
+ def self.config: () -> Config
10
+ def self.client: () -> Client
11
+
12
+ # ── Durable execution ──
13
+
14
+ def self.run: (String name, ?serde: untyped, ?retry_policy: untyped, ?background: bool) { () -> untyped } -> DurableFuture
15
+ def self.run_sync: (String name, ?serde: untyped, ?retry_policy: untyped, ?background: bool) { () -> untyped } -> untyped
16
+ def self.sleep: (Numeric seconds) -> DurableFuture
17
+
18
+ # ── State operations ──
19
+
20
+ def self.get: (String name, ?serde: untyped) -> untyped
21
+ def self.get_async: (String name, ?serde: untyped) -> DurableFuture
22
+ def self.set: (String name, untyped value, ?serde: untyped) -> void
23
+ def self.clear: (String name) -> void
24
+ def self.clear_all: () -> void
25
+ def self.state_keys: () -> Array[String]
26
+ def self.state_keys_async: () -> DurableFuture
27
+
28
+ # ── Service communication ──
29
+
30
+ def self.service_call: (untyped service, (String | Symbol) handler, untyped arg, ?key: String?, ?idempotency_key: String?, ?headers: Hash[String, String]?, ?input_serde: untyped, ?output_serde: untyped) -> DurableCallFuture
31
+ def self.service_send: (untyped service, (String | Symbol) handler, untyped arg, ?key: String?, ?delay: Numeric?, ?idempotency_key: String?, ?headers: Hash[String, String]?, ?input_serde: untyped) -> SendHandle
32
+ def self.object_call: (untyped service, (String | Symbol) handler, String key, untyped arg, ?idempotency_key: String?, ?headers: Hash[String, String]?, ?input_serde: untyped, ?output_serde: untyped) -> DurableCallFuture
33
+ def self.object_send: (untyped service, (String | Symbol) handler, String key, untyped arg, ?delay: Numeric?, ?idempotency_key: String?, ?headers: Hash[String, String]?, ?input_serde: untyped) -> SendHandle
34
+ def self.workflow_call: (untyped service, (String | Symbol) handler, String key, untyped arg, ?idempotency_key: String?, ?headers: Hash[String, String]?, ?input_serde: untyped, ?output_serde: untyped) -> DurableCallFuture
35
+ def self.workflow_send: (untyped service, (String | Symbol) handler, String key, untyped arg, ?delay: Numeric?, ?idempotency_key: String?, ?headers: Hash[String, String]?, ?input_serde: untyped) -> SendHandle
36
+ def self.generic_call: (String service, String handler, String arg, ?key: String?, ?idempotency_key: String?, ?headers: Hash[String, String]?) -> DurableCallFuture
37
+ def self.generic_send: (String service, String handler, String arg, ?key: String?, ?delay: Numeric?, ?idempotency_key: String?, ?headers: Hash[String, String]?) -> SendHandle
38
+
39
+ # ── Awakeables ──
40
+
41
+ def self.awakeable: (?serde: untyped) -> [String, DurableFuture]
42
+ def self.resolve_awakeable: (String awakeable_id, untyped payload, ?serde: untyped) -> void
43
+ def self.reject_awakeable: (String awakeable_id, String message, ?code: Integer) -> void
44
+
45
+ # ── Promises ──
46
+
47
+ def self.promise: (String name, ?serde: untyped) -> untyped
48
+ def self.peek_promise: (String name, ?serde: untyped) -> untyped
49
+ def self.resolve_promise: (String name, untyped payload, ?serde: untyped) -> void
50
+ def self.reject_promise: (String name, String message, ?code: Integer) -> void
51
+
52
+ # ── Futures / Metadata / Control ──
53
+
54
+ def self.wait_any: (*DurableFuture futures) -> [Array[DurableFuture], Array[DurableFuture]]
55
+ def self.request: () -> untyped
56
+ def self.key: () -> String
57
+ def self.cancel_invocation: (String invocation_id) -> void
58
+ def self.fetch_context!: (?service_kind: String?, ?handler_kind: String?) -> untyped
59
+
60
+ # ── Errors ──
61
+
62
+ class TerminalError < StandardError
63
+ attr_reader status_code: Integer
64
+ def initialize: (?String message, ?status_code: Integer) -> void
65
+ end
66
+
67
+ class SuspendedError < StandardError
68
+ def initialize: () -> void
69
+ end
70
+
71
+ class InternalError < StandardError
72
+ def initialize: () -> void
73
+ end
74
+
75
+ class DisconnectedError < StandardError
76
+ def initialize: () -> void
77
+ end
78
+
79
+ # ── Futures ──
80
+
81
+ class DurableFuture
82
+ attr_reader handle: Integer
83
+ def initialize: (untyped ctx, Integer handle, ?serde: untyped) -> void
84
+ def await: () -> untyped
85
+ def completed?: () -> bool
86
+ end
87
+
88
+ class DurableCallFuture < DurableFuture
89
+ def initialize: (untyped ctx, Integer result_handle, Integer invocation_id_handle, output_serde: untyped) -> void
90
+ def invocation_id: () -> String
91
+ def cancel: () -> void
92
+ end
93
+
94
+ class SendHandle
95
+ def initialize: (untyped ctx, Integer invocation_id_handle) -> void
96
+ def invocation_id: () -> String
97
+ def cancel: () -> void
98
+ end
99
+
100
+ # ── Config ──
101
+
102
+ class Config
103
+ attr_accessor ingress_url: String
104
+ attr_accessor admin_url: String
105
+ attr_accessor ingress_headers: Hash[String, String]
106
+ attr_accessor admin_headers: Hash[String, String]
107
+ def initialize: () -> void
108
+ end
109
+
110
+ # ── Client ──
111
+
112
+ class Client
113
+ def initialize: (?ingress_url: String, ?admin_url: String, ?ingress_headers: Hash[String, String], ?admin_headers: Hash[String, String]) -> void
114
+ def service: (untyped service) -> ClientServiceProxy
115
+ def object: (untyped service, String key) -> ClientServiceProxy
116
+ def workflow: (untyped service, String key) -> ClientServiceProxy
117
+ def resolve_awakeable: (String awakeable_id, untyped payload) -> void
118
+ def reject_awakeable: (String awakeable_id, String message, ?code: Integer) -> void
119
+ def cancel_invocation: (String invocation_id) -> void
120
+ def kill_invocation: (String invocation_id) -> void
121
+
122
+ private
123
+
124
+ def resolve_name: (untyped service) -> String
125
+ def post_ingress: (String path, untyped body) -> untyped
126
+ def post_admin: (String path, untyped body) -> untyped
127
+ def parse_response: (Net::HTTPResponse response) -> untyped
128
+ end
129
+
130
+ class ClientServiceProxy
131
+ def initialize: (String base_url, String service_name, String? key, Hash[String, String] headers) -> void
132
+ end
133
+
134
+ # ── Endpoint ──
135
+
136
+ class Endpoint
137
+ attr_reader services: Hash[String, untyped]
138
+ attr_reader identity_keys: Array[String]
139
+ attr_accessor protocol: String?
140
+ attr_reader middleware: Array[untyped]
141
+ attr_reader outbound_middleware: Array[untyped]
142
+ def initialize: () -> void
143
+ def bind: (*untyped svcs) -> self
144
+ def streaming_protocol: () -> self
145
+ def request_response_protocol: () -> self
146
+ def identity_key: (String key) -> self
147
+ def use: (untyped klass, *untyped args, **untyped kwargs) -> self
148
+ def use_outbound: (untyped klass, *untyped args, **untyped kwargs) -> self
149
+ def app: () -> untyped
150
+
151
+ private
152
+
153
+ def instantiate_middleware: (untyped klass, Array[untyped] args, Hash[Symbol, untyped] kwargs) -> untyped
154
+ end
155
+
156
+ # ── Service proxies ──
157
+
158
+ class ServiceCallProxy
159
+ def initialize: (untyped service_class, ?key: String?, ?call_method: Symbol) -> void
160
+ end
161
+
162
+ class ServiceSendProxy
163
+ def initialize: (untyped service_class, ?key: String?, ?send_method: Symbol, ?delay: Numeric?) -> void
164
+ end
165
+
166
+ # ── Service classes (declared but not checked — heavy metaprogramming) ──
167
+
168
+ class Service
169
+ end
170
+
171
+ class VirtualObject
172
+ end
173
+
174
+ class Workflow
175
+ end
176
+
177
+ # ── Internal ──
178
+
179
+ class Server
180
+ def initialize: (untyped endpoint) -> void
181
+ end
182
+
183
+ module JsonSerde
184
+ def self.serialize: (untyped obj) -> String
185
+ def self.deserialize: (String? buf) -> untyped
186
+ def self.json_schema: () -> Hash[String, untyped]?
187
+ end
188
+
189
+ module BytesSerde
190
+ def self.serialize: (untyped obj) -> String
191
+ def self.deserialize: (String? buf) -> String?
192
+ def self.json_schema: () -> Hash[String, untyped]?
193
+ end
194
+
195
+ class AttemptFinishedEvent
196
+ def set?: () -> bool
197
+ def wait: () -> void
198
+ end
199
+
200
+ NOT_SET: untyped
201
+ RunRetryPolicy: untyped
202
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restate-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Restate Developers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-20 00:00:00.000000000 Z
11
+ date: 2026-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.0'
41
- - !ruby/object:Gem::Dependency
42
- name: sorbet-runtime
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  description: Build resilient applications with distributed durable async/await using
56
42
  Restate
57
43
  email:
@@ -88,8 +74,7 @@ files:
88
74
  - lib/restate/virtual_object.rb
89
75
  - lib/restate/vm.rb
90
76
  - lib/restate/workflow.rb
91
- - lib/tapioca/dsl/compilers/restate.rb
92
- - rbi/restate-sdk.rbi
77
+ - sig/restate.rbs
93
78
  homepage: https://github.com/restatedev/sdk-ruby
94
79
  licenses:
95
80
  - MIT
@@ -1,115 +0,0 @@
1
- # typed: false
2
- # frozen_string_literal: true
3
-
4
- return unless defined?(Tapioca::Dsl::Compiler)
5
-
6
- require 'restate'
7
-
8
- module Tapioca
9
- module Dsl
10
- module Compilers
11
- # Generates Sorbet sigs for Restate handler methods.
12
- #
13
- # Handlers take 0 or 1 parameters (the input). Context is implicit
14
- # via +Restate.*+ module methods.
15
- #
16
- # Usage:
17
- # bundle exec tapioca dsl
18
- class Restate < Compiler
19
- ConstantType = type_member { { fixed: Module } }
20
-
21
- class << self
22
- def gather_constants
23
- # Load service files so they're visible to all_classes.
24
- # In non-Rails apps, Tapioca doesn't auto-load application code.
25
- load_service_files
26
-
27
- all_classes.select do |klass|
28
- klass.is_a?(Class) && (
29
- klass < ::Restate::Service ||
30
- klass < ::Restate::VirtualObject ||
31
- klass < ::Restate::Workflow
32
- )
33
- rescue TypeError
34
- false
35
- end
36
- end
37
-
38
- private
39
-
40
- def load_service_files # rubocop:disable Metrics/MethodLength
41
- root = Bundler.root.to_s
42
- patterns = [
43
- "#{root}/*.rb",
44
- "#{root}/app/**/*.rb",
45
- "#{root}/services/**/*.rb",
46
- "#{root}/examples/**/*.rb"
47
- ]
48
- Dir.glob(patterns).each do |file|
49
- next if file.end_with?('config.ru', 'Rakefile')
50
-
51
- require file
52
- rescue LoadError, StandardError
53
- nil # skip files that can't be loaded
54
- end
55
- end
56
- end
57
-
58
- def decorate # rubocop:disable Metrics/MethodLength
59
- root.create_path(constant) do |klass|
60
- constant.handlers.each do |name, handler|
61
- params = []
62
- if handler.arity == 1
63
- input_type = resolve_input_type(handler)
64
- params << create_param('input', type: input_type)
65
- end
66
- output_type = resolve_output_type(handler)
67
- klass.create_method(name, parameters: params, return_type: output_type)
68
- end
69
- end
70
- end
71
-
72
- private
73
-
74
- # Maps (service kind, handler kind) to the correct context module.
75
- def resolve_context_type(klass, handler)
76
- if klass < ::Restate::Workflow
77
- handler.kind == 'workflow' ? 'Restate::WorkflowContext' : 'Restate::WorkflowSharedContext'
78
- elsif klass < ::Restate::VirtualObject
79
- handler.kind == 'shared' ? 'Restate::ObjectSharedContext' : 'Restate::ObjectContext'
80
- else
81
- 'Restate::Context'
82
- end
83
- end
84
-
85
- # Resolves the Sorbet type string for the handler's input serde.
86
- def resolve_input_type(handler)
87
- type_class = handler.handler_io&.input_serde
88
- sorbet_type_name(type_class) || 'T.untyped'
89
- end
90
-
91
- # Resolves the Sorbet type string for the handler's output serde.
92
- def resolve_output_type(handler)
93
- type_class = handler.handler_io&.output_serde
94
- sorbet_type_name(type_class) || 'T.untyped'
95
- end
96
-
97
- # Returns a Sorbet type string if the serde wraps a known type, nil otherwise.
98
- def sorbet_type_name(serde)
99
- return nil if serde.nil?
100
-
101
- # TStructSerde exposes .struct_class (T::Struct subclasses are visible to Sorbet)
102
- return serde.struct_class.name if serde.is_a?(::Restate::TStructSerde)
103
-
104
- # TypeSerde wraps a primitive type in .type_class
105
- if serde.respond_to?(:type_class)
106
- name = serde.type_class.name
107
- return name if %w[String Integer Float].include?(name)
108
- end
109
-
110
- nil
111
- end
112
- end
113
- end
114
- end
115
- end