Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/borderless/context
Tiny, type-safe, JavaScript-native `context` implementation
https://github.com/borderless/context
context context-api javascript types typescript
Last synced: 7 days ago
JSON representation
Tiny, type-safe, JavaScript-native `context` implementation
- Host: GitHub
- URL: https://github.com/borderless/context
- Owner: borderless
- License: mit
- Created: 2020-03-12T04:02:04.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-12-12T06:17:51.000Z (11 months ago)
- Last Synced: 2024-10-13T15:12:04.509Z (about 1 month ago)
- Topics: context, context-api, javascript, types, typescript
- Language: TypeScript
- Size: 128 KB
- Stars: 18
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Context
[![NPM version][npm-image]][npm-url]
[![NPM downloads][downloads-image]][downloads-url]
[![Build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![Bundle size][bundlephobia-image]][bundlephobia-url]> Tiny, type-safe, JavaScript-native `context` implementation.
**Why?** Working on a project across browsers, workers and node.js requires different implementations on the same thing, e.g. `fetch` vs `require('http')`. Go's [`context`](https://blog.golang.org/context) package provides a nice abstraction to bring all the interfaces together. By implementing a JavaScript first variation, we can achieve the same benefits.
## Installation
```sh
npm install @borderless/context --save
```## Usage
Context values are unidirectional.
```ts
import { background, withValue } from "@borderless/context";// Extend the default `background` context with a value.
const ctx = withValue(background, "test", "test");ctx.value("test"); //=> "test"
background.value("test"); // Invalid.
```### Abort
Use `withAbort` to support cancellation of execution in your application.
```ts
import { withAbort } from "@borderless/context";const [ctx, abort] = withAbort(parentCtx);
onUserCancelsTask(() => abort(new Error("User canceled task")));
```### Timeout
Use `withTimeout` when you want to abort after a specific duration:
```ts
import { withTimeout } from "@borderless/context";const [ctx, abort] = withTimeout(parentCtx, 5000); // You can still `abort` manually.
```### Using Abort
The `useAbort` method will return a `Promise` which rejects when aborted.
```ts
import { useAbort } from "@borderless/context";// Race between the abort signal and making an ajax request.
Promise.race([useAbort(ctx), ajax("http://example.com")]);
```## Example
### Abort Controller
Use `context` with other abort signals, such as `fetch`.
```ts
import { useAbort, Context } from "@borderless/context";function request(ctx: Context<{}>, url: string) {
const controller = new AbortController();
withAbort(ctx).catch(e => controller.abort());
return fetch(url, { signal: controller.signal });
}
```### Application Tracing
Distributed application tracing is a natural example for `context`:
```ts
import { Context, withValue } from "@borderless/context";// Use a unique symbol for tracing.
const spanKey = Symbol("span");// Start a new span, and automatically use "parent" span.
export function startSpan(
ctx: Context,
name: string
): [Span, Context] {
const span = tracer.startSpan(name, {
childOf: ctx.value(spanKey)
});return [span, withValue(ctx, spanKey, span)];
}// server.js
export async function app(req, next) {
const [span, ctx] = startSpan(req.ctx, "app");req.ctx = ctx;
try {
return await next();
} finally {
span.finish();
}
}// middleware.js
export async function middleware(req, next) {
const [span, ctx] = startSpan(req.ctx, "middleware");req.ctx = ctx;
try {
return await next();
} finally {
span.finish();
}
}
```### Libraries
JavaScript and TypeScript libraries can accept a typed `context` argument.
```ts
import { Context, withValue } from "@borderless/context";export function withSentry(ctx: Context) {
return withValue(ctx, sentryKey, someSentryImplementation);
}export function captureException(
ctx: Context<{ [sentryKey]: SomeSentryImplementation }>,
error: Error
) {
return ctx.value(sentryKey).captureException(error);
}
```## License
MIT
[npm-image]: https://img.shields.io/npm/v/@borderless/context.svg?style=flat
[npm-url]: https://npmjs.org/package/@borderless/context
[downloads-image]: https://img.shields.io/npm/dm/@borderless/context.svg?style=flat
[downloads-url]: https://npmjs.org/package/@borderless/context
[travis-image]: https://img.shields.io/travis/BorderlessLabs/context.svg?style=flat
[travis-url]: https://travis-ci.org/BorderlessLabs/context
[coveralls-image]: https://img.shields.io/coveralls/BorderlessLabs/context.svg?style=flat
[coveralls-url]: https://coveralls.io/r/BorderlessLabs/context?branch=master
[bundlephobia-image]: https://img.shields.io/bundlephobia/minzip/@borderless/context.svg
[bundlephobia-url]: https://bundlephobia.com/result?p=@borderless/context