Skip to content
Merged
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
18 changes: 5 additions & 13 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ on:
push:
tags:
- v*
env:
CI: true

jobs:
release:
Expand All @@ -13,22 +11,16 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Setup Node.js environment
uses: actions/setup-node@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
node-version: 22
cache: "npm"
bun-version: latest

- name: Install Dependencies
run: npm install

# Ensure a new version doesn't get published to npm if it doesn't
# pass all required checks/validation:
- name: Run Checks
run: npm run typecheck && npm run prettier:ci && npm run eslint
run: bun install

- name: Build
run: npm run build
run: bun run build

- name: Publish to npm
uses: laserware/propellant@v1.0.2
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Deploy Documentation Site

on:
push:
branches: [ "main" ]

# Allows you to run this workflow manually from the Actions tab:
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

# Allow only one concurrent deployment, skipping runs queued between the
# run in-progress and latest queued. However, do NOT cancel in-progress runs
# as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false

jobs:
deploy:
name: Deployment
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install Dependencies
run: bun install

- name: Build Static Files
id: build
run: bun run docs:generate

- name: Setup Pages
uses: actions/configure-pages@v5

- name: Upload Artifact
uses: actions/upload-pages-artifact@v3
with:
path: "site"

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
25 changes: 11 additions & 14 deletions .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
name: Validate
on: [push]
env:
CI: true

jobs:
check:
Expand All @@ -10,20 +8,19 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Setup Node.js environment
uses: actions/setup-node@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
node-version: 22
cache: "npm"
bun-version: latest

- name: Install dependencies
run: npm install
- name: Install Dependencies
run: bun install

- name: ESLint
run: npm run eslint

- name: Check Formatting
run: npm run prettier:ci
- name: Run Biome Checks
run: bun run ci

- name: Check Types
run: npm run typecheck
run: bun run check:types

- name: Run Unit Tests
run: bun test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ yarn.lock
pnpm-lock.yaml
.pnp.*
.idea
site
12 changes: 12 additions & 0 deletions .run/Build.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>
12 changes: 12 additions & 0 deletions .run/Check Biome.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Check Biome" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="check:biome" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>
12 changes: 12 additions & 0 deletions .run/Check Types.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Check Types" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="check:types" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>
12 changes: 12 additions & 0 deletions .run/Tests.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Tests" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="test" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>
8 changes: 8 additions & 0 deletions .run/Validate.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Validate" type="CompoundRunConfigurationType">
<toRun name="Check Biome" type="js.build_tools.npm" />
<toRun name="Check Types" type="js.build_tools.npm" />
<toRun name="Tests" type="js.build_tools.npm" />
<method v="2" />
</configuration>
</component>
108 changes: 107 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,109 @@
# @laserware/stasis
# Stasis

State management using Redux libraries.

This library forwards exports from [Redux Toolkit](https://redux-toolkit.js.org) and [ReduxSaga](https://redux-saga.js.org).

> [!NOTE]
> I use both of these libraries heavily in several of my projects and it makes it easier to update
> a single dependency, rather than keep two up-to-date.

This library also provides the following additional APIs:

- `createAsyncAction`: Custom async action creator based on the [`createAsyncAction` export from `typesafe-actions`](https://github.com/piotrwitek/typesafe-actions?tab=readme-ov-file#createasyncaction)
- `ActionType`: Utility type that allows you to get the action `type` and `payload` types from the action
- `forwardChannelAction`: Simple utility function for dispatching actions emitted from an [`EventChannel`](https://redux-saga.js.org/docs/api#eventchannelsubscribe-buffer)

## Usage

Consult the Redux Toolkit and Redux Saga documentation for usage of forwarded exports.

> [!IMPORTANT]
> The exports from `redux-saga/effects` are forwarded directly, as well as via an `effects` object.
> If your build tool supports tree-shaking, any unused exports will be excluded from the resulting build.

The example below exhibits how to use the additional exports.

```ts
import {
createAsyncAction,
all, // Import individual effects
effects as E, // Or all of them
eventChannel,
forwardChannelAction,
type ActionType,
type EventChannel,
type SagaIterator,
} from "@laserware/stasis";

type Request = { value: string };

export const doSomething = createAsyncAction<
Request, // Payload for the `.request` action.
string, // Payload for the `.success` action.
string // Payload for the `.failure` action.
>("@app/doSomething");

export function* someSaga(): SagaIterator {
yield all([
E.takeEvery(doSomething.request, handleRequestSaga),
E.takeEvery(doSomething.success, handleSuccessSaga),
E.takeEvery(doSomething.failure, handleFailureSaga),
]);
}

function* handleRequestSaga(
action: ActionType<typeof doSomething.request>,
): SagaIterator {
// TypeScript knows this is a `Request` because of the `ActionType`
// annotation above:
const value = action.payload.value;

const resizeChannel = yield E.call(createResizeChannel);

// This will dispatch the action whenever the window is resized:
yield E.takeEvery(resizeChannel, forwardChannelAction);
// ...
}

function* handleSuccessSaga(
action: ActionType<typeof doSomething.success>,
): SagaIterator {
// TypeScript knows this is a string because of the `ActionType`
// annotation above:
const value = action.payload;

// ...
}

function* handleFailureSaga(
action: ActionType<typeof doSomething.failure>,
): SagaIterator {
// TypeScript knows this is a string because of the `ActionType`
// annotation above:
const value = action.payload;

// ...
}

function createResizeChannel(): EventChannel<
ActionType<typeof doSomething.success>
> {
return eventChannel((emit) => {
const handleWindowResize = () => {
emit(doSomething.success());
};

window.addEventListener("resize", handleResize);

return () => {
window.removeEventListener("resize", handleResize);
};
});
}
```

## Development

You'll need to install Bun prior to doing any development. Once installed, run `bun install` to install dependencies.

56 changes: 56 additions & 0 deletions biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": true,
"ignore": []
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"lineWidth": 80,
"ignore": ["./package.json"]
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"noUselessElse": "off",
"noParameterAssign": "off",
"noNonNullAssertion": "off"
},
"suspicious": {
"noExplicitAny": "off"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
},
"overrides": [
{
"include": ["src/**/*.test.ts"],
"formatter": {
"lineWidth": 100
},
"linter": {
"rules": {
"recommended": true,
"style": {
"noNonNullAssertion": "off"
}
}
}
}
]
}
Loading