@sylphx/lens-solid 2.1.0 → 2.1.2

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/dist/create.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @sylphx/lens-solid - Create Client
3
3
  *
4
4
  * Creates a typed Lens client with SolidJS primitives.
5
- * Each endpoint can be called directly as a primitive or via .fetch() for promises.
5
+ * Base client methods work in vanilla JS, primitives are extensions.
6
6
  *
7
7
  * @example
8
8
  * ```tsx
@@ -15,18 +15,20 @@
15
15
  * transport: httpTransport({ url: '/api/lens' }),
16
16
  * });
17
17
  *
18
- * // In component
19
- * const { data, loading } = client.user.get({ input: { id } });
18
+ * // Vanilla JS (anywhere - SSR, utilities, event handlers)
19
+ * const user = await client.user.get({ input: { id } });
20
+ * client.user.get({ input: { id } }).subscribe(data => console.log(data));
20
21
  *
21
- * // In SSR
22
- * const user = await client.user.get.fetch({ input: { id } });
22
+ * // SolidJS primitives (in components)
23
+ * const { data, loading } = client.user.get.createQuery({ input: { id } });
24
+ * const { mutate, loading } = client.user.create.createMutation();
23
25
  * ```
24
26
  */
25
- import { type LensClientConfig, type SelectionObject, type TypedClientConfig } from "@sylphx/lens-client";
27
+ import { type LensClientConfig, type QueryResult, type SelectionObject, type TypedClientConfig } from "@sylphx/lens-client";
26
28
  import type { MutationDef, QueryDef, RouterDef, RouterRoutes } from "@sylphx/lens-core";
27
29
  import { type Accessor } from "solid-js";
