@shivaedev/effect-contract 0.2.1 → 0.4.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.
- package/CHANGELOG.md +19 -0
- package/README.md +12 -1
- package/dist/bind.d.ts +16 -10
- package/dist/bind.d.ts.map +1 -1
- package/dist/bind.js +11 -7
- package/dist/bind.js.map +1 -1
- package/dist/keys.d.ts +9 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +5 -0
- package/dist/keys.js.map +1 -1
- package/dist/live.d.ts +35 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +60 -0
- package/dist/live.js.map +1 -0
- package/dist/operation.d.ts +1 -1
- package/dist/operation.d.ts.map +1 -1
- package/dist/resume.d.ts +17 -0
- package/dist/resume.d.ts.map +1 -0
- package/dist/resume.js +28 -0
- package/dist/resume.js.map +1 -0
- package/package.json +17 -10
- package/src/bind.ts +44 -30
- package/src/keys.ts +6 -1
- package/src/live.ts +81 -0
- package/src/operation.ts +1 -1
- package/src/resume.ts +44 -0
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -6
- package/dist/index.js.map +0 -1
- package/src/index.ts +0 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 - 2026-10-05
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Optional `live.ts` invalidation over native Streams, Reactivity and AtomRpc runtimes: precise changed keys, explicit full-scope reconciliation after initial/reconnected delivery, bounded paused observations, resume, typed stream failures and scoped teardown. Native query atoms own retained data and stale-request interruption.
|
|
8
|
+
- `Key` and `LiveHint` Schemas for existing list/item keys and Changed/Resync hints. A real streaming HTTP/browser fixture demonstrates their composition with native newline-delimited RPC serialization.
|
|
9
|
+
- Browser-safe `resume.ts` owns the existing native/browser resume signal without React peers; effect-react delegates its existing entry to it.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `bind` accepts a native client group with additional RPC operations while preserving the declared contract's types and rejecting clients missing its operations.
|
|
14
|
+
|
|
15
|
+
## 0.3.0 - 2026-10-04
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Breaking: no root entry and no module that re-exports another. `exports` maps one `"./*.ts"` pattern to every module (`src` under the `source` condition, `dist` otherwise), so you import the module that defines a name, and a bundler sees only the modules you use. Where each name now lives:
|
|
20
|
+
- `@shivaedev/effect-contract`: `@shivaedev/effect-contract/bind.ts` (`Bound`, `BoundCommand`, `BoundQuery`, `bind`, `Failure`, `QueryOptions`, `RunFailure`), `@shivaedev/effect-contract/contract.ts` (`Contract`, `contract`, `Declared`, `OperationRpc`, `Tag`), `@shivaedev/effect-contract/keys.ts` (`Collection`, `collection`, `Identity`, `ItemKey`, `invalidationKeys`, `Key`, `ListKey`, `readKeys`), `@shivaedev/effect-contract/operation.ts` (`Command`, `CommandShape`, `command`, `OperationShape`, `PayloadSchema`, `Query`, `QueryShape`, `query`), `@shivaedev/effect-contract/rejection.ts` (`FieldRejection`, `fieldRejection`, `MatchingTags`, `Reject`, `RejectedBy`, `RejectionClass`, `RejectionSpecs`, `Rejections`, `RejectionUnion`, `RejectionValue`, `TaggedRejection`)
|
|
21
|
+
|
|
3
22
|
## 0.2.1 - 2026-10-04
|
|
4
23
|
|
|
5
24
|
### Changed
|
package/README.md
CHANGED
|
@@ -4,7 +4,10 @@ Declare queries and commands once. Each declaration becomes an ordinary native E
|
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { Schema } from "effect";
|
|
7
|
-
import { collection
|
|
7
|
+
import { collection } from "@shivaedev/effect-contract/keys.ts";
|
|
8
|
+
import { command, query } from "@shivaedev/effect-contract/operation.ts";
|
|
9
|
+
import { contract } from "@shivaedev/effect-contract/contract.ts";
|
|
10
|
+
import { fieldRejection } from "@shivaedev/effect-contract/rejection.ts";
|
|
8
11
|
|
|
9
12
|
class Order extends Schema.Class<Order>("Order")({ id: Schema.Number, name: Schema.String, quantity: Schema.Number }) {}
|
|
10
13
|
class OrderNotFound extends Schema.TaggedError<OrderNotFound>()("OrderNotFound", {}) {}
|
|
@@ -40,9 +43,17 @@ export const Orders = contract("orders", { queries: [GetOrder, ListOrders], comm
|
|
|
40
43
|
| `fieldRejection` | `fieldRejection(struct, keys?)` | fields `{ field: Literals<keys>, message: String }` |
|
|
41
44
|
| `bind` | `bind(contract, atomRpcService)` | `{ [query]: { query, run }, [command]: { run } }` |
|
|
42
45
|
| `readKeys` / `invalidationKeys` | `(keys: Key[]) => string[]` | native Reactivity keys |
|
|
46
|
+
| `Key` / `LiveHint` | Schemas in `keys.ts` / `live.ts` | existing list/item keys and optional Changed/Resync hints |
|
|
47
|
+
| `resumeSignal` | `resumeSignal({ window?, native? })` in `resume.ts` | scoped native atom for visible browser resume/online and injected native resume |
|
|
48
|
+
| `live` | `live(atomRuntime, { stream, resyncKeys, resume?, retryDelay? })` | native connection atom, writable pause atom and typed status atom |
|
|
43
49
|
|
|
44
50
|
Payload accepts struct fields or any schema, as in `Rpc.make`. Omitted payload and success are `Schema.Void`.
|
|
45
51
|
|
|
52
|
+
Optional [live updates](../../docs/framework/live-updates.md) compose native
|
|
53
|
+
Streams, RPC, Reactivity and AtomRegistry without React or a second cache. The
|
|
54
|
+
guide distinguishes library behavior, real HTTP/browser fixture evidence and
|
|
55
|
+
application adoption, and explains why streaming HTTP uses native NDJSON.
|
|
56
|
+
|
|
46
57
|
### Operations and rejections
|
|
47
58
|
|
|
48
59
|
- Each operation exposes `payload`, `success`, `error` (the rejection union, or `Schema.Never` without rejections), `Rejection.X` (the class) and `reject.X(...)`, an `Effect<never, X>`.
|
package/dist/bind.d.ts
CHANGED
|
@@ -9,24 +9,30 @@ import type { Rpc } from "effect/unstable/rpc";
|
|
|
9
9
|
import type { RpcClientError } from "effect/unstable/rpc/RpcClientError";
|
|
10
10
|
import type { Contract, Tag } from "./contract.ts";
|
|
11
11
|
import type { CommandShape, QueryShape } from "./operation.ts";
|
|
12
|
-
export type Failure<R extends Rpc.Any> = R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer
|
|
13
|
-
export type RunFailure<R extends Rpc.Any> = R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer _Error, infer
|
|
12
|
+
export type Failure<R extends Rpc.Any> = R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer TError, infer TMiddleware, infer _Requires> ? TError["Type"] | TMiddleware["error"]["Type"] | RpcClientError : never;
|
|
13
|
+
export type RunFailure<R extends Rpc.Any> = R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer _Error, infer TMiddleware, infer _Requires> ? Failure<R> | TMiddleware["~ClientError"] : never;
|
|
14
14
|
export interface QueryOptions {
|
|
15
15
|
readonly headers?: Headers.Input;
|
|
16
16
|
readonly serializationKey?: string;
|
|
17
17
|
readonly timeToLive?: Duration.Input;
|
|
18
18
|
}
|
|
19
|
-
export interface BoundQuery<R extends Rpc.Any,
|
|
19
|
+
export interface BoundQuery<R extends Rpc.Any, TSelf> {
|
|
20
20
|
readonly query: (payload: Rpc.Payload<R>, options?: QueryOptions) => Atom.Atom<AsyncResult.AsyncResult<Rpc.Success<R>, Failure<R>>>;
|
|
21
|
-
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>,
|
|
21
|
+
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>, TSelf>;
|
|
22
22
|
}
|
|
23
|
-
export interface BoundCommand<R extends Rpc.Any,
|
|
24
|
-
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>,
|
|
23
|
+
export interface BoundCommand<R extends Rpc.Any, TSelf> {
|
|
24
|
+
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>, TSelf | Reactivity.Reactivity>;
|
|
25
25
|
}
|
|
26
|
-
export type Bound<
|
|
27
|
-
readonly [
|
|
26
|
+
export type Bound<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TRpcs extends Rpc.Any, TSelf> = {
|
|
27
|
+
readonly [TQuery in TQueries[number] as TQuery["name"]]: BoundQuery<Rpc.ExtractTag<TRpcs, Tag<TName, TQuery["name"]>>, TSelf>;
|
|
28
28
|
} & {
|
|
29
|
-
readonly [
|
|
29
|
+
readonly [TCommand in TCommands[number] as TCommand["name"]]: BoundCommand<Rpc.ExtractTag<TRpcs, Tag<TName, TCommand["name"]>>, TSelf>;
|
|
30
30
|
};
|
|
31
|
-
|
|
31
|
+
type MatchingClient<TRpcs extends Rpc.Any, TClientRpcs extends Rpc.Any> = [TRpcs] extends [Extract<TClientRpcs, {
|
|
32
|
+
readonly _tag: TRpcs["_tag"];
|
|
33
|
+
}>] ? [Extract<TClientRpcs, {
|
|
34
|
+
readonly _tag: TRpcs["_tag"];
|
|
35
|
+
}>] extends [TRpcs] ? unknown : "Client must preserve the contract RPC types" : "Client must implement the contract RPCs";
|
|
36
|
+
export declare function bind<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TRpcs extends Rpc.Any, TSelf, TId extends string, TClientRpcs extends Rpc.Any>(contract: Contract<TName, TQueries, TCommands, TRpcs>, service: AtomRpc.AtomRpcClient<TSelf, TId, TClientRpcs> & MatchingClient<NoInfer<TRpcs>, TClientRpcs>): Bound<TName, TQueries, TCommands, TRpcs, TSelf>;
|
|
37
|
+
export {};
|
|
32
38
|
//# sourceMappingURL=bind.d.ts.map
|
package/dist/bind.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,KAAK,WAAW,MAAM,wCAAwC,CAAC;AAC3E,OAAO,KAAK,KAAK,IAAI,MAAM,iCAAiC,CAAC;AAC7D,OAAO,KAAK,KAAK,OAAO,MAAM,oCAAoC,CAAC;AACnE,OAAO,KAAK,UAAU,MAAM,uCAAuC,CAAC;AACpE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAY,GAAG,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE/D,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,IACpC,CAAC,SAAS,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,QAAQ,EAAE,MAAM,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"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"}
|
package/dist/bind.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import * as Reactivity from "effect/unstable/reactivity/Reactivity";
|
|
3
3
|
import { invalidationKeys, readKeys } from "./keys.js";
|
|
4
|
-
const invalidateAfter = Effect.fn("EffectContract.
|
|
4
|
+
const invalidateAfter = Effect.fn("EffectContract.invalidateAfter")(function* (keys) {
|
|
5
5
|
yield* Reactivity.invalidate(invalidationKeys(keys));
|
|
6
6
|
});
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
function boundQuery(service, tag, query) {
|
|
8
|
+
function reads(payload) {
|
|
9
|
+
return readKeys(query.reads(payload));
|
|
10
|
+
}
|
|
9
11
|
return {
|
|
10
12
|
query: (payload, options = {}) => service.query(tag, payload, { ...options, reactivityKeys: reads(payload) }),
|
|
11
13
|
run: (payload) => service.use((client) => client(tag, payload)),
|
|
12
14
|
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
}
|
|
16
|
+
function boundCommand(service, tag, command) {
|
|
17
|
+
return {
|
|
18
|
+
run: (payload) => service.use((client) => client(tag, payload)).pipe(Effect.tap((result) => invalidateAfter(command.invalidates(payload, result)))),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
17
21
|
export function bind(contract, service) {
|
|
18
22
|
const { name, queries, commands } = contract.declaration;
|
|
19
23
|
return Object.fromEntries([
|
package/dist/bind.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bind.js","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC,OAAO,KAAK,UAAU,MAAM,uCAAuC,CAAC;AAIpE,OAAO,EAAE,gBAAgB,EAAY,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"bind.js","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC,OAAO,KAAK,UAAU,MAAM,uCAAuC,CAAC;AAIpE,OAAO,EAAE,gBAAgB,EAAY,QAAQ,EAAE,MAAM,WAAW,CAAC;AAgDjE,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,gCAAgC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAoB;IAClG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC;AAEH,SAAS,UAAU,CAAC,OAAqB,EAAE,GAAW,EAAE,KAAiB;IACxE,SAAS,KAAK,CAAC,OAAgB;QAC9B,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,CAAC;IACD,OAAO;QACN,KAAK,EAAE,CAAC,OAAgB,EAAE,UAAwB,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACpI,GAAG,EAAE,CAAC,OAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;KACxE,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,OAAqB,EAAE,GAAW,EAAE,OAAqB;IAC9E,OAAO;QACN,GAAG,EAAE,CAAC,OAAgB,EAAE,EAAE,CACzB,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;KAClI,CAAC;AACH,CAAC;AAcD,MAAM,UAAU,IAAI,CACnB,QAAoG,EACpG,OAAqB;IAErB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,WAAW,CAAC;IACzD,OAAO,MAAM,CAAC,WAAW,CAAC;QACzB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAU,CAAC;QACrG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAU,CAAC;KAChH,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/keys.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Schema } from "effect";
|
|
2
2
|
export type Identity = string | number;
|
|
3
3
|
export interface ListKey<Name extends string = string> {
|
|
4
4
|
readonly _tag: "List";
|
|
@@ -10,6 +10,14 @@ export interface ItemKey<Name extends string = string> {
|
|
|
10
10
|
readonly id: Identity;
|
|
11
11
|
}
|
|
12
12
|
export type Key = ListKey | ItemKey;
|
|
13
|
+
export declare const Key: Schema.Union<readonly [Schema.Struct<{
|
|
14
|
+
readonly _tag: Schema.Literal<"List">;
|
|
15
|
+
readonly collection: Schema.String;
|
|
16
|
+
}>, Schema.Struct<{
|
|
17
|
+
readonly _tag: Schema.Literal<"Item">;
|
|
18
|
+
readonly collection: Schema.String;
|
|
19
|
+
readonly id: Schema.Union<readonly [Schema.String, Schema.Number]>;
|
|
20
|
+
}>]>;
|
|
13
21
|
export interface Collection<Name extends string, Id extends Identity> {
|
|
14
22
|
readonly item: (id: Id) => ItemKey<Name>;
|
|
15
23
|
readonly list: ListKey<Name>;
|
package/dist/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvC,MAAM,WAAW,OAAO,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;CACtB;AAED,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,OAAO,CAAC;AAEpC,eAAO,MAAM,GAAG;;;;;;;IAGd,CAAC;AAEH,MAAM,WAAW,UAAU,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,QAAQ;IACnE,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACpB;AAED,eAAO,MAAM,UAAU,GAAI,KAAK,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,CAAC,GAAG,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,EACxG,MAAM,IAAI,EACV,KAAK,EAAE,KACL,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,CAI5B,CAAC;AAIH,eAAO,MAAM,QAAQ,GAAI,MAAM,SAAS,GAAG,EAAE,KAAG,SAAS,MAAM,EAAiC,CAAC;AAEjG,eAAO,MAAM,gBAAgB,GAAI,MAAM,SAAS,GAAG,EAAE,KAAG,SAAS,MAAM,EAEtE,CAAC"}
|
package/dist/keys.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export const Key = Schema.Union([
|
|
3
|
+
Schema.Struct({ _tag: Schema.Literal("List"), collection: Schema.String }),
|
|
4
|
+
Schema.Struct({ _tag: Schema.Literal("Item"), collection: Schema.String, id: Schema.Union([Schema.String, Schema.Number]) }),
|
|
5
|
+
]);
|
|
1
6
|
export const collection = (name, _id) => ({
|
|
2
7
|
item: (id) => ({ _tag: "Item", collection: name, id }),
|
|
3
8
|
list: { _tag: "List", collection: name },
|
package/dist/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAiBhC,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC;IAC/B,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC1E,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;CAC5H,CAAC,CAAC;AAQH,MAAM,CAAC,MAAM,UAAU,GAAG,CACzB,IAAU,EACV,GAAO,EACwB,EAAE,CAAC,CAAC;IACnC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACtD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE;IACxC,IAAI;CACJ,CAAC,CAAC;AAEH,MAAM,GAAG,GAAG,CAAC,GAAQ,EAAU,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;AAEzG,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAoB,EAAqB,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAEjG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAoB,EAAqB,EAAE,CAAC;IAC5E,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;CACxG,CAAC"}
|
package/dist/live.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Cause, type Duration, Option, Schema, Stream } from "effect";
|
|
2
|
+
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
3
|
+
import { Key } from "./keys.ts";
|
|
4
|
+
export declare const LiveHint: Schema.Union<readonly [Schema.Struct<{
|
|
5
|
+
readonly _tag: Schema.Literal<"Changed">;
|
|
6
|
+
readonly keys: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
7
|
+
readonly _tag: Schema.Literal<"List">;
|
|
8
|
+
readonly collection: Schema.String;
|
|
9
|
+
}>, Schema.Struct<{
|
|
10
|
+
readonly _tag: Schema.Literal<"Item">;
|
|
11
|
+
readonly collection: Schema.String;
|
|
12
|
+
readonly id: Schema.Union<readonly [Schema.String, Schema.Number]>;
|
|
13
|
+
}>]>>;
|
|
14
|
+
}>, Schema.Struct<{
|
|
15
|
+
readonly _tag: Schema.Literal<"Resync">;
|
|
16
|
+
}>]>;
|
|
17
|
+
export type LiveHint = typeof LiveHint.Type;
|
|
18
|
+
export interface LiveStatus<E> {
|
|
19
|
+
readonly connection: "connecting" | "live" | "reconnecting";
|
|
20
|
+
readonly failure: Option.Option<Cause.Cause<E>>;
|
|
21
|
+
readonly needsResync: boolean;
|
|
22
|
+
readonly pending: number;
|
|
23
|
+
}
|
|
24
|
+
export interface LiveOptions<E, R> {
|
|
25
|
+
readonly resume?: Atom.Atom<unknown>;
|
|
26
|
+
readonly resyncKeys: readonly Key[];
|
|
27
|
+
readonly retryDelay?: Duration.Input;
|
|
28
|
+
readonly stream: Stream.Stream<LiveHint, E, R>;
|
|
29
|
+
}
|
|
30
|
+
export declare function live<R, E, TRuntimeError>(runtime: Atom.AtomRuntime<R, TRuntimeError>, options: LiveOptions<E, R>): {
|
|
31
|
+
connection: Atom.Atom<import("effect/unstable/reactivity/AsyncResult").AsyncResult<void, TRuntimeError>>;
|
|
32
|
+
paused: Atom.Writable<boolean, boolean>;
|
|
33
|
+
status: Atom.Writable<LiveStatus<E>, LiveStatus<E>>;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAU,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACnF,OAAO,KAAK,IAAI,MAAM,iCAAiC,CAAC;AAExD,OAAO,EAAoB,GAAG,EAAY,MAAM,WAAW,CAAC;AAE5D,eAAO,MAAM,QAAQ;;;;;;;;;;;;IAGnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAC5C,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,YAAY,GAAG,MAAM,GAAG,cAAc,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AACD,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAC/C;AAID,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;;;;EAuDhH"}
|
package/dist/live.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Effect, Option, Schema, Stream } from "effect";
|
|
2
|
+
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
3
|
+
import * as Reactivity from "effect/unstable/reactivity/Reactivity";
|
|
4
|
+
import { invalidationKeys, Key, readKeys } from "./keys.js";
|
|
5
|
+
export const LiveHint = Schema.Union([
|
|
6
|
+
Schema.Struct({ _tag: Schema.Literal("Changed"), keys: Schema.Array(Key) }),
|
|
7
|
+
Schema.Struct({ _tag: Schema.Literal("Resync") }),
|
|
8
|
+
]);
|
|
9
|
+
const MAX_PENDING = 256;
|
|
10
|
+
export function live(runtime, options) {
|
|
11
|
+
const paused = Atom.make(false);
|
|
12
|
+
const status = Atom.make({ connection: "connecting", failure: Option.none(), needsResync: true, pending: 0 });
|
|
13
|
+
const connection = runtime
|
|
14
|
+
.atom((get) => Effect.gen(function* () {
|
|
15
|
+
get.mount(status);
|
|
16
|
+
const reactivity = yield* Reactivity.Reactivity;
|
|
17
|
+
function update(value) {
|
|
18
|
+
get.set(status, { ...get.once(status), ...value });
|
|
19
|
+
}
|
|
20
|
+
function resync() {
|
|
21
|
+
if (get.once(paused)) {
|
|
22
|
+
update({ needsResync: true });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
reactivity.invalidateUnsafe(readKeys(options.resyncKeys));
|
|
26
|
+
update({ needsResync: false, pending: 0 });
|
|
27
|
+
}
|
|
28
|
+
get.subscribe(paused, (value) => {
|
|
29
|
+
if (!value) {
|
|
30
|
+
resync();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
if (options.resume !== undefined) {
|
|
34
|
+
// A subscription alone does not initialize a derived signal's dependencies.
|
|
35
|
+
get.once(options.resume);
|
|
36
|
+
get.subscribe(options.resume, resync);
|
|
37
|
+
}
|
|
38
|
+
const attempt = Effect.suspend(() => {
|
|
39
|
+
let isFirst = true;
|
|
40
|
+
function observe(hint) {
|
|
41
|
+
update({ connection: "live", failure: Option.none() });
|
|
42
|
+
if (get.once(paused)) {
|
|
43
|
+
update({ needsResync: true, pending: Math.min(MAX_PENDING, get.once(status).pending + 1) });
|
|
44
|
+
}
|
|
45
|
+
else if (isFirst || hint._tag === "Resync") {
|
|
46
|
+
resync();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
reactivity.invalidateUnsafe(invalidationKeys(hint.keys));
|
|
50
|
+
}
|
|
51
|
+
isFirst = false;
|
|
52
|
+
}
|
|
53
|
+
return options.stream.pipe(Stream.runForEach((hint) => Effect.sync(() => observe(hint))), Effect.scoped, Effect.catchCause((failure) => Effect.sync(() => update({ failure: Option.some(failure) }))), Effect.andThen(Effect.sync(() => update({ connection: "reconnecting", needsResync: true }))), Effect.andThen(Effect.sleep(options.retryDelay ?? "1 second")));
|
|
54
|
+
});
|
|
55
|
+
yield* Effect.forever(attempt);
|
|
56
|
+
}))
|
|
57
|
+
.pipe(Atom.setIdleTTL(0));
|
|
58
|
+
return { connection, paused, status };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=live.js.map
|
package/dist/live.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACnF,OAAO,KAAK,IAAI,MAAM,iCAAiC,CAAC;AACxD,OAAO,KAAK,UAAU,MAAM,uCAAuC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE5D,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;IACpC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3E,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;CACjD,CAAC,CAAC;AAeH,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,MAAM,UAAU,IAAI,CAAsB,OAA2C,EAAE,OAA0B;IAChH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7H,MAAM,UAAU,GAAG,OAAO;SACxB,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;QAChD,SAAS,MAAM,CAAC,KAA6B;YAC5C,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,SAAS,MAAM;YACd,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9B,OAAO;YACR,CAAC;YACD,UAAU,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;YAC1D,MAAM,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;gBACZ,MAAM,EAAE,CAAC;YACV,CAAC;QACF,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAClC,4EAA4E;YAC5E,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACzB,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;YACnC,IAAI,OAAO,GAAG,IAAI,CAAC;YACnB,SAAS,OAAO,CAAC,IAAc;gBAC9B,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACvD,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;oBACtB,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC7F,CAAC;qBAAM,IAAI,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC9C,MAAM,EAAE,CAAC;gBACV,CAAC;qBAAM,CAAC;oBACP,UAAU,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1D,CAAC;gBACD,OAAO,GAAG,KAAK,CAAC;YACjB,CAAC;YACD,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CACzB,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAC7D,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAC5F,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAC5F,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,UAAU,CAAC,CAAC,CAC9D,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC,CAAC,CACF;SACA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACvC,CAAC"}
|
package/dist/operation.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
|
-
import type { Bivariant } from "@shivaedev/types";
|
|
2
|
+
import type { Bivariant } from "@shivaedev/types/bivariant.ts";
|
|
3
3
|
import type { Key } from "./keys.ts";
|
|
4
4
|
import { type MatchingTags, type Reject, type RejectionSpecs, type Rejections, type RejectionUnion } from "./rejection.ts";
|
|
5
5
|
export type PayloadSchema<Payload extends Schema.Top | Schema.Struct.Fields> = Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload;
|
package/dist/operation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operation.d.ts","sourceRoot":"","sources":["../src/operation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"operation.d.ts","sourceRoot":"","sources":["../src/operation.ts"],"names":[],"mappings":"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"}
|
package/dist/resume.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
2
|
+
export type ResumeSource = (resume: () => void) => () => void;
|
|
3
|
+
type ResumeEvent = "online" | "visibilitychange";
|
|
4
|
+
export interface ResumeWindow {
|
|
5
|
+
readonly addEventListener: (type: ResumeEvent, listener: () => void) => void;
|
|
6
|
+
readonly document: {
|
|
7
|
+
readonly visibilityState: string;
|
|
8
|
+
};
|
|
9
|
+
readonly removeEventListener: (type: ResumeEvent, listener: () => void) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface ResumeOptions {
|
|
12
|
+
readonly native?: ResumeSource;
|
|
13
|
+
readonly window?: ResumeWindow;
|
|
14
|
+
}
|
|
15
|
+
export declare function resumeSignal({ window, native }: ResumeOptions): Atom.Atom<number>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=resume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../src/resume.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,iCAAiC,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;AAE9D,KAAK,WAAW,GAAG,QAAQ,GAAG,kBAAkB,CAAC;AAEjD,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC7E,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,QAAQ,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CAChF;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;CAC/B;AAcD,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAcjF"}
|
package/dist/resume.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
2
|
+
function whileVisible(target, type) {
|
|
3
|
+
return (resume) => {
|
|
4
|
+
function visible() {
|
|
5
|
+
if (target.document.visibilityState === "visible") {
|
|
6
|
+
resume();
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
target.addEventListener(type, visible);
|
|
10
|
+
return () => target.removeEventListener(type, visible);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function resumeSignal({ window, native }) {
|
|
14
|
+
const browser = window === undefined ? [] : [whileVisible(window, "visibilitychange"), whileVisible(window, "online")];
|
|
15
|
+
const sources = native === undefined ? browser : [...browser, native];
|
|
16
|
+
return Atom.readable((get) => {
|
|
17
|
+
let count = 0;
|
|
18
|
+
function resume() {
|
|
19
|
+
count += 1;
|
|
20
|
+
get.setSelf(count);
|
|
21
|
+
}
|
|
22
|
+
for (const source of sources) {
|
|
23
|
+
get.addFinalizer(source(resume));
|
|
24
|
+
}
|
|
25
|
+
return count;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../src/resume.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,iCAAiC,CAAC;AAiBxD,SAAS,YAAY,CAAC,MAAoB,EAAE,IAAiB;IAC5D,OAAO,CAAC,MAAM,EAAE,EAAE;QACjB,SAAS,OAAO;YACf,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;gBACnD,MAAM,EAAE,CAAC;YACV,CAAC;QACF,CAAC;QACD,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAiB;IAC7D,MAAM,OAAO,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvH,MAAM,OAAO,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,SAAS,MAAM;YACd,KAAK,IAAI,CAAC,CAAC;YACX,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC9B,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Typed query and command contracts over native Effect RPC and reactivity",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-contract#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"sideEffects": false,
|
|
16
16
|
"type": "module",
|
|
17
17
|
"imports": {
|
|
18
|
-
"#test/*": "./test/*",
|
|
18
|
+
"#test/*": "./src/test-support/*",
|
|
19
19
|
"#*.ts": {
|
|
20
20
|
"source": "./src/*.ts",
|
|
21
21
|
"types": "./dist/*.d.ts",
|
|
@@ -23,31 +23,38 @@
|
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"exports": {
|
|
26
|
-
"
|
|
27
|
-
"types": "./dist
|
|
28
|
-
"source": "./src
|
|
29
|
-
"import": "./dist
|
|
30
|
-
"default": "./dist
|
|
26
|
+
"./*.ts": {
|
|
27
|
+
"types": "./dist/*.d.ts",
|
|
28
|
+
"source": "./src/*.ts",
|
|
29
|
+
"import": "./dist/*.js",
|
|
30
|
+
"default": "./dist/*.js"
|
|
31
31
|
},
|
|
32
32
|
"./package.json": "./package.json"
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
|
35
35
|
"dist",
|
|
36
36
|
"src",
|
|
37
|
+
"!src/**/*.test.ts",
|
|
38
|
+
"!src/**/*.spec.ts",
|
|
39
|
+
"!src/**/test-support",
|
|
37
40
|
"CHANGELOG.md",
|
|
38
41
|
"README.md"
|
|
39
42
|
],
|
|
40
43
|
"dependencies": {
|
|
41
|
-
"@shivaedev/types": "0.
|
|
44
|
+
"@shivaedev/types": "0.2.0"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|
|
47
|
+
"@effect/platform-node": "4.0.0-rc.112",
|
|
44
48
|
"@effect/vitest": "4.0.0-rc.112",
|
|
45
|
-
"@shivaedev/
|
|
49
|
+
"@shivaedev/effect-test": "0.3.0",
|
|
50
|
+
"@shivaedev/quality": "0.15.0",
|
|
46
51
|
"@types/node": "24.10.1",
|
|
47
52
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
48
53
|
"effect": "4.0.0-rc.112",
|
|
54
|
+
"esbuild": "0.28.1",
|
|
55
|
+
"happy-dom": "20.11.2",
|
|
49
56
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
50
|
-
"vitest": "4.1.
|
|
57
|
+
"vitest": "4.1.11"
|
|
51
58
|
},
|
|
52
59
|
"peerDependencies": {
|
|
53
60
|
"effect": "4.0.0-rc.112"
|
package/src/bind.ts
CHANGED
|
@@ -12,13 +12,13 @@ import { invalidationKeys, type Key, readKeys } from "./keys.ts";
|
|
|
12
12
|
import type { CommandShape, QueryShape } from "./operation.ts";
|
|
13
13
|
|
|
14
14
|
export type Failure<R extends Rpc.Any> =
|
|
15
|
-
R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer
|
|
16
|
-
?
|
|
15
|
+
R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer TError, infer TMiddleware, infer _Requires>
|
|
16
|
+
? TError["Type"] | TMiddleware["error"]["Type"] | RpcClientError
|
|
17
17
|
: never;
|
|
18
18
|
|
|
19
19
|
export type RunFailure<R extends Rpc.Any> =
|
|
20
|
-
R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer _Error, infer
|
|
21
|
-
? Failure<R> |
|
|
20
|
+
R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer _Error, infer TMiddleware, infer _Requires>
|
|
21
|
+
? Failure<R> | TMiddleware["~ClientError"]
|
|
22
22
|
: never;
|
|
23
23
|
|
|
24
24
|
export interface QueryOptions {
|
|
@@ -27,54 +27,68 @@ export interface QueryOptions {
|
|
|
27
27
|
readonly timeToLive?: Duration.Input;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export interface BoundQuery<R extends Rpc.Any,
|
|
30
|
+
export interface BoundQuery<R extends Rpc.Any, TSelf> {
|
|
31
31
|
readonly query: (payload: Rpc.Payload<R>, options?: QueryOptions) => Atom.Atom<AsyncResult.AsyncResult<Rpc.Success<R>, Failure<R>>>;
|
|
32
|
-
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>,
|
|
32
|
+
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>, TSelf>;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export interface BoundCommand<R extends Rpc.Any,
|
|
36
|
-
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>,
|
|
35
|
+
export interface BoundCommand<R extends Rpc.Any, TSelf> {
|
|
36
|
+
readonly run: (payload: Rpc.Payload<R>) => Effect.Effect<Rpc.Success<R>, RunFailure<R>, TSelf | Reactivity.Reactivity>;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export type Bound<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
TName extends string,
|
|
41
|
+
TQueries extends readonly QueryShape[],
|
|
42
|
+
TCommands extends readonly CommandShape[],
|
|
43
|
+
TRpcs extends Rpc.Any,
|
|
44
|
+
TSelf,
|
|
45
45
|
> = {
|
|
46
|
-
readonly [
|
|
46
|
+
readonly [TQuery in TQueries[number] as TQuery["name"]]: BoundQuery<Rpc.ExtractTag<TRpcs, Tag<TName, TQuery["name"]>>, TSelf>;
|
|
47
47
|
} & {
|
|
48
|
-
readonly [
|
|
48
|
+
readonly [TCommand in TCommands[number] as TCommand["name"]]: BoundCommand<Rpc.ExtractTag<TRpcs, Tag<TName, TCommand["name"]>>, TSelf>;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
type ErasedClient = AtomRpc.AtomRpcClient<unknown, string, Rpc.Rpc<string, Schema.Top, Schema.Top, Schema.Top>>;
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
type MatchingClient<TRpcs extends Rpc.Any, TClientRpcs extends Rpc.Any> = [TRpcs] extends [Extract<TClientRpcs, { readonly _tag: TRpcs["_tag"] }>]
|
|
54
|
+
? [Extract<TClientRpcs, { readonly _tag: TRpcs["_tag"] }>] extends [TRpcs]
|
|
55
|
+
? unknown
|
|
56
|
+
: "Client must preserve the contract RPC types"
|
|
57
|
+
: "Client must implement the contract RPCs";
|
|
58
|
+
|
|
59
|
+
const invalidateAfter = Effect.fn("EffectContract.invalidateAfter")(function* (keys: readonly Key[]) {
|
|
54
60
|
yield* Reactivity.invalidate(invalidationKeys(keys));
|
|
55
61
|
});
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
function boundQuery(service: ErasedClient, tag: string, query: QueryShape) {
|
|
64
|
+
function reads(payload: unknown) {
|
|
65
|
+
return readKeys(query.reads(payload));
|
|
66
|
+
}
|
|
59
67
|
return {
|
|
60
68
|
query: (payload: unknown, options: QueryOptions = {}) => service.query(tag, payload, { ...options, reactivityKeys: reads(payload) }),
|
|
61
69
|
run: (payload: unknown) => service.use((client) => client(tag, payload)),
|
|
62
70
|
};
|
|
63
|
-
}
|
|
71
|
+
}
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
function boundCommand(service: ErasedClient, tag: string, command: CommandShape) {
|
|
74
|
+
return {
|
|
75
|
+
run: (payload: unknown) =>
|
|
76
|
+
service.use((client) => client(tag, payload)).pipe(Effect.tap((result) => invalidateAfter(command.invalidates(payload, result)))),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
69
79
|
|
|
70
80
|
export function bind<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
TName extends string,
|
|
82
|
+
TQueries extends readonly QueryShape[],
|
|
83
|
+
TCommands extends readonly CommandShape[],
|
|
84
|
+
TRpcs extends Rpc.Any,
|
|
85
|
+
TSelf,
|
|
86
|
+
TId extends string,
|
|
87
|
+
TClientRpcs extends Rpc.Any,
|
|
88
|
+
>(
|
|
89
|
+
contract: Contract<TName, TQueries, TCommands, TRpcs>,
|
|
90
|
+
service: AtomRpc.AtomRpcClient<TSelf, TId, TClientRpcs> & MatchingClient<NoInfer<TRpcs>, TClientRpcs>,
|
|
91
|
+
): Bound<TName, TQueries, TCommands, TRpcs, TSelf>;
|
|
78
92
|
export function bind(
|
|
79
93
|
contract: { readonly declaration: Declared<string, readonly QueryShape[], readonly CommandShape[]> },
|
|
80
94
|
service: ErasedClient,
|
package/src/keys.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Schema } from "effect";
|
|
2
2
|
|
|
3
3
|
export type Identity = string | number;
|
|
4
4
|
|
|
@@ -15,6 +15,11 @@ export interface ItemKey<Name extends string = string> {
|
|
|
15
15
|
|
|
16
16
|
export type Key = ListKey | ItemKey;
|
|
17
17
|
|
|
18
|
+
export const Key = Schema.Union([
|
|
19
|
+
Schema.Struct({ _tag: Schema.Literal("List"), collection: Schema.String }),
|
|
20
|
+
Schema.Struct({ _tag: Schema.Literal("Item"), collection: Schema.String, id: Schema.Union([Schema.String, Schema.Number]) }),
|
|
21
|
+
]);
|
|
22
|
+
|
|
18
23
|
export interface Collection<Name extends string, Id extends Identity> {
|
|
19
24
|
readonly item: (id: Id) => ItemKey<Name>;
|
|
20
25
|
readonly list: ListKey<Name>;
|
package/src/live.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type Cause, type Duration, Effect, Option, Schema, Stream } from "effect";
|
|
2
|
+
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
3
|
+
import * as Reactivity from "effect/unstable/reactivity/Reactivity";
|
|
4
|
+
import { invalidationKeys, Key, readKeys } from "./keys.ts";
|
|
5
|
+
|
|
6
|
+
export const LiveHint = Schema.Union([
|
|
7
|
+
Schema.Struct({ _tag: Schema.Literal("Changed"), keys: Schema.Array(Key) }),
|
|
8
|
+
Schema.Struct({ _tag: Schema.Literal("Resync") }),
|
|
9
|
+
]);
|
|
10
|
+
export type LiveHint = typeof LiveHint.Type;
|
|
11
|
+
export interface LiveStatus<E> {
|
|
12
|
+
readonly connection: "connecting" | "live" | "reconnecting";
|
|
13
|
+
readonly failure: Option.Option<Cause.Cause<E>>;
|
|
14
|
+
readonly needsResync: boolean;
|
|
15
|
+
readonly pending: number;
|
|
16
|
+
}
|
|
17
|
+
export interface LiveOptions<E, R> {
|
|
18
|
+
readonly resume?: Atom.Atom<unknown>;
|
|
19
|
+
readonly resyncKeys: readonly Key[];
|
|
20
|
+
readonly retryDelay?: Duration.Input;
|
|
21
|
+
readonly stream: Stream.Stream<LiveHint, E, R>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const MAX_PENDING = 256;
|
|
25
|
+
|
|
26
|
+
export function live<R, E, TRuntimeError>(runtime: Atom.AtomRuntime<R, TRuntimeError>, options: LiveOptions<E, R>) {
|
|
27
|
+
const paused = Atom.make(false);
|
|
28
|
+
const status = Atom.make<LiveStatus<E>>({ connection: "connecting", failure: Option.none(), needsResync: true, pending: 0 });
|
|
29
|
+
const connection = runtime
|
|
30
|
+
.atom((get) =>
|
|
31
|
+
Effect.gen(function* () {
|
|
32
|
+
get.mount(status);
|
|
33
|
+
const reactivity = yield* Reactivity.Reactivity;
|
|
34
|
+
function update(value: Partial<LiveStatus<E>>) {
|
|
35
|
+
get.set(status, { ...get.once(status), ...value });
|
|
36
|
+
}
|
|
37
|
+
function resync() {
|
|
38
|
+
if (get.once(paused)) {
|
|
39
|
+
update({ needsResync: true });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
reactivity.invalidateUnsafe(readKeys(options.resyncKeys));
|
|
43
|
+
update({ needsResync: false, pending: 0 });
|
|
44
|
+
}
|
|
45
|
+
get.subscribe(paused, (value) => {
|
|
46
|
+
if (!value) {
|
|
47
|
+
resync();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
if (options.resume !== undefined) {
|
|
51
|
+
// A subscription alone does not initialize a derived signal's dependencies.
|
|
52
|
+
get.once(options.resume);
|
|
53
|
+
get.subscribe(options.resume, resync);
|
|
54
|
+
}
|
|
55
|
+
const attempt = Effect.suspend(() => {
|
|
56
|
+
let isFirst = true;
|
|
57
|
+
function observe(hint: LiveHint) {
|
|
58
|
+
update({ connection: "live", failure: Option.none() });
|
|
59
|
+
if (get.once(paused)) {
|
|
60
|
+
update({ needsResync: true, pending: Math.min(MAX_PENDING, get.once(status).pending + 1) });
|
|
61
|
+
} else if (isFirst || hint._tag === "Resync") {
|
|
62
|
+
resync();
|
|
63
|
+
} else {
|
|
64
|
+
reactivity.invalidateUnsafe(invalidationKeys(hint.keys));
|
|
65
|
+
}
|
|
66
|
+
isFirst = false;
|
|
67
|
+
}
|
|
68
|
+
return options.stream.pipe(
|
|
69
|
+
Stream.runForEach((hint) => Effect.sync(() => observe(hint))),
|
|
70
|
+
Effect.scoped,
|
|
71
|
+
Effect.catchCause((failure) => Effect.sync(() => update({ failure: Option.some(failure) }))),
|
|
72
|
+
Effect.andThen(Effect.sync(() => update({ connection: "reconnecting", needsResync: true }))),
|
|
73
|
+
Effect.andThen(Effect.sleep(options.retryDelay ?? "1 second")),
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
yield* Effect.forever(attempt);
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
79
|
+
.pipe(Atom.setIdleTTL(0));
|
|
80
|
+
return { connection, paused, status };
|
|
81
|
+
}
|
package/src/operation.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
|
-
import type { Bivariant } from "@shivaedev/types";
|
|
2
|
+
import type { Bivariant } from "@shivaedev/types/bivariant.ts";
|
|
3
3
|
import type { Key } from "./keys.ts";
|
|
4
4
|
import { type MatchingTags, type Reject, type RejectionSpecs, type Rejections, type RejectionUnion, rejectionSet } from "./rejection.ts";
|
|
5
5
|
|
package/src/resume.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
2
|
+
|
|
3
|
+
export type ResumeSource = (resume: () => void) => () => void;
|
|
4
|
+
|
|
5
|
+
type ResumeEvent = "online" | "visibilitychange";
|
|
6
|
+
|
|
7
|
+
export interface ResumeWindow {
|
|
8
|
+
readonly addEventListener: (type: ResumeEvent, listener: () => void) => void;
|
|
9
|
+
readonly document: { readonly visibilityState: string };
|
|
10
|
+
readonly removeEventListener: (type: ResumeEvent, listener: () => void) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ResumeOptions {
|
|
14
|
+
readonly native?: ResumeSource;
|
|
15
|
+
readonly window?: ResumeWindow;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function whileVisible(target: ResumeWindow, type: ResumeEvent): ResumeSource {
|
|
19
|
+
return (resume) => {
|
|
20
|
+
function visible() {
|
|
21
|
+
if (target.document.visibilityState === "visible") {
|
|
22
|
+
resume();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
target.addEventListener(type, visible);
|
|
26
|
+
return () => target.removeEventListener(type, visible);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resumeSignal({ window, native }: ResumeOptions): Atom.Atom<number> {
|
|
31
|
+
const browser = window === undefined ? [] : [whileVisible(window, "visibilitychange"), whileVisible(window, "online")];
|
|
32
|
+
const sources = native === undefined ? browser : [...browser, native];
|
|
33
|
+
return Atom.readable((get) => {
|
|
34
|
+
let count = 0;
|
|
35
|
+
function resume() {
|
|
36
|
+
count += 1;
|
|
37
|
+
get.setSelf(count);
|
|
38
|
+
}
|
|
39
|
+
for (const source of sources) {
|
|
40
|
+
get.addFinalizer(source(resume));
|
|
41
|
+
}
|
|
42
|
+
return count;
|
|
43
|
+
});
|
|
44
|
+
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { type Bound, type BoundCommand, type BoundQuery, bind, type Failure, type QueryOptions, type RunFailure } from "./bind.ts";
|
|
2
|
-
export { type Contract, contract, type Declared, type OperationRpc, type Tag } from "./contract.ts";
|
|
3
|
-
export { type Collection, collection, type Identity, type ItemKey, invalidationKeys, type Key, type ListKey, readKeys } from "./keys.ts";
|
|
4
|
-
export { type Command, type CommandShape, command, type OperationShape, type PayloadSchema, type Query, type QueryShape, query, } from "./operation.ts";
|
|
5
|
-
export { type FieldRejection, fieldRejection, type MatchingTags, type Reject, type RejectedBy, type RejectionClass, type RejectionSpecs, type Rejections, type RejectionUnion, type RejectionValue, type TaggedRejection, } from "./rejection.ts";
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AACnI,OAAO,EAAE,KAAK,QAAQ,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,KAAK,GAAG,EAAE,MAAM,eAAe,CAAC;AACpG,OAAO,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,gBAAgB,EAAE,KAAK,GAAG,EAAE,KAAK,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACzI,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,GACL,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,GACpB,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { bind } from "./bind.js";
|
|
2
|
-
export { contract } from "./contract.js";
|
|
3
|
-
export { collection, invalidationKeys, readKeys } from "./keys.js";
|
|
4
|
-
export { command, query, } from "./operation.js";
|
|
5
|
-
export { fieldRejection, } from "./rejection.js";
|
|
6
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,IAAI,EAAoD,MAAM,WAAW,CAAC;AACnI,OAAO,EAAiB,QAAQ,EAA8C,MAAM,eAAe,CAAC;AACpG,OAAO,EAAmB,UAAU,EAA+B,gBAAgB,EAA0B,QAAQ,EAAE,MAAM,WAAW,CAAC;AACzI,OAAO,EAGN,OAAO,EAKP,KAAK,GACL,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEN,cAAc,GAUd,MAAM,gBAAgB,CAAC"}
|
package/src/index.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export { type Bound, type BoundCommand, type BoundQuery, bind, type Failure, type QueryOptions, type RunFailure } from "./bind.ts";
|
|
2
|
-
export { type Contract, contract, type Declared, type OperationRpc, type Tag } from "./contract.ts";
|
|
3
|
-
export { type Collection, collection, type Identity, type ItemKey, invalidationKeys, type Key, type ListKey, readKeys } from "./keys.ts";
|
|
4
|
-
export {
|
|
5
|
-
type Command,
|
|
6
|
-
type CommandShape,
|
|
7
|
-
command,
|
|
8
|
-
type OperationShape,
|
|
9
|
-
type PayloadSchema,
|
|
10
|
-
type Query,
|
|
11
|
-
type QueryShape,
|
|
12
|
-
query,
|
|
13
|
-
} from "./operation.ts";
|
|
14
|
-
export {
|
|
15
|
-
type FieldRejection,
|
|
16
|
-
fieldRejection,
|
|
17
|
-
type MatchingTags,
|
|
18
|
-
type Reject,
|
|
19
|
-
type RejectedBy,
|
|
20
|
-
type RejectionClass,
|
|
21
|
-
type RejectionSpecs,
|
|
22
|
-
type Rejections,
|
|
23
|
-
type RejectionUnion,
|
|
24
|
-
type RejectionValue,
|
|
25
|
-
type TaggedRejection,
|
|
26
|
-
} from "./rejection.ts";
|