Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# EXAMPLE USAGE:
#
# Refer for explanation to following link:
# https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md
#
# pre-push:
# commands:
# packages-audit:
# tags: frontend security
# run: yarn audit
# gems-audit:
# tags: backend security
# run: bundle audit
#
# pre-commit:
# parallel: true
# commands:
# eslint:
# glob: "*.{js,ts,jsx,tsx}"
# run: yarn eslint {staged_files}
# rubocop:
# tags: backend style
# glob: "*.rb"
# exclude: '(^|/)(application|routes)\.rb$'
# run: bundle exec rubocop --force-exclusion {all_files}
# govet:
# tags: backend style
# files: git ls-files -m
# glob: "*.go"
# run: go vet {files}
# scripts:
# "hello.js":
# runner: node
# "any.go":
# runner: go run
3 changes: 3 additions & 0 deletions packages/restate-sdk-effect/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
src/generated
62 changes: 62 additions & 0 deletions packages/restate-sdk-effect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[![Documentation](https://img.shields.io/badge/doc-reference-blue)](https://docs.restate.dev)
[![Examples](https://img.shields.io/badge/view-examples-blue)](https://github.com/restatedev/examples)
[![NPM Version](https://img.shields.io/npm/v/%40restatedev%2Frestate-sdk-effect)](https://www.npmjs.com/package/@restatedev/restate-sdk-effect)
[![Discord](https://img.shields.io/discord/1128210118216007792?logo=discord)](https://discord.gg/skW3AZ6uGd)
[![Twitter](https://img.shields.io/twitter/follow/restatedev.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=restatedev)

# Restate Typescript SDK Effect integration

[Restate](https://restate.dev/) is a system for easily building resilient applications using *distributed durable async/await*.

This package contains a effect integration, allowing to define input/output models of your handlers.

```typescript
import * as restate from "@restatedev/restate-sdk";
import { serde } from "@restatedev/restate-sdk-effect";
import { Schema } from "effect";

const Greeting = Schema.Struct({
name: Schema.String
});

const greeter = restate.service({
name: "greeter",
handlers: {
greet: restate.handlers.handler(
{
input: serde.effect(Greeting),
output: serde.effect(Schema.String),
},
async (ctx, greeting) => {
return `Hello ${greeting.name}!`;
}
),
},
});

export type Greeter = typeof greeter;

restate.serve({ services: [greeter], port: 9080 });
```

For the SDK main package, checkout [`@restatedev/restate-sdk`](../restate-sdk).

## Community

* 🤗️ [Join our online community](https://discord.gg/skW3AZ6uGd) for help, sharing feedback and talking to the community.
* 📖 [Check out our documentation](https://docs.restate.dev) to get quickly started!
* 📣 [Follow us on Twitter](https://twitter.com/restatedev) for staying up to date.
* 🙋 [Create a GitHub issue](https://github.com/restatedev/sdk-typescript/issues) for requesting a new feature or reporting a problem.
* 🏠 [Visit our GitHub org](https://github.com/restatedev) for exploring other repositories.

## Using the library

To use this library, add the dependency to your project:

```shell
npm install --save-dev @restatedev/restate-sdk-effect
```

## Versions

This library follows [Semantic Versioning](https://semver.org/).
7 changes: 7 additions & 0 deletions packages/restate-sdk-effect/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "../../api-extractor.base.json"
}
64 changes: 64 additions & 0 deletions packages/restate-sdk-effect/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"name": "@restatedev/restate-sdk-effect",
"version": "1.0.0",
"description": "Restate Typescript SDK Effect",
"author": "Alexander Teague",
"license": "MIT",
"email": "[email protected]",
"homepage": "https://github.com/restatedev/sdk-typescript#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/restatedev/sdk-typescript.git"
},
"bugs": {
"url": "https://github.com/restatedev/sdk-typescript/issues"
},
"type": "module",
"sideEffects": false,
"main": "./dist/cjs/src/public_api.js",
"types": "./dist/cjs/src/public_api.d.ts",
"module": "./dist/esm/src/public_api.js",
"exports": {
".": {
"import": {
"types": "./dist/esm/src/public_api.d.ts",
"default": "./dist/esm/src/public_api.js"
},
"require": {
"types": "./dist/cjs/src/public_api.d.ts",
"default": "./dist/cjs/src/public_api.js"
}
}
},
"files": [
"dist"
],
"devDependencies": {
"@restatedev/restate-sdk-core": "^1.8.3"
},
"dependencies": {
"effect": "^3.17.9"
},
"scripts": {
"api:extract": "api-extractor run --local",
"build": "npm run build:cjs && npm run build:esm",
"build:cjs": "tsc --module commonjs --verbatimModuleSyntax false --moduleResolution node10 --outDir ./dist/cjs --declaration --declarationDir ./dist/cjs && echo >./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
"build:esm": "tsc --outDir ./dist/esm --declaration --declarationDir ./dist/esm",
"lint": "eslint --ignore-path .eslintignore --max-warnings=0 --ext .ts .",
"format": "prettier --ignore-path .eslintignore --write \"**/*.+(js|ts|json)\"",
"format-check": "prettier --ignore-path .eslintignore --check \"**/*.+(js|ts|json)\"",
"attw": "attw --pack",
"verify": "npm run format-check && npm run lint && npm run build && npm run attw && npm run api:extract",
"release": "release-it"
},
"engines": {
"node": ">= 20.19"
},
"directories": {
"example": "examples",
"test": "test"
},
"publishConfig": {
"@restatedev:registry": "https://registry.npmjs.org"
}
}
13 changes: 13 additions & 0 deletions packages/restate-sdk-effect/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate SDK for Node.js/TypeScript,
* which is released under the MIT license.
*
* You can find a copy of the license in file LICENSE in the root
* directory of this repository or package, or at
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
*/

export { serde } from "./serde_api.js";
export type { Serde } from "./serde_api.js";
78 changes: 78 additions & 0 deletions packages/restate-sdk-effect/src/serde_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { Serde } from "@restatedev/restate-sdk-core";
import { Effect, JSONSchema, ParseResult, Schema } from "effect";

export type { Serde } from "@restatedev/restate-sdk-core";

class EffectSerde<A, I = A> implements Serde<A> {
contentType? = "application/json";
jsonSchema?: object | undefined;

constructor(private readonly schema: Schema.Schema<A, I>) {
// Generate JSON schema from Effect Schema
this.jsonSchema = JSONSchema.make(schema);

// Handle void/undefined types
if (schema.Type === Schema.Void || schema.Type === Schema.Undefined) {
this.contentType = undefined;
}
}

serialize(value: A): Uint8Array {
if (value === undefined) {
return new Uint8Array(0);
}

// Encode the value using the schema
const encoded = Schema.encode(this.schema)(value);

// Run the effect synchronously and handle potential errors
const result = Effect.runSync(
Effect.catchAll(encoded, (error) =>
Effect.die(
new Error(
`Serialization failed: ${ParseResult.TreeFormatter.formatErrorSync(
error
)}`
)
)
)
);

return new TextEncoder().encode(JSON.stringify(result));
}

deserialize(data: Uint8Array): A {
const js =
data.length === 0
? undefined
: JSON.parse(new TextDecoder().decode(data));

// Decode the value using the schema
const decoded = Schema.decode(this.schema)(js);

// Run the effect and handle errors
return Effect.runSync(
Effect.catchAll(decoded, (error) =>
Effect.die(
new Error(
`Deserialization failed: ${ParseResult.TreeFormatter.formatErrorSync(
error
)}`
)
)
)
);
}
}

export namespace serde {
/**
* An Effect Schema based serde.
*
* @param schema the Effect schema
* @returns a serde that will validate the data with the Effect schema
*/
export const effect = <A, I = A>(schema: Schema.Schema<A, I>): Serde<A> => {
return new EffectSerde(schema);
};
}
5 changes: 5 additions & 0 deletions packages/restate-sdk-effect/tsconfig.eslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "test/**/*.ts"],
"references": [{ "path": "../restate-sdk-core" }]
}
9 changes: 9 additions & 0 deletions packages/restate-sdk-effect/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist/esm",
"paths": {}
},
"include": ["src/**/*.ts"],
"references": [{ "path": "../restate-sdk-core" }]
}