@empyria/restate 0.1.2 → 0.1.4

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.
package/README.md CHANGED
@@ -43,12 +43,13 @@ import { checkServiceHandler } from '@empyria/restate/lib/Admin.js'
43
43
 
44
44
  ## Modules
45
45
 
46
- | Module | Purpose |
47
- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
48
- | [lib/Admin.js](./lib/Admin.js) | Restate Admin API client — service/handler discovery, deployment registration and teardown, workflow/message dispatch, and `setupRestate` for wiring up an endpoint with health checks and graceful shutdown. |
49
- | [lib/Caller.js](./lib/Caller.js) | `CallerServiceDef` — a generic Restate service that dispatches a call to any handler on any other service by name, for when the target isn't known at compile time. |
50
- | [lib/Cron.js](./lib/Cron.js) | `cronJobInitiator`/`cronJob` — Restate services implementing cron-driven, replay-safe recurring job scheduling on top of `croner`. |
51
- | [lib/Validation.js](./lib/Validation.js) | `withValidation` — wraps a workflow handler with input/output JSON schema validation via `@empyria/common`. |
46
+ | Module | Purpose |
47
+ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
48
+ | [lib/Admin.js](./lib/Admin.js) | Restate Admin API client — service/handler discovery, deployment registration and teardown, workflow/message dispatch, `defineWorkflow`/`defineService`/`defineObject` construct definers, and `setupRestate` for wiring up an endpoint with health checks and graceful shutdown. |
49
+ | [lib/Caller.js](./lib/Caller.js) | `CallerServiceDef` — a generic Restate service that dispatches a call to any handler on any other service by name, for when the target isn't known at compile time. |
50
+ | [lib/Cron.js](./lib/Cron.js) | `cronJobInitiator`/`cronJob` — Restate services implementing cron-driven, replay-safe recurring job scheduling on top of `croner`. |
51
+ | [lib/Pubsub.js](./lib/Pubsub.js) | `definePubsub` (register a pubsub Virtual Object on your endpoint), `pubsubPublisher` (publish into it from inside a handler, in-process), `pubsubClient` (publish/pull/subscribe to it from anywhere else, over the network) — thin wrappers around `@restatedev/pubsub`/`@restatedev/pubsub-client`. |
52
+ | [lib/Validation.js](./lib/Validation.js) | `withValidation` — wraps a workflow handler with input/output JSON schema validation via `@empyria/common`. |
52
53
 
53
54
  There is no official Restate Admin API client (verified directly against the published
54
55
  `@restatedev/restate-sdk`/`-clients` packages) — `lib/Admin.js` is a hand-written wrapper kept
package/index.js CHANGED
@@ -5,3 +5,5 @@ export * from './lib/Cron.js'
5
5
  export * from './lib/Admin.js'
6
6
 
7
7
  export * from './lib/Caller.js'
