@jigs.design/client 0.0.0-stage → 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tom Bates
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,32 @@
1
- # Temporary Holding Version
1
+ # @jigs.design/client
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `createPickleClient` is the browser's connection to a Pickle server: the transport and the query cache, on TanStack Query Core. It has no React and no schema library.
4
+
5
+ ```ts
6
+ import { createPickleClient } from "@jigs.design/client";
7
+
8
+ export const client = createPickleClient({ endpoint: "/api/pickle" });
9
+ ```
10
+
11
+ Create one client per app, in its own module. Every view and session that imports it shares one query cache, so two views reading the same query make one request, and a mutation's invalidations reach both. The client retries network failures, aborts a query's request when nothing reads it any more, and refreshes the queries a mutation invalidates.
12
+
13
+ ## Exports
14
+
15
+ | Export | What it is |
16
+ | -------------------- | ---------------------------------------------------------------- |
17
+ | `createPickleClient` | The client, with `observe`, `mutate`, `invalidate` and `session` |
18
+
19
+ The view calls `observe` and `mutate`; app code calls `invalidate`. `mutate(name, input, procedure)` takes the procedure's `kind` and `invalidates` from the program, and every call goes out with its `kind`, which the server checks against the host.
20
+ | `httpTransport`, `Transport` | The default HTTP transport, and the type to implement your own |
21
+ | `TransportError` | What a transport rejects with: `{ code, message }` |
22
+
23
+ It re-exports the shared types from `@jigs.design/runtime`.
24
+
25
+ ## Source
26
+
27
+ - `src/client.ts`: the client and its query cache.
28
+ - `src/transport.ts`: the transport contract and the HTTP transport.
29
+
30
+ ## Docs
31
+
32
+ [Transport](../../apps/docs/docs/running/transport.mdx) and [Session](../../apps/docs/docs/running/session.mdx).
@@ -0,0 +1,92 @@
1
+ import { HeadersOption, Transport } from "./transport.js";
2
+ import { Message, MutationResult, QueryResult, SessionEvent, SessionOptions } from "@jigs.design/runtime";
3
+ //#region src/client.d.ts
4
+ interface CacheOptions {
5
+ /**
6
+ * How long a query result stays fresh, in milliseconds. A fresh result is
7
+ * reused by a new view, so two blocks or two turns that read the same
8
+ * query share one call; a stale one refetches when a view reads it again.
9
+ * `invalidates` and `invalidate` refetch at any age. Default 60,000: a
10
+ * minute, so a long session does not show hour-old data.
11
+ */
12
+ staleTime?: number;
13
+ }
14
+ /**
15
+ * What the page asks the user before a mutation whose policy is "confirm"
16
+ * runs. `message` is the host's text, never the model's; `input` is what
17
+ * the program sent. Resolve true to run the mutation. `signal` aborts when
18
+ * the view that called the mutation stops or loads another document: close
19
+ * the question then, since the mutation has already failed as `DECLINED`.
20
+ */
21
+ export type ConfirmFunction = (request: {
22
+ input: unknown;
23
+ message: string;
24
+ name: string;
25
+ signal: AbortSignal;
26
+ }) => Promise<boolean>;
27
+ interface ConfirmOptions {
28
+ /**
29
+ * Asks the user to approve a mutation whose policy is "confirm", in the
30
+ * page's own UI, outside the sandbox. Without it, or when it resolves
31
+ * false or throws, the mutation fails with `DECLINED`. A `PickleView`'s
32
+ * `onConfirm` takes its place for that view.
33
+ */
34
+ confirm?: ConfirmFunction;
35
+ }
36
+ export type ClientOptions = CacheOptions & ConfirmOptions & ({
37
+ credentials?: RequestCredentials;
38
+ endpoint: string;
39
+ fetch?: typeof fetch;
40
+ headers?: HeadersOption;
41
+ transport?: never;
42
+ } | {
43
+ credentials?: never;
44
+ endpoint?: never;
45
+ fetch?: never;
46
+ headers?: never;
47
+ transport: Transport;
48
+ });
49
+ export interface PickleClient {
50
+ /** URL of the sandbox frame document. */
51
+ readonly frame: string;
52
+ /** Refetches every query with this name, for every input. */
53
+ invalidate: (name: string) => Promise<void>;
54
+ /**
55
+ * Runs one mutation or action and, when it succeeds, refetches the
56
+ * queries the server says it refreshed. A reply without that list
57
+ * refetches every input of each query in `invalidates`. `kind` goes to
58
+ * the server, which refuses a call whose kind is not the procedure's.
59
+ * When the server asks for confirmation, `procedure.confirm` (else the
60
+ * client's `confirm`) asks the user, and the call goes again with the
61
+ * server's token only if they approve before `procedure.signal` aborts.
62
+ * The signal only withdraws the question: a call already sent is not
63
+ * cancelled, since the server may have run it.
64
+ */
65
+ mutate: (name: string, input: unknown, procedure: {
66
+ confirm?: ConfirmFunction | undefined;
67
+ invalidates: ReadonlyArray<string>;
68
+ kind: "action" | "mutation";
69
+ signal?: AbortSignal | undefined;
70
+ }) => Promise<MutationResult>;
71
+ /**
72
+ * Keeps one query subscribed and reports every result. Unsubscribing
73
+ * aborts its request when nothing else reads it. The call goes out with
74
+ * `kind: "query"`.
75
+ */
76
+ observe: (name: string, input: unknown, listener: (result: QueryResult) => void) => () => void;
77
+ /** One turn, as session events. */
78
+ session: (body: {
79
+ messages: ReadonlyArray<Message>;
80
+ options?: SessionOptions;
81
+ }, options: {
82
+ signal: AbortSignal;
83
+ }) => AsyncIterable<SessionEvent>;
84
+ }
85
+ /**
86
+ * The browser's connection to a Pickle server. Create one per app, in its
87
+ * own module: each client has its own query cache, so two clients share no
88
+ * requests and no invalidations.
89
+ */
90
+ export declare function createPickleClient(options: ClientOptions): PickleClient;
91
+ //#endregion
92
+ export {};
package/dist/client.js ADDED
@@ -0,0 +1,159 @@
1
+ import { TransportError, errorDataOf, httpTransport } from "./transport.js";
2
+ import { QueryClient, QueryObserver } from "@tanstack/query-core";
3
+ //#region src/client.ts
4
+ /** How long a query result stays fresh by default: a minute. */
5
+ const DEFAULT_STALE_TIME = 6e4;
6
+ const RETRYABLE = /* @__PURE__ */ new Set(["NETWORK", "UNAVAILABLE"]);
7
+ const MAX_RETRIES = 2;
8
+ function toQueryResult(result) {
9
+ if (result.status === "success") return {
10
+ data: result.data,
11
+ error: null,
12
+ status: "success"
13
+ };
14
+ if (result.status === "error") return {
15
+ data: null,
16
+ error: errorDataOf(result.error),
17
+ status: "error"
18
+ };
19
+ return {
20
+ data: null,
21
+ error: null,
22
+ status: "pending"
23
+ };
24
+ }
25
+ /**
26
+ * The browser's connection to a Pickle server. Create one per app, in its
27
+ * own module: each client has its own query cache, so two clients share no
28
+ * requests and no invalidations.
29
+ */
30
+ function createPickleClient(options) {
31
+ const transport = options.transport === void 0 ? httpTransport(httpOptions(options)) : options.transport;
32
+ const queries = new QueryClient({ defaultOptions: {
33
+ mutations: { retry: false },
34
+ queries: {
35
+ gcTime: 3e5,
36
+ refetchOnReconnect: false,
37
+ refetchOnWindowFocus: false,
38
+ retry: (failures, error) => failures < MAX_RETRIES && RETRYABLE.has(errorDataOf(error).code),
39
+ staleTime: options.staleTime ?? DEFAULT_STALE_TIME
40
+ }
41
+ } });
42
+ return {
43
+ frame: transport.frame,
44
+ invalidate: (name) => queries.invalidateQueries({ queryKey: [name] }),
45
+ mutate: async (name, input, procedure) => {
46
+ const send = async (confirmation) => {
47
+ try {
48
+ return await transport.call(confirmation === void 0 ? {
49
+ input,
50
+ kind: procedure.kind,
51
+ name
52
+ } : {
53
+ confirmation,
54
+ input,
55
+ kind: procedure.kind,
56
+ name
57
+ }, { signal: new AbortController().signal });
58
+ } catch (error) {
59
+ return { error: errorDataOf(error) };
60
+ }
61
+ };
62
+ let reply = await send();
63
+ if ("requiresAction" in reply) {
64
+ const declined = await askToConfirm(procedure.confirm ?? options.confirm, {
65
+ input,
66
+ message: reply.requiresAction.message,
67
+ name,
68
+ signal: procedure.signal ?? new AbortController().signal
69
+ });
70
+ if (declined !== null) return {
71
+ error: declined,
72
+ status: "error"
73
+ };
74
+ reply = await send(reply.requiresAction.token);
75
+ }
76
+ if ("error" in reply) return {
77
+ error: reply.error,
78
+ status: "error"
79
+ };
80
+ if ("requiresAction" in reply) return {
81
+ error: unconfirmed,
82
+ status: "error"
83
+ };
84
+ const targets = reply.invalidate ?? procedure.invalidates.map((target) => ({ name: target }));
85
+ for (const target of targets) queries.invalidateQueries({ queryKey: target.input === void 0 ? [target.name] : [target.name, target.input] });
86
+ return {
87
+ data: reply.data,
88
+ status: "success"
89
+ };
90
+ },
91
+ observe: (name, input, listener) => {
92
+ const observer = new QueryObserver(queries, {
93
+ queryFn: async (context) => {
94
+ const reply = await transport.call({
95
+ input,
96
+ kind: "query",
97
+ name
98
+ }, { signal: context.signal });
99
+ if ("requiresAction" in reply) throw new TransportError(unconfirmed);
100
+ return reply.data;
101
+ },
102
+ queryKey: [name, input]
103
+ });
104
+ const unsubscribe = observer.subscribe((result) => {
105
+ listener(toQueryResult(result));
106
+ });
107
+ listener(toQueryResult(observer.getCurrentResult()));
108
+ return unsubscribe;
109
+ },
110
+ session: (body, sessionOptions) => transport.session(body, sessionOptions)
111
+ };
112
+ }
113
+ const unconfirmed = {
114
+ code: "FORBIDDEN",
115
+ message: "The server asked for a confirmation the call cannot give."
116
+ };
117
+ /**
118
+ * Asks the user through `confirm`. Null when they approved before
119
+ * `request.signal` aborted; otherwise the `DECLINED` error the mutation fails
120
+ * with, which says why. An abort settles it even if `confirm` never does.
121
+ */
122
+ async function askToConfirm(confirm, request) {
123
+ if (confirm === void 0) return {
124
+ code: "DECLINED",
125
+ message: `"${request.name}" needs the user's confirmation, and this page cannot ask for it.`
126
+ };
127
+ const withdrawn = {
128
+ code: "DECLINED",
129
+ message: `The confirmation for "${request.name}" was withdrawn before the user answered.`
130
+ };
131
+ if (request.signal.aborted) return withdrawn;
132
+ const aborted = Promise.withResolvers();
133
+ const onAbort = () => aborted.resolve(false);
134
+ request.signal.addEventListener("abort", onAbort, { once: true });
135
+ let answer;
136
+ try {
137
+ answer = await Promise.race([confirm(request), aborted.promise]) === true ? null : {
138
+ code: "DECLINED",
139
+ message: "The user declined."
140
+ };
141
+ } catch (error) {
142
+ answer = {
143
+ code: "DECLINED",
144
+ message: `The confirmation for "${request.name}" failed: ${error instanceof Error ? error.message : String(error)}`
145
+ };
146
+ } finally {
147
+ request.signal.removeEventListener("abort", onAbort);
148
+ }
149
+ return request.signal.aborted ? withdrawn : answer;
150
+ }
151
+ function httpOptions(options) {
152
+ const http = { endpoint: options.endpoint };
153
+ if (options.credentials !== void 0) http.credentials = options.credentials;
154
+ if (options.fetch !== void 0) http.fetch = options.fetch;
155
+ if (options.headers !== void 0) http.headers = options.headers;
156
+ return http;
157
+ }
158
+ //#endregion
159
+ export { createPickleClient };
@@ -0,0 +1,4 @@
1
+ import { CallReply, HeadersOption, HttpTransportOptions, Transport, TransportError, httpTransport } from "./transport.js";
2
+ import { ClientOptions, ConfirmFunction, PickleClient, createPickleClient } from "./client.js";
3
+ import { Diagnostic, Invalidation, Message, PickleErrorCode, PickleErrorData, Program, SessionEvent, Span } from "@jigs.design/runtime";
4
+ export { type CallReply, type ClientOptions, type ConfirmFunction, type Diagnostic, type HeadersOption, type HttpTransportOptions, type Invalidation, type Message, type PickleClient, type PickleErrorCode, type PickleErrorData, type Program, type SessionEvent, type Span, type Transport, TransportError, createPickleClient, httpTransport };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { TransportError, httpTransport } from "./transport.js";
2
+ import { createPickleClient } from "./client.js";
3
+ export { TransportError, createPickleClient, httpTransport };
@@ -0,0 +1,60 @@
1
+ import { Invalidation, Message, PickleErrorCode, PickleErrorData, ProcedureKind, SessionEvent, SessionOptions } from "@jigs.design/runtime";
2
+ //#region src/transport.d.ts
3
+ /**
4
+ * A call's reply: the procedure's data and, for a mutation, the queries the
5
+ * server says it refreshed. Without `invalidate`, the client refreshes every
6
+ * input of each query in the program's `invalidates` list. A mutation whose
7
+ * policy is "confirm" first replies with `requiresAction` instead, and has
8
+ * not run.
9
+ */
10
+ export type CallReply = {
11
+ data: unknown;
12
+ invalidate?: ReadonlyArray<Invalidation>;
13
+ } | {
14
+ requiresAction: {
15
+ message: string;
16
+ token: string;
17
+ };
18
+ };
19
+ /** How the browser reaches the server. Implement it to host Pickle behind another router. */
20
+ export interface Transport {
21
+ /**
22
+ * Resolves with the reply, or rejects with a `TransportError`. `kind` is
23
+ * the procedure's kind in the program; send it on, since the server
24
+ * refuses a call without it or with the wrong one.
25
+ */
26
+ call: (request: {
27
+ /** The token from a `requiresAction` reply, once the user approved. */
28
+ confirmation?: string;
29
+ input: unknown;
30
+ kind: ProcedureKind;
31
+ name: string;
32
+ }, options: {
33
+ signal: AbortSignal;
34
+ }) => Promise<CallReply>;
35
+ /** URL of the sandbox frame document. */
36
+ frame: string;
37
+ /** Reports every failure as one `error` event and then ends; never throws. */
38
+ session: (body: {
39
+ messages: ReadonlyArray<Message>;
40
+ options?: SessionOptions;
41
+ }, options: {
42
+ signal: AbortSignal;
43
+ }) => AsyncIterable<SessionEvent>;
44
+ }
45
+ /** A failure with a code the spec can read. */
46
+ export declare class TransportError extends Error implements PickleErrorData {
47
+ readonly code: PickleErrorCode;
48
+ constructor(data: PickleErrorData);
49
+ }
50
+ export type HeadersOption = HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
51
+ export interface HttpTransportOptions {
52
+ credentials?: RequestCredentials;
53
+ /** Path or URL where `pickle.handler` is mounted. */
54
+ endpoint: string;
55
+ fetch?: typeof fetch;
56
+ headers?: HeadersOption;
57
+ }
58
+ /** The default transport: `fetch` against `pickle.handler`. */
59
+ export declare function httpTransport(options: HttpTransportOptions): Transport;
60
+ //#endregion
@@ -0,0 +1,197 @@
1
+ import { parseErrorData, parseInvalidations, parseSessionEvent } from "@jigs.design/runtime";
2
+ //#region src/transport.ts
3
+ /** A failure with a code the spec can read. */
4
+ var TransportError = class extends Error {
5
+ code;
6
+ constructor(data) {
7
+ super(data.message);
8
+ this.code = data.code;
9
+ this.name = "TransportError";
10
+ }
11
+ };
12
+ const VERSION_HEADER = "pickle-version";
13
+ const GATEWAY_STATUSES = /* @__PURE__ */ new Set([
14
+ 502,
15
+ 503,
16
+ 504
17
+ ]);
18
+ const unavailable = {
19
+ code: "UNAVAILABLE",
20
+ message: "The server is not available right now."
21
+ };
22
+ const network = {
23
+ code: "NETWORK",
24
+ message: "Could not reach the server."
25
+ };
26
+ /** The error a reply carries, or `UNAVAILABLE` when the reply is not one of Pickle's. */
27
+ async function replyError(response) {
28
+ if (GATEWAY_STATUSES.has(response.status) || !response.headers.has(VERSION_HEADER)) return unavailable;
29
+ try {
30
+ const body = await response.json();
31
+ return (typeof body === "object" && body !== null && "error" in body ? parseErrorData(body.error) : null) ?? unavailable;
32
+ } catch {
33
+ return unavailable;
34
+ }
35
+ }
36
+ /** Why the `headers` function failed, as the call's error. */
37
+ function headersError(cause) {
38
+ return thrownErrorData(cause) ?? {
39
+ code: "UNAUTHORIZED",
40
+ message: `The request headers could not be built: ${cause instanceof Error ? cause.message : String(cause)}`
41
+ };
42
+ }
43
+ /** The default transport: `fetch` against `pickle.handler`. */
44
+ function httpTransport(options) {
45
+ const fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
46
+ const credentials = options.credentials ?? "same-origin";
47
+ /**
48
+ * The request's headers. A `headers` function that throws, such as a
49
+ * token refresh that failed, is not a network failure: it keeps a thrown
50
+ * `{ code, message }` and is otherwise `UNAUTHORIZED`, never retried.
51
+ */
52
+ const headers = async () => {
53
+ let extra;
54
+ try {
55
+ extra = typeof options.headers === "function" ? await options.headers() : options.headers;
56
+ } catch (error) {
57
+ throw new TransportError(headersError(error));
58
+ }
59
+ const merged = new Headers(extra);
60
+ merged.set("content-type", "application/json");
61
+ return merged;
62
+ };
63
+ const post = (body, init, signal) => fetcher(options.endpoint, {
64
+ body,
65
+ credentials,
66
+ headers: init,
67
+ method: "POST",
68
+ signal
69
+ });
70
+ return {
71
+ async call(request, callOptions) {
72
+ const init = await headers();
73
+ let response;
74
+ try {
75
+ response = await post(JSON.stringify({
76
+ confirmation: request.confirmation,
77
+ input: request.input,
78
+ kind: request.kind,
79
+ name: request.name,
80
+ type: "call"
81
+ }), init, callOptions.signal);
82
+ } catch (error) {
83
+ if (callOptions.signal.aborted) throw error;
84
+ throw new TransportError(network);
85
+ }
86
+ if (!response.ok || !response.headers.has(VERSION_HEADER)) throw new TransportError(await replyError(response));
87
+ let body;
88
+ try {
89
+ body = await response.json();
90
+ } catch {
91
+ throw new TransportError(unavailable);
92
+ }
93
+ if (typeof body !== "object" || body === null) throw new TransportError(unavailable);
94
+ if ("requiresAction" in body) {
95
+ const requiresAction = parseRequiresAction(body.requiresAction);
96
+ if (requiresAction === null) throw new TransportError(unavailable);
97
+ return { requiresAction };
98
+ }
99
+ if (!("data" in body)) throw new TransportError(unavailable);
100
+ if (!("invalidate" in body)) return { data: body.data };
101
+ const invalidate = parseInvalidations(body.invalidate);
102
+ if (invalidate === null) throw new TransportError(unavailable);
103
+ return {
104
+ data: body.data,
105
+ invalidate
106
+ };
107
+ },
108
+ frame: options.endpoint,
109
+ async *session(body, { signal }) {
110
+ let init;
111
+ try {
112
+ init = await headers();
113
+ } catch (error) {
114
+ yield {
115
+ error: errorDataOf(error),
116
+ type: "error"
117
+ };
118
+ return;
119
+ }
120
+ let response;
121
+ try {
122
+ response = await post(JSON.stringify({
123
+ messages: body.messages,
124
+ options: body.options,
125
+ type: "session"
126
+ }), init, signal);
127
+ } catch {
128
+ if (!signal.aborted) yield {
129
+ error: network,
130
+ type: "error"
131
+ };
132
+ return;
133
+ }
134
+ if (!response.ok || !response.headers.has(VERSION_HEADER) || response.body === null) {
135
+ yield {
136
+ error: await replyError(response),
137
+ type: "error"
138
+ };
139
+ return;
140
+ }
141
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
142
+ let buffer = "";
143
+ let ended = false;
144
+ try {
145
+ for (;;) {
146
+ const chunk = await reader.read();
147
+ if (chunk.done) {
148
+ if (!ended && !signal.aborted) yield {
149
+ error: network,
150
+ type: "error"
151
+ };
152
+ return;
153
+ }
154
+ buffer += chunk.value;
155
+ let end = buffer.indexOf("\n\n");
156
+ while (end !== -1) {
157
+ const frame = buffer.slice(0, end);
158
+ buffer = buffer.slice(end + 2);
159
+ const data = frame.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
160
+ const event = data === "" ? null : parseSessionEvent(data);
161
+ if (event !== null) {
162
+ ended ||= event.type !== "program";
163
+ yield event;
164
+ }
165
+ end = buffer.indexOf("\n\n");
166
+ }
167
+ }
168
+ } catch {
169
+ if (!signal.aborted) yield {
170
+ error: network,
171
+ type: "error"
172
+ };
173
+ } finally {
174
+ reader.releaseLock();
175
+ }
176
+ }
177
+ };
178
+ }
179
+ function parseRequiresAction(value) {
180
+ return typeof value === "object" && value !== null && "message" in value && "token" in value && typeof value.message === "string" && typeof value.token === "string" ? {
181
+ message: value.message,
182
+ token: value.token
183
+ } : null;
184
+ }
185
+ /** The `{ code, message }` of anything a transport rejected with. */
186
+ function errorDataOf(cause) {
187
+ return thrownErrorData(cause) ?? unavailable;
188
+ }
189
+ /** The `{ code, message }` that `cause` carries, or null. */
190
+ function thrownErrorData(cause) {
191
+ return typeof cause === "object" && cause !== null ? parseErrorData({
192
+ code: "code" in cause ? cause.code : void 0,
193
+ message: "message" in cause ? cause.message : void 0
194
+ }) : null;
195
+ }
196
+ //#endregion
197
+ export { TransportError, errorDataOf, httpTransport };
package/package.json CHANGED
@@ -1,6 +1,31 @@
1
1
  {
2
2
  "name": "@jigs.design/client",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "createPickleClient: the browser's transport and query cache. No React.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/yoamomonstruos/pickle.git",
9
+ "directory": "packages/client"
10
+ },
11
+ "type": "module",
12
+ "sideEffects": false,
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "@tanstack/query-core": "5.104.4",
29
+ "@jigs.design/runtime": "0.1.0"
30
+ }
6
31
  }