28
- /** Query hook options */
29
- export interface QueryHookOptions<TInput> {
30
+ /** Query primitive options */
31
+ export interface QueryPrimitiveOptions<TInput> {
30
32
  /** Query input parameters */
31
33
  input?: TInput;
32
34
  /** Field selection */
@@ -34,8 +36,8 @@ export interface QueryHookOptions<TInput> {
34
36
  /** Skip query execution */
35
37
  skip?: boolean;
36
38
  }
37
- /** Query hook result */
38
- export interface QueryHookResult<T> {
39
+ /** Query primitive result */
40
+ export interface QueryPrimitiveResult<T> {
39
41
  /** Reactive data accessor */
40
42
  data: Accessor<T | null>;
41
43
  /** Reactive loading state */
@@ -45,8 +47,8 @@ export interface QueryHookResult<T> {
45
47
  /** Refetch the query */
46
48
  refetch: () => void;
47
49
  }
48
- /** Mutation hook options */
49
- export interface MutationHookOptions<TOutput> {
50
+ /** Mutation primitive options */
51
+ export interface MutationPrimitiveOptions<TOutput> {
50
52
  /** Called on successful mutation */
51
53
  onSuccess?: (data: TOutput) => void;
52
54
  /** Called on mutation error */
@@ -54,8 +56,8 @@ export interface MutationHookOptions<TOutput> {
54
56
  /** Called when mutation settles (success or error) */
55
57
  onSettled?: () => void;
56
58
  }
57
- /** Mutation hook result */
58
- export interface MutationHookResult<TInput, TOutput> {
59
+ /** Mutation primitive result */
60
+ export interface MutationPrimitiveResult<TInput, TOutput> {
59
61
  /** Execute the mutation */
60
62
  mutate: (options: {
61
63
  input: TInput;
@@ -70,28 +72,27 @@ export interface MutationHookResult<TInput, TOutput> {
70
72
  /** Reset mutation state */
71
73
  reset: () => void;
72
74
  }
73
- /** Query endpoint type */
75
+ /** Query endpoint with SolidJS primitives */
74
76
  export interface QueryEndpoint<TInput, TOutput> {
75
- /** Primitive call (in component) */
76
- <_TSelect extends SelectionObject = Record<string, never>>(options: TInput extends void ? QueryHookOptions<void> | void : QueryHookOptions<TInput>): QueryHookResult<TOutput>;
77
- /** Promise call (SSR) */
78
- fetch: <TSelect extends SelectionObject = Record<string, never>>(options: TInput extends void ? {
79
- input?: void;
80
- select?: TSelect;
81
- } | void : {
82
- input: TInput;
83
- select?: TSelect;
84
- }) => Promise<TOutput>;
77
+ /** Vanilla JS call - returns QueryResult (Promise + Observable) */
78
+ (options?: {
79
+ input?: TInput;
80
+ select?: SelectionObject;
81
+ }): QueryResult<TOutput>;
82
+ /** SolidJS primitive for reactive queries */
83
+ createQuery: (options?: TInput extends void ? QueryPrimitiveOptions<void> | void : QueryPrimitiveOptions<TInput>) => QueryPrimitiveResult<TOutput>;
85
84
  }
86
- /** Mutation endpoint type */
85
+ /** Mutation endpoint with SolidJS primitives */
87
86
  export interface MutationEndpoint<TInput, TOutput> {
88
- /** Primitive call (in component) */
89
- (options?: MutationHookOptions<TOutput>): MutationHookResult<TInput, TOutput>;
90
- /** Promise call (SSR) */
91
- fetch: <TSelect extends SelectionObject = Record<string, never>>(options: {
87
+ /** Vanilla JS call - returns Promise */
88
+ (options: {
92
89
  input: TInput;
93
- select?: TSelect;
94
- }) => Promise<TOutput>;
90
+ select?: SelectionObject;
91
+ }): Promise<{
92
+ data: TOutput;
93
+ }>;
94
+ /** SolidJS primitive for mutations */
95
+ createMutation: (options?: MutationPrimitiveOptions<TOutput>) => MutationPrimitiveResult<TInput, TOutput>;
95
96
  }
96
97
  /** Infer client type from router routes */
97
98
  type InferTypedClient<TRoutes extends RouterRoutes> = {
@@ -102,9 +103,8 @@ export type TypedClient<TRouter extends RouterDef> = TRouter extends RouterDef<i
102
103
  /**
103
104
  * Create a Lens client with SolidJS primitives.
104
105
  *
105
- * Each endpoint can be called:
106
- * - Directly as a primitive: `client.user.get({ input: { id } })`
107
- * - Via .fetch() for promises: `await client.user.get.fetch({ input: { id } })`
106
+ * Base client methods work in vanilla JS (SSR, utilities, event handlers).
107
+ * SolidJS primitives are available as `.createQuery()` and `.createMutation()`.
108
108
  *
109
109
  * @example
110
110
  * ```tsx
@@ -117,14 +117,16 @@ export type TypedClient<TRouter extends RouterDef> = TRouter extends RouterDef<i
117
117
  * transport: httpTransport({ url: '/api/lens' }),
118
118
  * });
119
119
  *
120
+ * // Vanilla JS (anywhere)
121
+ * const user = await client.user.get({ input: { id } });
122
+ *
120
123
  * // Component usage
121
124
  * function UserProfile(props: { id: string }) {
122
- * const { data, loading, error } = client.user.get({
125
+ * const { data, loading, error } = client.user.get.createQuery({
123
126
  * input: { id: props.id },
124
- * select: { name: true },
125
127
  * });
126
128
  *
127
- * const { mutate, loading: saving } = client.user.update({
129
+ * const { mutate, loading: saving } = client.user.update.createMutation({
128
130
  * onSuccess: () => console.log('Updated!'),
129
131
  * });
130
132
  *
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -15,14 +15,16 @@
15
15
  * transport: httpTransport({ url: '/api/lens' }),
16
16
  * });
17
17
  *
18
- * // Component usage
19
- * const { data, loading } = client.user.get({ input: { id } });
18
+ * // Vanilla JS (anywhere - SSR, utilities, event handlers)
19
+ * const user = await client.user.get({ input: { id } });
20
+ * client.user.get({ input: { id } }).subscribe(data => console.log(data));
20
21
  *
21
- * // SSR usage
22
- * const user = await client.user.get.fetch({ input: { id } });
22
+ * // SolidJS primitives (in components)
23
+ * const { data, loading } = client.user.get.createQuery({ input: { id } });
24
+ * const { mutate } = client.user.create.createMutation();
23
25
  * ```
24
26
  */
25
- export { createClient, type MutationEndpoint, type MutationHookOptions, type MutationHookResult, type QueryEndpoint, type QueryHookOptions, type QueryHookResult, type TypedClient, } from "./create.js";
27
+ export { createClient, type MutationEndpoint, type MutationPrimitiveOptions, type MutationPrimitiveResult, type QueryEndpoint, type QueryPrimitiveOptions, type QueryPrimitiveResult, type TypedClient, } from "./create.js";
26
28
  export { LensProvider, type LensProviderProps, useLensClient } from "./context.js";
27
29
  export { type CreateLazyQueryResult, type CreateMutationResult, type CreateQueryOptions, type CreateQueryResult, createLazyQuery, createMutation, createQuery, type MutationFn, type QueryInput, } from "./primitives.js";
28
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EACN,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,WAAW,GAChB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAMnF,OAAO,EACN,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,eAAe,EAEf,cAAc,EAEd,WAAW,EACX,KAAK,UAAU,EAEf,KAAK,UAAU,GACf,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,OAAO,EACN,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,WAAW,GAChB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAMnF,OAAO,EACN,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,eAAe,EAEf,cAAc,EAEd,WAAW,EACX,KAAK,UAAU,EAEf,KAAK,UAAU,GACf,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -425,10 +425,12 @@ class ClientImpl {
425
425
  }
426
426
  }
427
427
  const resultOrObservable = this.transport.execute(processedOp);
428
+ let result;
428
429
  if (this.isObservable(resultOrObservable)) {
429
- return { data: resultOrObservable };
430
+ result = await this.firstValueFrom(resultOrObservable);
431
+ } else {
432
+ result = await resultOrObservable;
430
433
  }
431
- let result = await resultOrObservable;
432
434
  for (const plugin of this.plugins) {
433
435
  if (plugin.afterResponse) {
434
436
  result = await plugin.afterResponse(result, processedOp);
@@ -453,6 +455,32 @@ class ClientImpl {
453
455
  isObservable(value) {
454
456
  return value !== null && typeof value === "object" && "subscribe" in value && typeof value.subscribe === "function";
455
457
  }
458
+ firstValueFrom(observable) {
459
+ return new Promise((resolve, reject) => {
460
+ let resolved = false;
461
+ const subscription = observable.subscribe({
462
+ next: (value) => {
463
+ if (!resolved) {
464
+ resolved = true;
465
+ subscription.unsubscribe?.();
466
+ resolve(value);
467
+ }
468
+ },
469
+ error: (err) => {
470
+ if (!resolved) {
471
+ resolved = true;
472
+ reject(err);
473
+ }
474
+ },
475
+ complete: () => {
476
+ if (!resolved) {
477
+ resolved = true;
478
+ reject(new Error("Observable completed without emitting a value"));
479
+ }
480
+ }
481
+ });
482
+ });
483
+ }
456
484
  getOperationMeta(path) {
457
485
  if (!this.metadata)
458
486
  return;
@@ -1023,17 +1051,9 @@ class SubscriptionRegistry {
1023
1051
  }
1024
1052
 
1025
1053
  // src/create.ts
1026
- import { createEffect, createSignal, onCleanup } from "solid-js";
1027
- function createQueryHook(baseClient, path) {
1028
- const getEndpoint = (p) => {
1029
- const parts = p.split(".");
1030
- let current = baseClient;
1031
- for (const part of parts) {
1032
- current = current[part];
1033
- }
1034
- return current;
1035
- };
1036
- const useQueryPrimitive = (options) => {
1054
+ import { createSignal, onCleanup } from "solid-js";
1055
+ function createQueryPrimitiveFactory(getEndpoint) {
1056
+ return function createQuery(options) {
1037
1057
  const [data, setData] = createSignal(null);
1038
1058
  const [loading, setLoading] = createSignal(!options?.skip);
1039
1059
  const [error, setError] = createSignal(null);
@@ -1049,7 +1069,7 @@ function createQueryHook(baseClient, path) {
1049
1069
  setError(null);
1050
1070
  return;
1051
1071
  }
1052
- const endpoint = getEndpoint(path);
1072
+ const endpoint = getEndpoint();
1053
1073
  const query = endpoint({ input: options?.input, select: options?.select });
1054
1074
  setLoading(true);
1055
1075
  setError(null);
@@ -1069,10 +1089,6 @@ function createQueryHook(baseClient, path) {
1069
1089
  });
1070
1090
  };
1071
1091
  executeQuery();
1072
- createEffect(() => {
1073
- const _ = JSON.stringify(options);
1074
- executeQuery();
1075
- });
1076
1092
  onCleanup(() => {
1077
1093
  if (unsubscribe) {
1078
1094
  unsubscribe();
@@ -1086,7 +1102,7 @@ function createQueryHook(baseClient, path) {
1086
1102
  }
1087
1103
  setLoading(true);
1088
1104
  setError(null);
1089
- const endpoint = getEndpoint(path);
1105
+ const endpoint = getEndpoint();
1090
1106
  const query = endpoint({ input: options?.input, select: options?.select });
1091
1107
  if (query) {
1092
1108
  unsubscribe = query.subscribe((value) => {
@@ -1106,24 +1122,9 @@ function createQueryHook(baseClient, path) {
1106
1122
  };
1107
1123
  return { data, loading, error, refetch };
1108
1124
  };
1109
- const fetch2 = async (options) => {
1110
- const endpoint = getEndpoint(path);
1111
- const queryResult = endpoint({ input: options?.input, select: options?.select });
1112
- return queryResult.then((data) => data);
1113
- };
1114
- useQueryPrimitive.fetch = fetch2;
1115
- return useQueryPrimitive;
1116
1125
  }
1117
- function createMutationHook(baseClient, path) {
1118
- const getEndpoint = (p) => {
1119
- const parts = p.split(".");
1120
- let current = baseClient;
1121
- for (const part of parts) {
1122
- current = current[part];
1123
- }
1124
- return current;
1125
- };
1126
- const useMutationPrimitive = (hookOptions) => {
1126
+ function createMutationPrimitiveFactory(getEndpoint) {
1127
+ return function createMutation(primitiveOptions) {
1127
1128
  const [data, setData] = createSignal(null);
1128
1129
  const [loading, setLoading] = createSignal(false);
1129
1130
  const [error, setError] = createSignal(null);
@@ -1131,20 +1132,19 @@ function createMutationHook(baseClient, path) {
1131
1132
  setLoading(true);
1132
1133
  setError(null);
1133
1134
  try {
1134
- const endpoint = getEndpoint(path);
1135
+ const endpoint = getEndpoint();
1135
1136
  const result = await endpoint({ input: options.input, select: options.select });
1136
- const mutationResult = result;
1137
- setData(() => mutationResult.data);
1137
+ setData(() => result.data);
1138
1138
  setLoading(false);
1139
- hookOptions?.onSuccess?.(mutationResult.data);
1140
- hookOptions?.onSettled?.();
1141
- return mutationResult.data;
1139
+ primitiveOptions?.onSuccess?.(result.data);
1140
+ primitiveOptions?.onSettled?.();
1141
+ return result.data;
1142
1142
  } catch (err) {
1143
1143
  const mutationError = err instanceof Error ? err : new Error(String(err));
1144
1144
  setError(mutationError);
1145
1145
  setLoading(false);
1146
- hookOptions?.onError?.(mutationError);
1147
- hookOptions?.onSettled?.();
1146
+ primitiveOptions?.onError?.(mutationError);
1147
+ primitiveOptions?.onSettled?.();
1148
1148
  throw mutationError;
1149
1149
  }
1150
1150
  };
@@ -1155,16 +1155,8 @@ function createMutationHook(baseClient, path) {
1155
1155
  };
1156
1156
  return { mutate, loading, error, data, reset };
1157
1157
  };
1158
- const fetch2 = async (options) => {
1159
- const endpoint = getEndpoint(path);
1160
- const result = await endpoint({ input: options.input, select: options.select });
1161
- const mutationResult = result;
1162
- return mutationResult.data;
1163
- };
1164
- useMutationPrimitive.fetch = fetch2;
1165
- return useMutationPrimitive;
1166
1158
  }
1167
- var hookCache = new Map;
1159
+ var primitiveCache = new Map;
1168
1160
  function createClient2(config) {
1169
1161
  const baseClient = createClient(config);
1170
1162
  function createProxy(path) {
@@ -1173,21 +1165,35 @@ function createClient2(config) {
1173
1165
  if (typeof prop === "symbol")
1174
1166
  return;
1175
1167
  const key = prop;
1176
- if (key === "fetch") {
1177
- return async (options) => {
1178
- const parts = path.split(".");
1179
- let current = baseClient;
1180
- for (const part of parts) {
1181
- current = current[part];
1182
- }
1183
- const endpointFn = current;
1184
- const queryResult = endpointFn(options);
1185
- const result = await queryResult;
1186
- if (result && typeof result === "object" && "data" in result && Object.keys(result).length === 1) {
1187
- return result.data;
1188
- }
1189
- return result;
1190
- };
1168
+ if (key === "createQuery") {
1169
+ const cacheKey = `${path}:createQuery`;
1170
+ if (!primitiveCache.has(cacheKey)) {
1171
+ const getEndpoint = () => {
1172
+ const parts = path.split(".");
1173
+ let current = baseClient;
1174
+ for (const part of parts) {
1175
+ current = current[part];
1176
+ }
1177
+ return current;
1178
+ };
1179
+ primitiveCache.set(cacheKey, createQueryPrimitiveFactory(getEndpoint));
1180
+ }
1181
+ return primitiveCache.get(cacheKey);
1182
+ }
1183
+ if (key === "createMutation") {
1184
+ const cacheKey = `${path}:createMutation`;
1185
+ if (!primitiveCache.has(cacheKey)) {
1186
+ const getEndpoint = () => {
1187
+ const parts = path.split(".");
1188
+ let current = baseClient;
1189
+ for (const part of parts) {
1190
+ current = current[part];
1191
+ }
1192
+ return current;
1193
+ };
1194
+ primitiveCache.set(cacheKey, createMutationPrimitiveFactory(getEndpoint));
1195
+ }
1196
+ return primitiveCache.get(cacheKey);
1191
1197
  }
1192
1198
  if (key === "then")
1193
1199
  return;
@@ -1197,33 +1203,17 @@ function createClient2(config) {
1197
1203
  return createProxy(newPath);
1198
1204
  },
1199
1205
  apply(_target, _thisArg, args) {
1200
- const options = args[0];
1201
- const isQueryOptions = options && (("input" in options) || ("select" in options) || ("skip" in options));
1202
- const isMutationOptions = !options || !isQueryOptions && (Object.keys(options).length === 0 || ("onSuccess" in options) || ("onError" in options) || ("onSettled" in options));
1203
- const cacheKeyQuery = `${path}:query`;
1204
- const cacheKeyMutation = `${path}:mutation`;
1205
- if (isQueryOptions) {
1206
- if (!hookCache.has(cacheKeyQuery)) {
1207
- hookCache.set(cacheKeyQuery, createQueryHook(baseClient, path));
1208
- }
1209
- const hook2 = hookCache.get(cacheKeyQuery);
1210
- return hook2(options);
1206
+ const parts = path.split(".");
1207
+ let current = baseClient;
1208
+ for (const part of parts) {
1209
+ current = current[part];
1211
1210
  }
1212
- if (isMutationOptions) {
1213
- if (!hookCache.has(cacheKeyMutation)) {
1214
- hookCache.set(cacheKeyMutation, createMutationHook(baseClient, path));
1215
- }
1216
- const hook2 = hookCache.get(cacheKeyMutation);
1217
- return hook2(options);
1218
- }
1219
- if (!hookCache.has(cacheKeyQuery)) {
1220
- hookCache.set(cacheKeyQuery, createQueryHook(baseClient, path));
1221
- }
1222
- const hook = hookCache.get(cacheKeyQuery);
1223
- return hook(options);
1211
+ const endpoint = current;
1212
+ return endpoint(args[0]);
1224
1213
  }
1225
1214
  };
1226
- return new Proxy(() => {}, handler);
1215
+ const proxy = new Proxy(() => {}, handler);
1216
+ return proxy;
1227
1217
  }
1228
1218
  return createProxy("");
1229
1219
  }
@@ -1243,7 +1233,7 @@ function useLensClient() {
1243
1233
  return client;
1244
1234
  }
1245
1235
  // src/primitives.ts
1246
- import { createEffect as createEffect2, createSignal as createSignal2, onCleanup as onCleanup2 } from "solid-js";
1236
+ import { createEffect, createSignal as createSignal2, onCleanup as onCleanup2 } from "solid-js";
1247
1237
  function resolveQuery(input) {
1248
1238
  return typeof input === "function" ? input() : input;
1249
1239
  }
@@ -1282,7 +1272,7 @@ function createQuery(queryInput, options) {
1282
1272
  };
1283
1273
  const initialQuery = resolveQuery(queryInput);
1284
1274
  executeQuery(initialQuery);
1285
- createEffect2(() => {
1275
+ createEffect(() => {
1286
1276
  const queryResult = resolveQuery(queryInput);
1287
1277
  if (queryResult !== initialQuery) {
1288
1278
  executeQuery(queryResult);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylphx/lens-solid",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "SolidJS bindings for Lens API framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -31,8 +31,8 @@
31
31
  "author": "SylphxAI",
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@sylphx/lens-client": "^2.1.0",
35
- "@sylphx/lens-core": "^2.0.1"
34
+ "@sylphx/lens-client": "^2.2.1",
35
+ "@sylphx/lens-core": "^2.2.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "solid-js": ">=1.8.0"
package/src/create.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @sylphx/lens-solid - Create Client
3
3
  *
4
4
  * Creates a typed Lens client with SolidJS primitives.
5
- * Each endpoint can be called directly as a primitive or via .fetch() for promises.
5
+ * Base client methods work in vanilla JS, primitives are extensions.
6
6
  *
7
7
  * @example
8
8
  * ```tsx
@@ -15,11 +15,13 @@
15
15
  * transport: httpTransport({ url: '/api/lens' }),
16
16
  * });
17
17
  *
18
- * // In component
19
- * const { data, loading } = client.user.get({ input: { id } });
18
+ * // Vanilla JS (anywhere - SSR, utilities, event handlers)
19
+ * const user = await client.user.get({ input: { id } });
20
+ * client.user.get({ input: { id } }).subscribe(data => console.log(data));
20
21
  *
21
- * // In SSR
22
- * const user = await client.user.get.fetch({ input: { id } });
22
+ * // SolidJS primitives (in components)
23
+ * const { data, loading } = client.user.get.createQuery({ input: { id } });
24
+ * const { mutate, loading } = client.user.create.createMutation();
23
25
  * ```
24
26
  */
25
27
 
@@ -31,14 +33,14 @@ import {
31
33
  type TypedClientConfig,
32
34
  } from "@sylphx/lens-client";
33
35
  import type { MutationDef, QueryDef, RouterDef, RouterRoutes } from "@sylphx/lens-core";
34
- import { type Accessor, createEffect, createSignal, onCleanup } from "solid-js";
36
+ import { type Accessor, createSignal, onCleanup } from "solid-js";
35
37
 
36
38
  // =============================================================================
37
39
  // Types
38
40
  // =============================================================================
39
41
 
40
- /** Query hook options */
41
- export interface QueryHookOptions<TInput> {
42
+ /** Query primitive options */
43
+ export interface QueryPrimitiveOptions<TInput> {
42
44
  /** Query input parameters */
43
45
  input?: TInput;
44
46
  /** Field selection */
@@ -47,8 +49,8 @@ export interface QueryHookOptions<TInput> {
47
49
  skip?: boolean;
48
50
  }
49
51
 
50
- /** Query hook result */
51
- export interface QueryHookResult<T> {
52
+ /** Query primitive result */
53
+ export interface QueryPrimitiveResult<T> {
52
54
  /** Reactive data accessor */
53
55
  data: Accessor<T | null>;
54
56
  /** Reactive loading state */
@@ -59,8 +61,8 @@ export interface QueryHookResult<T> {
59
61
  refetch: () => void;
60
62
  }
61
63
 
62
- /** Mutation hook options */
63
- export interface MutationHookOptions<TOutput> {
64
+ /** Mutation primitive options */
65
+ export interface MutationPrimitiveOptions<TOutput> {
64
66
  /** Called on successful mutation */
65
67
  onSuccess?: (data: TOutput) => void;
66
68
  /** Called on mutation error */
@@ -69,8 +71,8 @@ export interface MutationHookOptions<TOutput> {
69
71
  onSettled?: () => void;
70
72
  }
71
73
 
72
- /** Mutation hook result */
73
- export interface MutationHookResult<TInput, TOutput> {
74
+ /** Mutation primitive result */
75
+ export interface MutationPrimitiveResult<TInput, TOutput> {
74
76
  /** Execute the mutation */
75
77
  mutate: (options: { input: TInput; select?: SelectionObject }) => Promise<TOutput>;
76
78
  /** Reactive loading state */
@@ -83,31 +85,28 @@ export interface MutationHookResult<TInput, TOutput> {
83
85
  reset: () => void;
84
86
  }
85
87
 
86
- /** Query endpoint type */
88
+ /** Query endpoint with SolidJS primitives */
87
89
  export interface QueryEndpoint<TInput, TOutput> {
88
- /** Primitive call (in component) */
89
- <_TSelect extends SelectionObject = Record<string, never>>(
90
- options: TInput extends void ? QueryHookOptions<void> | void : QueryHookOptions<TInput>,
91
- ): QueryHookResult<TOutput>;
92
-
93
- /** Promise call (SSR) */
94
- fetch: <TSelect extends SelectionObject = Record<string, never>>(
95
- options: TInput extends void
96
- ? { input?: void; select?: TSelect } | void
97
- : { input: TInput; select?: TSelect },
98
- ) => Promise<TOutput>;
90
+ /** Vanilla JS call - returns QueryResult (Promise + Observable) */
91
+ (options?: { input?: TInput; select?: SelectionObject }): QueryResult<TOutput>;
92
+
93
+ /** SolidJS primitive for reactive queries */
94
+ createQuery: (
95
+ options?: TInput extends void
96
+ ? QueryPrimitiveOptions<void> | void
97
+ : QueryPrimitiveOptions<TInput>,
98
+ ) => QueryPrimitiveResult<TOutput>;
99
99
  }
100
100
 
101
- /** Mutation endpoint type */
101
+ /** Mutation endpoint with SolidJS primitives */
102
102
  export interface MutationEndpoint<TInput, TOutput> {
103
- /** Primitive call (in component) */
104
- (options?: MutationHookOptions<TOutput>): MutationHookResult<TInput, TOutput>;
105
-
106
- /** Promise call (SSR) */
107
- fetch: <TSelect extends SelectionObject = Record<string, never>>(options: {
108
- input: TInput;
109
- select?: TSelect;
110
- }) => Promise<TOutput>;
103
+ /** Vanilla JS call - returns Promise */
104
+ (options: { input: TInput; select?: SelectionObject }): Promise<{ data: TOutput }>;
105
+
106
+ /** SolidJS primitive for mutations */
107
+ createMutation: (
108
+ options?: MutationPrimitiveOptions<TOutput>,
109
+ ) => MutationPrimitiveResult<TInput, TOutput>;
111
110
  }
112
111
 
113
112
  /** Infer client type from router routes */
@@ -126,26 +125,18 @@ export type TypedClient<TRouter extends RouterDef> =
126
125
  TRouter extends RouterDef<infer TRoutes> ? InferTypedClient<TRoutes> : never;
127
126
 
128
127
  // =============================================================================
129
- // Hook Factories
128
+ // Primitive Factories
130
129
  // =============================================================================
131
130
 
132
131
  /**
133
- * Create a query primitive for a specific endpoint
132
+ * Create createQuery primitive for a specific endpoint
134
133
  */
135
- function createQueryHook<TInput, TOutput>(
136
- baseClient: unknown,
137
- path: string,
138
- ): QueryEndpoint<TInput, TOutput> {
139
- const getEndpoint = (p: string) => {
140
- const parts = p.split(".");
141
- let current: unknown = baseClient;
142
- for (const part of parts) {
143
- current = (current as Record<string, unknown>)[part];
144
- }
145
- return current as (options: unknown) => QueryResult<TOutput>;
146
- };
147
-
148
- const useQueryPrimitive = (options?: QueryHookOptions<TInput>): QueryHookResult<TOutput> => {
134
+ function createQueryPrimitiveFactory<TInput, TOutput>(
135
+ getEndpoint: () => (options: unknown) => QueryResult<TOutput>,
136
+ ) {
137
+ return function createQuery(
138
+ options?: QueryPrimitiveOptions<TInput>,
139
+ ): QueryPrimitiveResult<TOutput> {
149
140
  const [data, setData] = createSignal<TOutput | null>(null);
150
141
  const [loading, setLoading] = createSignal(!options?.skip);
151
142
  const [error, setError] = createSignal<Error | null>(null);
@@ -165,7 +156,7 @@ function createQueryHook<TInput, TOutput>(
165
156
  return;
166
157
  }
167
158
 
168
- const endpoint = getEndpoint(path);
159
+ const endpoint = getEndpoint();
169
160
  const query = endpoint({ input: options?.input, select: options?.select });
170
161
 
171
162
  setLoading(true);
@@ -191,16 +182,9 @@ function createQueryHook<TInput, TOutput>(
191
182
  );
192
183
  };
193
184
 
194
- // Execute initial query synchronously
185
+ // Execute initial query
195
186
  executeQuery();
196
187
 
197
- // Use createEffect for reactive updates when options change
198
- createEffect(() => {
199
- // Access options to track them (Solid will re-run when they change)
200
- const _ = JSON.stringify(options);
201
- executeQuery();
202
- });
203
-
204
188
  onCleanup(() => {
205
189
  if (unsubscribe) {
206
190
  unsubscribe();
@@ -215,7 +199,7 @@ function createQueryHook<TInput, TOutput>(
215
199
  }
216
200
  setLoading(true);
217
201
  setError(null);
218
- const endpoint = getEndpoint(path);
202
+ const endpoint = getEndpoint();
219
203
  const query = endpoint({ input: options?.input, select: options?.select });
220
204
  if (query) {
221
205
  unsubscribe = query.subscribe((value) => {
@@ -239,42 +223,17 @@ function createQueryHook<TInput, TOutput>(
239
223
 
240
224
  return { data, loading, error, refetch };
241
225
  };
242
-
243
- // Fetch method for promises (SSR)
244
- const fetch = async (options?: {
245
- input?: TInput;
246
- select?: SelectionObject;
247
- }): Promise<TOutput> => {
248
- const endpoint = getEndpoint(path);
249
- const queryResult = endpoint({ input: options?.input, select: options?.select });
250
- return queryResult.then((data) => data);
251
- };
252
-
253
- // Attach fetch method to the hook function
254
- useQueryPrimitive.fetch = fetch;
255
-
256
- return useQueryPrimitive as unknown as QueryEndpoint<TInput, TOutput>;
257
226
  }
258
227
 
259
228
  /**
260
- * Create a mutation primitive for a specific endpoint
229
+ * Create createMutation primitive for a specific endpoint
261
230
  */
262
- function createMutationHook<TInput, TOutput>(
263
- baseClient: unknown,
264
- path: string,
265
- ): MutationEndpoint<TInput, TOutput> {
266
- const getEndpoint = (p: string) => {
267
- const parts = p.split(".");
268
- let current: unknown = baseClient;
269
- for (const part of parts) {
270
- current = (current as Record<string, unknown>)[part];
271
- }
272
- return current as (options: unknown) => QueryResult<{ data: TOutput }>;
273
- };
274
-
275
- const useMutationPrimitive = (
276
- hookOptions?: MutationHookOptions<TOutput>,
277
- ): MutationHookResult<TInput, TOutput> => {
231
+ function createMutationPrimitiveFactory<TInput, TOutput>(
232
+ getEndpoint: () => (options: unknown) => Promise<{ data: TOutput }>,
233
+ ) {
234
+ return function createMutation(
235
+ primitiveOptions?: MutationPrimitiveOptions<TOutput>,
236
+ ): MutationPrimitiveResult<TInput, TOutput> {
278
237
  const [data, setData] = createSignal<TOutput | null>(null);
279
238
  const [loading, setLoading] = createSignal(false);
280
239
  const [error, setError] = createSignal<Error | null>(null);
@@ -287,24 +246,23 @@ function createMutationHook<TInput, TOutput>(
287
246
  setError(null);
288
247
 
289
248
  try {
290
- const endpoint = getEndpoint(path);
249
+ const endpoint = getEndpoint();
291
250
  const result = await endpoint({ input: options.input, select: options.select });
292
- const mutationResult = result as unknown as { data: TOutput };
293
251
 
294
- setData(() => mutationResult.data);
252
+ setData(() => result.data);
295
253
  setLoading(false);
296
254
 
297
- hookOptions?.onSuccess?.(mutationResult.data);
298
- hookOptions?.onSettled?.();
255
+ primitiveOptions?.onSuccess?.(result.data);
256
+ primitiveOptions?.onSettled?.();
299
257
 
300
- return mutationResult.data;
258
+ return result.data;
301
259
  } catch (err) {
302
260
  const mutationError = err instanceof Error ? err : new Error(String(err));
303
261
  setError(mutationError);
304
262
  setLoading(false);
305
263
 
306
- hookOptions?.onError?.(mutationError);
307
- hookOptions?.onSettled?.();
264
+ primitiveOptions?.onError?.(mutationError);
265
+ primitiveOptions?.onSettled?.();
308
266
 
309
267
  throw mutationError;
310
268
  }
@@ -318,34 +276,20 @@ function createMutationHook<TInput, TOutput>(
318
276
 
319
277
  return { mutate, loading, error, data, reset };
320
278
  };
321
-
322
- // Fetch method for promises (SSR)
323
- const fetch = async (options: { input: TInput; select?: SelectionObject }): Promise<TOutput> => {
324
- const endpoint = getEndpoint(path);
325
- const result = await endpoint({ input: options.input, select: options.select });
326
- const mutationResult = result as unknown as { data: TOutput };
327
- return mutationResult.data;
328
- };
329
-
330
- // Attach fetch method to the hook function
331
- useMutationPrimitive.fetch = fetch;
332
-
333
- return useMutationPrimitive as unknown as MutationEndpoint<TInput, TOutput>;
334
279
  }
335
280
 
336
281
  // =============================================================================
337
282
  // Create Client
338
283
  // =============================================================================
339
284
 
340
- // Cache for hook functions
341
- const hookCache = new Map<string, unknown>();
285
+ // Cache for primitive functions to ensure stable references
286
+ const primitiveCache = new Map<string, unknown>();
342
287
 
343
288
  /**
344
289
  * Create a Lens client with SolidJS primitives.
345
290
  *
346
- * Each endpoint can be called:
347
- * - Directly as a primitive: `client.user.get({ input: { id } })`
348
- * - Via .fetch() for promises: `await client.user.get.fetch({ input: { id } })`
291
+ * Base client methods work in vanilla JS (SSR, utilities, event handlers).
292
+ * SolidJS primitives are available as `.createQuery()` and `.createMutation()`.
349
293
  *
350
294
  * @example
351
295
  * ```tsx
@@ -358,14 +302,16 @@ const hookCache = new Map<string, unknown>();
358
302
  * transport: httpTransport({ url: '/api/lens' }),
359
303
  * });
360
304
  *
305
+ * // Vanilla JS (anywhere)
306
+ * const user = await client.user.get({ input: { id } });
307
+ *
361
308
  * // Component usage
362
309
  * function UserProfile(props: { id: string }) {
363
- * const { data, loading, error } = client.user.get({
310
+ * const { data, loading, error } = client.user.get.createQuery({
364
311
  * input: { id: props.id },
365
- * select: { name: true },
366
312
  * });
367
313
  *
368
- * const { mutate, loading: saving } = client.user.update({
314
+ * const { mutate, loading: saving } = client.user.update.createMutation({
369
315
  * onSuccess: () => console.log('Updated!'),
370
316
  * });
371
317
  *
@@ -386,6 +332,7 @@ const hookCache = new Map<string, unknown>();
386
332
  export function createClient<TRouter extends RouterDef>(
387
333
  config: LensClientConfig | TypedClientConfig<{ router: TRouter }>,
388
334
  ): TypedClient<TRouter> {
335
+ // Create base client for transport
389
336
  const baseClient = createBaseClient(config as LensClientConfig);
390
337
 
391
338
  function createProxy(path: string): unknown {
@@ -394,27 +341,38 @@ export function createClient<TRouter extends RouterDef>(
394
341
  if (typeof prop === "symbol") return undefined;
395
342
  const key = prop as string;
396
343
 
397
- if (key === "fetch") {
398
- return async (options: unknown) => {
399
- const parts = path.split(".");
400
- let current: unknown = baseClient;
401
- for (const part of parts) {
402
- current = (current as Record<string, unknown>)[part];
403
- }
404
- const endpointFn = current as (opts: unknown) => QueryResult<unknown>;
405
- const queryResult = endpointFn(options);
406
- const result = await queryResult;
407
-
408
- if (
409
- result &&
410
- typeof result === "object" &&
411
- "data" in result &&
412
- Object.keys(result).length === 1
413
- ) {
414
- return (result as { data: unknown }).data;
415
- }
416
- return result;
417
- };
344
+ // Handle .createQuery() - SolidJS primitive for queries
345
+ if (key === "createQuery") {
346
+ const cacheKey = `${path}:createQuery`;
347
+ if (!primitiveCache.has(cacheKey)) {
348
+ const getEndpoint = () => {
349
+ const parts = path.split(".");
350
+ let current: unknown = baseClient;
351
+ for (const part of parts) {
352
+ current = (current as Record<string, unknown>)[part];
353
+ }
354
+ return current as (options: unknown) => QueryResult<unknown>;
355
+ };
356
+ primitiveCache.set(cacheKey, createQueryPrimitiveFactory(getEndpoint));
357
+ }
358
+ return primitiveCache.get(cacheKey);
359
+ }
360
+
361
+ // Handle .createMutation() - SolidJS primitive for mutations
362
+ if (key === "createMutation") {
363
+ const cacheKey = `${path}:createMutation`;
364
+ if (!primitiveCache.has(cacheKey)) {
365
+ const getEndpoint = () => {
366
+ const parts = path.split(".");
367
+ let current: unknown = baseClient;
368
+ for (const part of parts) {
369
+ current = (current as Record<string, unknown>)[part];
370
+ }
371
+ return current as (options: unknown) => Promise<{ data: unknown }>;
372
+ };
373
+ primitiveCache.set(cacheKey, createMutationPrimitiveFactory(getEndpoint));
374
+ }
375
+ return primitiveCache.get(cacheKey);
418
376
  }
419
377
 
420
378
  if (key === "then") return undefined;
@@ -425,47 +383,19 @@ export function createClient<TRouter extends RouterDef>(
425
383
  },
426
384
 
427
385
  apply(_target, _thisArg, args) {
428
- const options = args[0] as Record<string, unknown> | undefined;
429
-
430
- const isQueryOptions =
431
- options && ("input" in options || "select" in options || "skip" in options);
432
-
433
- const isMutationOptions =
434
- !options ||
435
- (!isQueryOptions &&
436
- (Object.keys(options).length === 0 ||
437
- "onSuccess" in options ||
438
- "onError" in options ||
439
- "onSettled" in options));
440
-
441
- const cacheKeyQuery = `${path}:query`;
442
- const cacheKeyMutation = `${path}:mutation`;
443
-
444
- if (isQueryOptions) {
445
- if (!hookCache.has(cacheKeyQuery)) {
446
- hookCache.set(cacheKeyQuery, createQueryHook(baseClient, path));
447
- }
448
- const hook = hookCache.get(cacheKeyQuery) as (opts: unknown) => unknown;
449
- return hook(options);
450
- }
451
-
452
- if (isMutationOptions) {
453
- if (!hookCache.has(cacheKeyMutation)) {
454
- hookCache.set(cacheKeyMutation, createMutationHook(baseClient, path));
455
- }
456
- const hook = hookCache.get(cacheKeyMutation) as (opts: unknown) => unknown;
457
- return hook(options);
458
- }
459
-
460
- if (!hookCache.has(cacheKeyQuery)) {
461
- hookCache.set(cacheKeyQuery, createQueryHook(baseClient, path));
386
+ // Direct call - delegate to base client (returns QueryResult or Promise)
387
+ const parts = path.split(".");
388
+ let current: unknown = baseClient;
389
+ for (const part of parts) {
390
+ current = (current as Record<string, unknown>)[part];
462
391
  }
463
- const hook = hookCache.get(cacheKeyQuery) as (opts: unknown) => unknown;
464
- return hook(options);
392
+ const endpoint = current as (options: unknown) => unknown;
393
+ return endpoint(args[0]);
465
394
  },
466
395
  };
467
396
 
468
- return new Proxy((() => {}) as (...args: unknown[]) => unknown, handler);
397
+ const proxy = new Proxy((() => {}) as (...args: unknown[]) => unknown, handler);
398
+ return proxy;
469
399
  }
470
400
 
471
401
  return createProxy("") as TypedClient<TRouter>;
package/src/index.ts CHANGED
@@ -15,11 +15,13 @@
15
15
  * transport: httpTransport({ url: '/api/lens' }),
16
16
  * });
17
17
  *
18
- * // Component usage
19
- * const { data, loading } = client.user.get({ input: { id } });
18
+ * // Vanilla JS (anywhere - SSR, utilities, event handlers)
19
+ * const user = await client.user.get({ input: { id } });
20
+ * client.user.get({ input: { id } }).subscribe(data => console.log(data));
20
21
  *
21
- * // SSR usage
22
- * const user = await client.user.get.fetch({ input: { id } });
22
+ * // SolidJS primitives (in components)
23
+ * const { data, loading } = client.user.get.createQuery({ input: { id } });
24
+ * const { mutate } = client.user.create.createMutation();
23
25
  * ```
24
26
  */
25
27
 
@@ -30,11 +32,11 @@
30
32
  export {
31
33
  createClient,
32
34
  type MutationEndpoint,
33
- type MutationHookOptions,
34
- type MutationHookResult,
35
+ type MutationPrimitiveOptions,
36
+ type MutationPrimitiveResult,
35
37
  type QueryEndpoint,
36
- type QueryHookOptions,
37
- type QueryHookResult,
38
+ type QueryPrimitiveOptions,
39
+ type QueryPrimitiveResult,
38
40
  type TypedClient,
39
41
  } from "./create.js";
40
42