8
+
9
+ export * from './lib/Pubsub.js'
package/lib/Pubsub.js ADDED
@@ -0,0 +1,51 @@
1
+ import { createPubsubObject, createPubsubPublisher } from '@restatedev/pubsub'
2
+ import { createPubsubClient } from '@restatedev/pubsub-client'
3
+
4
+ /**
5
+ * Typed wrapper around `@restatedev/pubsub`'s `createPubsubObject`; see `Admin.js`'s
6
+ * `defineWorkflow`/`defineService`/`defineObject` for the same "typed wrapper, plain passthrough
7
+ * in JS" pattern this follows. Unlike those three, there's no handler map to write —
8
+ * `createPubsubObject` returns a complete `VirtualObjectDefinition` on its own (pull/publish/
9
+ * subscribe/truncate), so this exists purely for the same "one `define*` per Restate construct"
10
+ * naming consistency, not to add behavior.
11
+ *
12
+ * Register the result alongside your other services/objects on the same endpoint (see
13
+ * `setupRestate`'s `services` param — Admin.js) — that registration is what lets Restate route to
14
+ * it at all. Restate's own ingress does NOT serve a ready-made SSE route for it, though: reaching
15
+ * it from a browser needs an app-owned relay built on {@link pubsubClient}'s own `.sse()` (or a
16
+ * hand-rolled loop over `.pull()`, e.g. to log each message before forwarding it) — confirmed
17
+ * directly against `@restatedev/pubsub-client`'s compiled source, 2026-08-24, after an earlier,
18
+ * wrong assumption that this was automatic.
19
+ * @param {Parameters<typeof createPubsubObject>[0]} name
20
+ * @param {Parameters<typeof createPubsubObject>[1]} [options]
21
+ */
22
+ export function definePubsub(name, options) {
23
+ return createPubsubObject(name, options)
24
+ }
25
+
26
+ /**
27
+ * Typed wrapper around `@restatedev/pubsub`'s `createPubsubPublisher` — the in-process publish
28
+ * path. Call the returned function from inside any handler that already has `ctx` and shares a
29
+ * Restate endpoint with the pubsub object it targets (both registered via the same `services`
30
+ * list passed to `setupRestate` — see {@link definePubsub}). Under the hood it's
31
+ * `ctx.objectSendClient({name}, topic).publish(message)` — a real Restate call, already covered
32
+ * by the invocation's own journal, so callers don't need to wrap it in an extra `ctx.run()`
33
+ * themselves (unlike a plain `fetch()`-based call, e.g. `sendMessageAsync` in Admin.js, which
34
+ * does).
35
+ * @param {Parameters<typeof createPubsubPublisher>[0]} name
36
+ */
37
+ export function pubsubPublisher(name) {
38
+ return createPubsubPublisher(name)
39
+ }
40
+
41
+ /**
42
+ * Typed wrapper around `@restatedev/pubsub-client`'s `createPubsubClient` — the out-of-process
43
+ * counterpart to {@link pubsubPublisher}/{@link definePubsub}: a network client (`pull`/`sse`/
44
+ * `publish`/`truncate`) for anything that ISN'T a handler on the same Restate endpoint as the
45
+ * pubsub object — a separate process relaying to a browser, an external consumer, ... — reaching
46
+ * it over a plain ingress URL instead of `ctx.objectSendClient`.
47
+ * @param {Parameters<typeof createPubsubClient>[0]} pubsubOptions
48
+ */
49
+ export function pubsubClient(pubsubOptions) {
50
+ return createPubsubClient(pubsubOptions)
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empyria/restate",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Restate.dev helpers for the Empyria nanoservice framework",
5
5
  "license": "MIT",
6
6
  "author": "Imre Fazekas <imre.fazekas@icloud.com>",
@@ -26,13 +26,15 @@
26
26
  "dependencies": {
27
27
  "@empyria/classification": "0.1.2",
28
28
  "@empyria/common": "0.1.2",
29
- "@restatedev/restate-sdk": "1.16.7",
30
- "@restatedev/restate-sdk-clients": "1.16.7",
31
- "@restatedev/restate-sdk-core": "1.16.7",
29
+ "@restatedev/pubsub": "0.3.2",
30
+ "@restatedev/pubsub-client": "0.3.2",
31
+ "@restatedev/restate-sdk": "1.16.8",
32
+ "@restatedev/restate-sdk-clients": "1.16.8",
33
+ "@restatedev/restate-sdk-core": "1.16.8",
32
34
  "croner": "10.0.1"
33
35
  },
34
36
  "devDependencies": {
35
- "@restatedev/restate-server": "1.7.4",
37
+ "@restatedev/restate-server": "1.7.6",
36
38
  "oxfmt": "0.64.0",
37
39
  "oxlint": "1.79.0"
38
40
  },
@@ -0,0 +1,51 @@
1
+ import { describe, test, expect } from 'bun:test'
2
+ import { definePubsub, pubsubPublisher, pubsubClient } from '../lib/Pubsub.js'
3
+
4
+ describe('definePubsub', () => {
5
+ test('is a passthrough to createPubsubObject, name and all', () => {
6
+ const pubsub = definePubsub('pubsub')
7
+ expect(pubsub.name).toBe('pubsub')
8
+ })
9
+
10
+ test('forwards options (e.g. pullTimeout) to createPubsubObject', () => {
11
+ const pubsub = definePubsub('pubsub', { pullTimeout: { seconds: 30 } })
12
+ expect(pubsub.name).toBe('pubsub')
13
+ })
14
+ })
15
+
16
+ describe('pubsubPublisher', () => {
17
+ test('returns a function that publishes via ctx.objectSendClient', () => {
18
+ let capturedTarget
19
+ let capturedKey
20
+ let capturedMessage
21
+ const fakeCtx = {
22
+ objectSendClient: (target, key) => {
23
+ capturedTarget = target
24
+ capturedKey = key
25
+ return {
26
+ publish: (message) => {
27
+ capturedMessage = message
28
+ },
29
+ }
30
+ },
31
+ }
32
+
33
+ const publish = pubsubPublisher('pubsub')
34
+ publish(fakeCtx, 'agent-service', { event: 'ask-triggered' })
35
+
36
+ expect(capturedTarget).toEqual({ name: 'pubsub' })
37
+ expect(capturedKey).toBe('agent-service')
38
+ expect(capturedMessage).toEqual({ event: 'ask-triggered' })
39
+ })
40
+ })
41
+
42
+ describe('pubsubClient', () => {
43
+ test('is a passthrough to createPubsubClient exposing pull/sse/publish/truncate', () => {
44
+ const client = pubsubClient({ url: 'http://localhost:8080', name: 'pubsub' })
45
+
46
+ expect(typeof client.pull).toBe('function')
47
+ expect(typeof client.sse).toBe('function')
48
+ expect(typeof client.publish).toBe('function')
49
+ expect(typeof client.truncate).toBe('function')
50
+ })
51
+ })