apixa 0.1.0 → 1.0.0-rc.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.
Files changed (186) hide show
  1. package/README.md +57 -13
  2. package/dist/{chunk-QZIU7J3G.js → chunks/chunk-3ZFOEESZ.js} +1 -1
  3. package/dist/{chunk-QVKMZELC.js → chunks/chunk-6WSJJKM6.js} +1 -1
  4. package/dist/{chunk-SIFGLE22.js → chunks/chunk-7U7EGEIJ.js} +43 -14
  5. package/dist/chunks/chunk-BRBSHKI5.js +360 -0
  6. package/dist/{chunk-IAQ5YOVE.js → chunks/chunk-D2GA433L.js} +1 -1
  7. package/dist/{chunk-6ZX7GAWG.js → chunks/chunk-I5JYOAUR.js} +1 -1
  8. package/dist/{chunk-LARJYKRJ.js → chunks/chunk-JM47QQH6.js} +15 -15
  9. package/dist/{chunk-MLPW6EET.js → chunks/chunk-K4ELX7MW.js} +1 -1
  10. package/dist/{chunk-R4FXTZWU.js → chunks/chunk-OO6JF76I.js} +1 -1
  11. package/dist/{chunk-GWZTJ7LM.js → chunks/chunk-RYTQAJRH.js} +177 -175
  12. package/dist/{data-GNCSLYM4.js → chunks/data-4B7QV4F5.js} +1 -1
  13. package/dist/{data-B47EIZXW.js → chunks/data-7ISALG7G.js} +1 -1
  14. package/dist/{data-GTTIEVFI.js → chunks/data-HAGFVAZM.js} +1 -1
  15. package/dist/{data-DL4IKJCX.js → chunks/data-HNAJ5IYV.js} +1 -1
  16. package/dist/chunks/data-WOMFLQWC.js +6 -0
  17. package/dist/chunks/data-ZPXVMWRQ.js +6 -0
  18. package/dist/core.d.ts +1 -0
  19. package/dist/core.js +80 -0
  20. package/dist/index.d.ts +1 -305
  21. package/dist/index.js +11 -25
  22. package/dist/mocking/datasets/comments.d.ts +1 -6
  23. package/dist/mocking/datasets/comments.js +2 -2
  24. package/dist/mocking/datasets/companies.d.ts +1 -6
  25. package/dist/mocking/datasets/companies.js +2 -2
  26. package/dist/mocking/datasets/index.d.ts +1 -18
  27. package/dist/mocking/datasets/index.js +15 -15
  28. package/dist/mocking/datasets/orders.d.ts +1 -6
  29. package/dist/mocking/datasets/orders.js +2 -2
  30. package/dist/mocking/datasets/posts.d.ts +1 -6
  31. package/dist/mocking/datasets/posts.js +2 -2
  32. package/dist/mocking/datasets/products.d.ts +1 -6
  33. package/dist/mocking/datasets/products.js +2 -2
  34. package/dist/mocking/datasets/users.d.ts +1 -6
  35. package/dist/mocking/datasets/users.js +2 -2
  36. package/dist/mocking/index.d.ts +1 -317
  37. package/dist/mocking/index.js +4 -351
  38. package/dist/mocking/node.d.ts +1 -33
  39. package/dist/mocking/node.js +5 -4
  40. package/dist/mocking/register.d.ts +1 -2
  41. package/dist/mocking/register.js +2 -2
  42. package/dist/react/advanced.d.ts +1 -111
  43. package/dist/react/advanced.js +17 -6
  44. package/dist/react/index.d.ts +1 -283
  45. package/dist/react/index.js +29 -7
  46. package/dist/types/packages/core/src/api/client.d.ts +11 -0
  47. package/dist/types/packages/core/src/api/define-api.d.ts +9 -0
  48. package/dist/types/packages/core/src/api/define-apis.d.ts +9 -0
  49. package/dist/types/packages/core/src/api/index.d.ts +3 -0
  50. package/dist/types/packages/core/src/api/metadata.d.ts +32 -0
  51. package/dist/types/packages/core/src/api/reset.d.ts +7 -0
  52. package/dist/types/packages/core/src/api/resource-client.d.ts +20 -0
  53. package/dist/types/packages/core/src/api/validate.d.ts +20 -0
  54. package/dist/types/packages/core/src/errors/abort-error.d.ts +4 -0
  55. package/dist/types/packages/core/src/errors/api-error.d.ts +22 -0
  56. package/dist/types/packages/core/src/errors/config-error.d.ts +5 -0
  57. package/dist/types/packages/core/src/errors/guards.d.ts +8 -0
  58. package/dist/types/packages/core/src/errors/http-error.d.ts +8 -0
  59. package/dist/types/packages/core/src/errors/index.d.ts +13 -0
  60. package/dist/types/packages/core/src/errors/mock-error.d.ts +10 -0
  61. package/dist/types/packages/core/src/errors/network-error.d.ts +4 -0
  62. package/dist/types/packages/core/src/errors/parse-error.d.ts +4 -0
  63. package/dist/types/packages/core/src/errors/security-error.d.ts +5 -0
  64. package/dist/types/packages/core/src/errors/timeout-error.d.ts +4 -0
  65. package/dist/types/packages/core/src/errors/transform-error.d.ts +11 -0
  66. package/dist/types/packages/core/src/errors/validation-error.d.ts +4 -0
  67. package/dist/types/packages/core/src/http/body.d.ts +2 -0
  68. package/dist/types/packages/core/src/http/headers.d.ts +9 -0
  69. package/dist/types/packages/core/src/http/index.d.ts +5 -0
  70. package/dist/types/packages/core/src/http/path.d.ts +6 -0
  71. package/dist/types/packages/core/src/http/query.d.ts +3 -0
  72. package/dist/types/packages/core/src/http/url.d.ts +27 -0
  73. package/dist/types/packages/core/src/index.d.ts +16 -0
  74. package/dist/types/packages/core/src/mock/datasets.d.ts +31 -0
  75. package/dist/types/packages/core/src/mock/execute.d.ts +27 -0
  76. package/dist/types/packages/core/src/mock/handler.d.ts +46 -0
  77. package/dist/types/packages/core/src/mock/index.d.ts +5 -0
  78. package/dist/types/packages/core/src/mock/source.d.ts +21 -0
  79. package/dist/types/packages/core/src/mock/store.d.ts +73 -0
  80. package/dist/types/packages/core/src/operation/args.d.ts +7 -0
  81. package/dist/types/packages/core/src/operation/conventions.d.ts +122 -0
  82. package/dist/types/packages/core/src/operation/expand.d.ts +12 -0
  83. package/dist/types/packages/core/src/operation/index.d.ts +4 -0
  84. package/dist/types/packages/core/src/request/index.d.ts +2 -0
  85. package/dist/types/packages/core/src/request/pipeline.d.ts +95 -0
  86. package/dist/types/packages/core/src/request/retry.d.ts +17 -0
  87. package/dist/types/packages/core/src/transform/index.d.ts +1 -0
  88. package/dist/types/packages/core/src/transform/keys.d.ts +12 -0
  89. package/dist/types/packages/core/src/transport/fetch.d.ts +2 -0
  90. package/dist/types/packages/core/src/transport/index.d.ts +2 -0
  91. package/dist/types/packages/core/src/transport/read-body.d.ts +2 -0
  92. package/dist/types/packages/core/src/types/builtins.d.ts +48 -0
  93. package/dist/types/packages/core/src/types/definition.d.ts +154 -0
  94. package/dist/types/packages/core/src/types/errors.d.ts +20 -0
  95. package/dist/types/packages/core/src/types/http.d.ts +29 -0
  96. package/dist/types/packages/core/src/types/index.d.ts +11 -0
  97. package/dist/types/packages/core/src/types/inference.d.ts +600 -0
  98. package/dist/types/packages/core/src/types/middleware.d.ts +35 -0
  99. package/dist/{mock-datasets-Xa9NXK9n.d.ts → types/packages/core/src/types/mock-datasets.d.ts} +19 -20
  100. package/dist/types/packages/core/src/types/mock-handler.d.ts +54 -0
  101. package/dist/types/packages/core/src/types/retry.d.ts +47 -0
  102. package/dist/types/packages/core/src/types/transform.d.ts +27 -0
  103. package/dist/types/packages/core/src/types/transport.d.ts +79 -0
  104. package/dist/types/packages/core/src/utils/slice.d.ts +12 -0
  105. package/dist/types/packages/internal/shared/src/index.d.ts +4 -0
  106. package/dist/types/packages/internal/shared/src/keys.d.ts +25 -0
  107. package/dist/types/packages/internal/shared/src/operations.d.ts +20 -0
  108. package/dist/types/packages/mocking/src/catalog.d.ts +26 -0
  109. package/dist/types/packages/mocking/src/data/entities.d.ts +5 -0
  110. package/dist/types/packages/mocking/src/dataset-modules/comments.d.ts +4 -0
  111. package/dist/types/packages/mocking/src/dataset-modules/companies.d.ts +4 -0
  112. package/dist/types/packages/mocking/src/dataset-modules/orders.d.ts +4 -0
  113. package/dist/types/packages/mocking/src/dataset-modules/posts.d.ts +4 -0
  114. package/dist/types/packages/mocking/src/dataset-modules/products.d.ts +4 -0
  115. package/dist/types/packages/mocking/src/dataset-modules/users.d.ts +4 -0
  116. package/dist/types/packages/mocking/src/datasets.d.ts +17 -0
  117. package/dist/types/packages/mocking/src/discover.d.ts +3 -0
  118. package/dist/types/packages/mocking/src/errors.d.ts +17 -0
  119. package/dist/types/packages/mocking/src/index.d.ts +19 -0
  120. package/dist/types/packages/mocking/src/load.d.ts +15 -0
  121. package/dist/types/packages/mocking/src/loader.d.ts +16 -0
  122. package/dist/types/packages/mocking/src/mock-api.d.ts +25 -0
  123. package/dist/types/packages/mocking/src/mock-types.d.ts +279 -0
  124. package/dist/types/packages/mocking/src/node.d.ts +8 -0
  125. package/dist/types/packages/mocking/src/paths.d.ts +6 -0
  126. package/dist/types/packages/mocking/src/register.d.ts +1 -0
  127. package/dist/types/packages/mocking/src/registry.d.ts +11 -0
  128. package/dist/types/packages/mocking/src/resource.d.ts +13 -0
  129. package/dist/types/packages/mocking/src/slice.d.ts +16 -0
  130. package/dist/{types-mSoi1qGP.d.ts → types/packages/mocking/src/types.d.ts} +6 -8
  131. package/dist/types/packages/react/src/advanced.d.ts +28 -0
  132. package/dist/types/packages/react/src/cache.d.ts +15 -0
  133. package/dist/types/packages/react/src/compose.d.ts +10 -0
  134. package/dist/types/packages/react/src/controller.d.ts +11 -0
  135. package/dist/types/packages/react/src/hydration-boundary.d.ts +11 -0
  136. package/dist/types/packages/react/src/hydration.d.ts +5 -0
  137. package/dist/types/packages/react/src/index.d.ts +17 -0
  138. package/dist/types/packages/react/src/keys.d.ts +7 -0
  139. package/dist/types/packages/react/src/mutation-controller.d.ts +40 -0
  140. package/dist/types/packages/react/src/mutation-store.d.ts +57 -0
  141. package/dist/types/packages/react/src/mutation-types.d.ts +125 -0
  142. package/dist/types/packages/react/src/optimistic.d.ts +55 -0
  143. package/dist/types/packages/react/src/provider.d.ts +14 -0
  144. package/dist/types/packages/react/src/query-client.d.ts +31 -0
  145. package/dist/types/packages/react/src/query-controller.d.ts +49 -0
  146. package/dist/types/packages/react/src/query-helpers.d.ts +112 -0
  147. package/dist/types/packages/react/src/query-options.d.ts +152 -0
  148. package/dist/types/packages/react/src/types.d.ts +123 -0
  149. package/dist/types/packages/react/src/use-resource-mutation.d.ts +34 -0
  150. package/dist/types/packages/react/src/use-resource-query.d.ts +112 -0
  151. package/dist/types/packages/react/src/use-resource.d.ts +69 -0
  152. package/dist/types/src/core.d.ts +1 -0
  153. package/dist/types/src/index.d.ts +8 -0
  154. package/dist/types/src/mocking/datasets/comments.d.ts +1 -0
  155. package/dist/types/src/mocking/datasets/companies.d.ts +1 -0
  156. package/dist/types/src/mocking/datasets/index.d.ts +1 -0
  157. package/dist/types/src/mocking/datasets/orders.d.ts +1 -0
  158. package/dist/types/src/mocking/datasets/posts.d.ts +1 -0
  159. package/dist/types/src/mocking/datasets/products.d.ts +1 -0
  160. package/dist/types/src/mocking/datasets/users.d.ts +1 -0
  161. package/dist/types/src/mocking/index.d.ts +1 -0
  162. package/dist/types/src/mocking/node.d.ts +1 -0
  163. package/dist/types/src/mocking/register.d.ts +2 -0
  164. package/dist/types/src/react/advanced.d.ts +1 -0
  165. package/dist/types/src/react/index.d.ts +2 -0
  166. package/package.json +36 -21
  167. package/dist/data-JR6F6HSR.js +0 -6
  168. package/dist/data-WRWVXGYD.js +0 -6
  169. package/dist/inference-BGj3DlzE.d.ts +0 -1220
  170. package/dist/loader-hhMdppVZ.d.ts +0 -32
  171. package/dist/mutation-controller-BjCOn42y.d.ts +0 -476
  172. /package/dist/{chunk-WNJUPR6P.js → chunks/chunk-23CRJXIO.js} +0 -0
  173. /package/dist/{chunk-QY5YMHHN.js → chunks/chunk-3RDQXC6Q.js} +0 -0
  174. /package/dist/{chunk-KE7UM4VW.js → chunks/chunk-QPINWJOY.js} +0 -0
  175. /package/dist/{chunk-A3QU5MFP.js → chunks/chunk-SO3IYVYQ.js} +0 -0
  176. /package/dist/{chunk-ZSLMMDUX.js → chunks/chunk-VACVV4XV.js} +0 -0
  177. /package/dist/{chunk-DGSIZXRI.js → chunks/chunk-YZ7TR6HL.js} +0 -0
  178. /package/dist/{data-QF32LRM4.js → chunks/data-544O3O74.js} +0 -0
  179. /package/dist/{data-3HVQ54F3.js → chunks/data-5JYPNNLK.js} +0 -0
  180. /package/dist/{data-ADLKYCN6.js → chunks/data-BLJLBYSL.js} +0 -0
  181. /package/dist/{data-Y6374BIT.js → chunks/data-CJY7V7VX.js} +0 -0
  182. /package/dist/{data-HWX62BTJ.js → chunks/data-CPWQB3IU.js} +0 -0
  183. /package/dist/{data-UIVRJ77R.js → chunks/data-DD3Q7CSO.js} +0 -0
  184. /package/dist/{data-OKVHGTXW.js → chunks/data-MFATSP4G.js} +0 -0
  185. /package/dist/{data-UZVNJUNM.js → chunks/data-MG5JK7PM.js} +0 -0
  186. /package/dist/{data-PQPSE56A.js → chunks/data-YHFBWU6E.js} +0 -0
package/README.md CHANGED
@@ -18,20 +18,63 @@ Working with APIs often means repeating the same patterns across resources and p
18
18
 
19
19
  Apixa aims to reduce this duplication while preserving TypeScript's type safety and flexibility.
20
20
 
21
- ## npm package
21
+ ## Installation
22
22
 
23
- The `apixa` package is prepared for publication but has not been published yet. After publication,
24
- install it with `npm install apixa`. Core has no framework dependency:
23
+ Apixa publishes one npm package: `apixa` (`1.0.0-rc.0`, ESM, Node.js 22+). The RC is prepared
24
+ locally and has not been published. After release, install it with:
25
+
26
+ ```sh
27
+ npm install apixa
28
+ # React applications also install the optional peers:
29
+ npm install apixa react @tanstack/react-query
30
+ ```
25
31
 
26
32
  ```ts
27
- import { defineApi, defineApis } from "apixa";
33
+ import { defineApi, defineApis, defineMockApi } from "apixa";
34
+ import { MockStore } from "apixa/core";
35
+ import "apixa/mocking/register";
36
+ import { users } from "apixa/mocking/datasets/users";
37
+ import { listDatasets } from "apixa/mocking/node"; // Node-only
38
+ ```
39
+
40
+ ```tsx
41
+ import {
42
+ QueryClient,
43
+ ApixaProvider,
44
+ ApixaHydrationBoundary,
45
+ useResource,
46
+ useResourceQuery,
47
+ useResourceMutation,
48
+ } from "apixa/react";
49
+ // Server Components use the server-safe entry:
50
+ import { QueryClient as ServerQueryClient, dehydrate } from "apixa/react/advanced";
28
51
  ```
29
52
 
30
- Mocking is included under `apixa/mocking`; named datasets use `apixa/mocking/register` and
31
- `apixa/mocking/datasets`. For the optional React integration, install `react` and
32
- `@tanstack/react-query`, then import hooks from `apixa/react` and server-safe helpers from
33
- `apixa/react/advanced`. The existing scoped `@apixa/*` package entry points remain available
34
- for current consumers.
53
+ Framework subpaths keep integrations isolated. Root, Core and Mocking imports require neither
54
+ React nor TanStack Query. React and TanStack Query are optional peers, left external to the
55
+ library build; install them only when using `apixa/react`. Missing peers produce the loader's
56
+ module-not-found error when a React entry is imported. Future `apixa/vue` and `apixa/angular`
57
+ subpaths are planned, not implemented.
58
+
59
+ Core, Mocking, React and shared integration helpers remain private workspace modules. Their
60
+ canonical code is compiled into one distribution with shared runtime chunks. No scoped package
61
+ installation is required. See the [installation guide](./docs/guides/humans/install-apixa.md)
62
+ and [public API contract](./docs/public-api.md).
63
+
64
+ ### Runtime support
65
+
66
+ | Runtime | Status |
67
+ | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
68
+ | Node.js 22, 24 | Supported (CI matrix) |
69
+ | Modern browsers | Supported (verified in Chromium) |
70
+ | Cloudflare Workers | `apixa`, `apixa/core`, `apixa/mocking*` (not `/node`) and `apixa/react/advanced`, run in `workerd` without `nodejs_compat` |
71
+ | Vercel Edge Runtime | Same entries, run in `edge-runtime` |
72
+ | React 18 / 19, Next.js 15 App Router, Vite 6 | Supported (packed consumers, production and development builds) |
73
+ | TypeScript 5.5+ | Declarations checked with 5.5.4 and the latest release, `Bundler` and `NodeNext` resolution |
74
+
75
+ `apixa/mocking/node` reads the file system and is Node-only. Thrown errors keep `error.request`
76
+ (including headers and body) readable but non-enumerable, so logging an error does not print
77
+ credentials.
35
78
 
36
79
  ## Core Principles
37
80
 
@@ -40,7 +83,7 @@ for current consumers.
40
83
  - **Convention-driven:** Generate common resource operations where appropriate.
41
84
  - **Fully customizable:** Support custom endpoints and override generated behavior.
42
85
  - **Framework-agnostic:** Keep the core independent of UI frameworks and data-fetching libraries.
43
- - **Composable:** Allow additional capabilities through optional packages.
86
+ - **Composable:** Allow additional capabilities through isolated subpaths.
44
87
 
45
88
  ## Usage (implemented)
46
89
 
@@ -120,7 +163,7 @@ Set `defaultOperations: false` to start with no builtins, then enable individual
120
163
  groups. `writeOnly: true` filters read defaults. Group precedence and all default wire conventions
121
164
  are documented in [docs/conventions.md](docs/conventions.md#selection-order).
122
165
 
123
- Pass `transport` to inject a custom HTTP implementation (used in tests). The default is Fetch, shipped inside `@apixa/core`.
166
+ Pass `transport` to inject a custom HTTP implementation (used in tests). The default is Fetch, shipped inside Core.
124
167
 
125
168
  ### Request reliability (implemented)
126
169
 
@@ -219,7 +262,8 @@ API methods are intended to return native promises, allowing them to work natura
219
262
  packages/
220
263
  core/ # API definitions and execution
221
264
  mocking/ # Local datasets and standalone mock APIs
222
- tanstack-query/ # Optional React Query integration
265
+ react/ # Private React integration
266
+ internal/shared/ # Private, never published: framework-neutral integration helpers
223
267
  datasets/ # Version-controlled JSON fixtures
224
268
  examples/
225
269
  next/ # Primary frontend playground (Next.js)
@@ -245,7 +289,7 @@ Planned later packages (not created yet): `transport-fetch`, `client`, `server`,
245
289
 
246
290
  ## Project Status
247
291
 
248
- Apixa is in early development. Last shipped: **v0.11.0**. The v1.0.0 TanStack Query workstream is in progress. `@apixa/core` exposes `defineApi()` with default-first CRUD, reliability, re-callable middleware, and extension seams. `@apixa/mocking` augments Core for resource mocks.
292
+ Apixa is in early development. Last shipped: **v0.11.0**. The v1.0.0 TanStack Query workstream is in progress. Core exposes `defineApi()` with default-first CRUD, reliability, re-callable middleware, and extension seams. Mocking augments Core for resource mocks.
249
293
 
250
294
  See [versions/v1.0.0/acceptance-criteria.md](./versions/v1.0.0/acceptance-criteria.md) for the active milestone checklist.
251
295
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  data_default
3
- } from "./chunk-A3QU5MFP.js";
3
+ } from "./chunk-SO3IYVYQ.js";
4
4
 
5
5
  // packages/mocking/src/dataset-modules/products.ts
6
6
  var products = data_default;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  data_default
3
- } from "./chunk-ZSLMMDUX.js";
3
+ } from "./chunk-VACVV4XV.js";
4
4
 
5
5
  // packages/mocking/src/dataset-modules/orders.ts
6
6
  var orders = data_default;
@@ -2,9 +2,9 @@ import {
2
2
  BUILTIN_CONVENTIONS,
3
3
  createIdempotencyKey,
4
4
  getOperationMetadata
5
- } from "./chunk-GWZTJ7LM.js";
5
+ } from "./chunk-RYTQAJRH.js";
6
6
 
7
- // packages/tanstack-query/src/operations.ts
7
+ // packages/internal/shared/src/operations.ts
8
8
  var BUILTIN_READ_NAMES = new Set(
9
9
  Object.entries(BUILTIN_CONVENTIONS).filter(([, convention]) => convention.access === "read").map(([name]) => name)
10
10
  );
@@ -45,12 +45,12 @@ function assertNoFullResponse(args, info) {
45
45
  const options = args[info.optionsIndex];
46
46
  if (isPlainObject(options) && options.full === true) {
47
47
  throw new Error(
48
- "Apixa TanStack hooks return raw payloads; full: true needs the Core client directly."
48
+ "Apixa React hooks return raw payloads; full: true needs the Core client directly."
49
49
  );
50
50
  }
51
51
  }
52
52
 
53
- // packages/tanstack-query/src/keys.ts
53
+ // packages/internal/shared/src/keys.ts
54
54
  function createResourceKeys(input) {
55
55
  const root = [...input.scope ?? [], ...input.queryKey];
56
56
  return {
@@ -65,7 +65,12 @@ function createResourceKeys(input) {
65
65
  };
66
66
  }
67
67
 
68
- // packages/tanstack-query/src/query-options.ts
68
+ // packages/react/src/keys.ts
69
+ function createResourceKeys2(input) {
70
+ return createResourceKeys(input);
71
+ }
72
+
73
+ // packages/react/src/query-options.ts
69
74
  import {
70
75
  infiniteQueryOptions,
71
76
  queryOptions
@@ -105,7 +110,7 @@ function buildResourceQueryOptions(resource, options) {
105
110
  }
106
111
  const staticArgs = Array.isArray(args) ? args : query === void 0 ? void 0 : info.optionsIndex === null ? [{ query }] : withOptions([], info, { query });
107
112
  if (staticArgs) assertNoFullResponse(staticArgs, info);
108
- const keys = createResourceKeys({ queryKey, scope });
113
+ const keys = createResourceKeys2({ queryKey, scope });
109
114
  const identity = keyParts ?? normalizeIdentity(staticArgs ?? [], info);
110
115
  let generatedKey;
111
116
  if (operation === "getAll") {
@@ -215,7 +220,7 @@ function buildResourceInfiniteQueryOptions(resource, options) {
215
220
  `infinite.query needs Core's RequestOptions slot; ${operation} has a signature Core does not own \u2014 use infinite.args.`
216
221
  );
217
222
  }
218
- const keys = createResourceKeys({ queryKey, scope });
223
+ const keys = createResourceKeys2({ queryKey, scope });
219
224
  const { query: pageQuery, args: pageArgs, initialPageParam, maxPages } = infinite;
220
225
  return infiniteQueryOptions({
221
226
  ...nativeOptions,
@@ -251,7 +256,7 @@ function prefetchResourceInfiniteQuery(client, resource, options) {
251
256
  });
252
257
  }
253
258
 
254
- // packages/tanstack-query/src/query-helpers.ts
259
+ // packages/react/src/query-helpers.ts
255
260
  var INHERITED = ["staleTime", "gcTime", "retry", "retryDelay", "networkMode", "meta"];
256
261
  function createQueryHelpers(resource, client, keys, current) {
257
262
  const observed = () => {
@@ -354,8 +359,8 @@ function assertInfiniteData(value) {
354
359
  }
355
360
  }
356
361
 
357
- // packages/tanstack-query/src/query-controller.ts
358
- function createResourceQueryController(resource, config, keys = createResourceKeys(config)) {
362
+ // packages/react/src/query-controller.ts
363
+ function createResourceQueryController(resource, config, keys = createResourceKeys2(config)) {
359
364
  const root = { queryKey: config.queryKey, scope: config.scope };
360
365
  const listOptions = (overrides = {}) => buildResourceQueryOptions(resource, {
361
366
  ...overrides,
@@ -407,7 +412,7 @@ function createResourceQueryController(resource, config, keys = createResourceKe
407
412
  };
408
413
  }
409
414
 
410
- // packages/tanstack-query/src/optimistic.ts
415
+ // packages/react/src/optimistic.ts
411
416
  function inFlightFetches(queries) {
412
417
  const out = [];
413
418
  for (const query of queries) {
@@ -543,7 +548,7 @@ var OptimisticLayers = class _OptimisticLayers {
543
548
  }
544
549
  };
545
550
 
546
- // packages/tanstack-query/src/mutation-store.ts
551
+ // packages/react/src/mutation-store.ts
547
552
  import {
548
553
  MutationObserver
549
554
  } from "@tanstack/react-query";
@@ -776,9 +781,32 @@ function withIdempotencyKey(resource, name, info, args, keys) {
776
781
  return withOptions(args, info, { idempotencyKey: key });
777
782
  }
778
783
 
784
+ // packages/react/src/query-client.ts
785
+ import {
786
+ QueryClient as TanStackQueryClient
787
+ } from "@tanstack/react-query";
788
+ var QueryClient = class extends TanStackQueryClient {
789
+ constructor(config = {}) {
790
+ const { staleTime, gcTime, retry, networkMode, meta, defaultOptions, ...native } = config;
791
+ const shorthand = { staleTime, gcTime, retry, networkMode, meta };
792
+ for (const key of Object.keys(shorthand))
793
+ if (shorthand[key] === void 0) delete shorthand[key];
794
+ const hasShorthand = Object.keys(shorthand).length > 0;
795
+ super(
796
+ hasShorthand ? {
797
+ ...native,
798
+ defaultOptions: {
799
+ ...defaultOptions,
800
+ queries: { ...shorthand, ...defaultOptions?.queries }
801
+ }
802
+ } : { ...native, ...defaultOptions ? { defaultOptions } : {} }
803
+ );
804
+ }
805
+ };
806
+
779
807
  export {
780
808
  describeOperations,
781
- createResourceKeys,
809
+ createResourceKeys2 as createResourceKeys,
782
810
  createResourceQueryOptions,
783
811
  buildResourceQueryOptions,
784
812
  createResourceInfiniteQueryOptions,
@@ -790,5 +818,6 @@ export {
790
818
  OptimisticLayers,
791
819
  ResourceMutationStore,
792
820
  validateConfig,
793
- applyInvalidation
821
+ applyInvalidation,
822
+ QueryClient
794
823
  };
@@ -0,0 +1,360 @@
1
+ import {
2
+ BUILTIN_CONVENTIONS,
3
+ MockError,
4
+ MockStore,
5
+ applyResourceSliceToListResult,
6
+ expandOperations,
7
+ runBuiltin
8
+ } from "./chunk-RYTQAJRH.js";
9
+ import {
10
+ InvalidSliceError,
11
+ MockApiError,
12
+ catalog,
13
+ isDatasetId,
14
+ listDatasetIds
15
+ } from "./chunk-JM47QQH6.js";
16
+
17
+ // packages/mocking/src/mock-types.ts
18
+ var MOCK_BUILTINS = [
19
+ "getAll",
20
+ "getById",
21
+ "getBySlug",
22
+ "getMany",
23
+ "getBy",
24
+ "findFirst",
25
+ "search",
26
+ "exists",
27
+ "count",
28
+ "create",
29
+ "update",
30
+ "patch",
31
+ "upsert",
32
+ "delete",
33
+ "createMany",
34
+ "deleteMany"
35
+ ];
36
+
37
+ // packages/mocking/src/resource.ts
38
+ var CODES = {
39
+ MOCK_NOT_FOUND: "NOT_FOUND",
40
+ MOCK_DUPLICATE_ID: "DUPLICATE_ID",
41
+ MOCK_INVALID_INPUT: "INVALID_INPUT",
42
+ MOCK_UNSUPPORTED: "INVALID_CONFIG",
43
+ MOCK_LOAD: "UNKNOWN_DATASET"
44
+ };
45
+ function translate(error) {
46
+ if (error instanceof MockError) {
47
+ const code = error.code === "MOCK_INVALID_INPUT" && PAGING_MESSAGE.test(error.message) ? "INVALID_PAGINATION" : CODES[error.code] ?? "INVALID_INPUT";
48
+ const translated = new MockApiError(code, error.message);
49
+ translated.cause = error;
50
+ throw translated;
51
+ }
52
+ throw error;
53
+ }
54
+ var PAGING_MESSAGE = /: (page|pageSize|cursor) must be/;
55
+ function createResource(name, type, options) {
56
+ const label = `Mock resource "${name}"`;
57
+ const entry = catalog[type];
58
+ const source = {
59
+ label,
60
+ idKey: entry.idKey,
61
+ load: async () => (await entry.load()).default,
62
+ // Catalog datasets are module-cached and never mutated: no private snapshot needed.
63
+ seed: options.seed,
64
+ immutable: true
65
+ };
66
+ const store = new MockStore(source);
67
+ const pagination = options.pagination === true ? "page" : options.pagination || void 0;
68
+ const fail = (code, message) => new MockApiError(code, `${label}: ${message}`);
69
+ const use = (fn) => async (...args) => {
70
+ try {
71
+ await store.ready();
72
+ return await fn(...args);
73
+ } catch (error) {
74
+ return translate(error);
75
+ }
76
+ };
77
+ const run = (intent) => async (...args) => {
78
+ try {
79
+ const built = intent(...args);
80
+ const { data } = await runBuiltin(store, source, built, pagination);
81
+ return built.op === "delete" || built.op === "deleteMany" ? void 0 : data;
82
+ } catch (error) {
83
+ return translate(error);
84
+ }
85
+ };
86
+ const getAllFn = run((query) => ({ op: "getAll", query }));
87
+ const builtins = {
88
+ // `slice` caps the list result (like Core); the store keeps every record.
89
+ getAll: async (query) => applyResourceSliceToListResult(await getAllFn(query), options.slice),
90
+ getById: run((id) => ({ op: "getById", id })),
91
+ getBySlug: run((slug) => ({ op: "getBySlug", slug })),
92
+ getMany: run((ids) => ({ op: "getMany", ids })),
93
+ getBy: run((field, value) => ({ op: "getBy", field, value })),
94
+ findFirst: run((query) => ({ op: "findFirst", query })),
95
+ search: run((query) => ({ op: "search", query })),
96
+ exists: run((id) => ({ op: "exists", id })),
97
+ count: run((query) => ({ op: "count", query })),
98
+ create: run((body) => ({ op: "create", body })),
99
+ update: run((id, body) => ({ op: "update", id, body })),
100
+ patch: run((id, body) => ({ op: "patch", id, body })),
101
+ upsert: run((id, body) => ({ op: "upsert", id, body })),
102
+ delete: run((id) => ({ op: "delete", id })),
103
+ createMany: run((body) => ({ op: "createMany", body })),
104
+ deleteMany: run((body) => ({ op: "deleteMany", body }))
105
+ };
106
+ const ctx = {
107
+ idKey: entry.idKey,
108
+ rows: async () => {
109
+ await store.ready().catch(translate);
110
+ return store.liveRows();
111
+ },
112
+ fail,
113
+ defaults: {
114
+ getAll: use(() => store.list()),
115
+ getById: use((id) => store.get(id)),
116
+ create: use((input) => store.create(input)),
117
+ update: use((id, input) => store.update(id, input)),
118
+ patch: use((id, input) => store.patch(id, input)),
119
+ delete: use((id) => store.delete(id))
120
+ }
121
+ };
122
+ const custom = (fn) => async (...args) => {
123
+ try {
124
+ return await fn(ctx, ...args);
125
+ } finally {
126
+ store.reindex();
127
+ }
128
+ };
129
+ const resource = {};
130
+ for (const [opName, definition] of Object.entries(options.operations)) {
131
+ if (typeof definition === "function") {
132
+ resource[opName] = custom(definition);
133
+ } else if (MOCK_BUILTINS.includes(opName)) {
134
+ resource[opName] = builtins[opName];
135
+ }
136
+ }
137
+ return resource;
138
+ }
139
+
140
+ // packages/mocking/src/slice.ts
141
+ function isPlainSliceRange(value) {
142
+ return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).every((k) => k === "start" || k === "end");
143
+ }
144
+ function assertSliceConfig(slice, label) {
145
+ if (typeof slice === "number") {
146
+ if (!Number.isInteger(slice) || slice < 0) {
147
+ throw new InvalidSliceError(
148
+ `${label}: slice must be a non-negative integer (got ${String(slice)}).`
149
+ );
150
+ }
151
+ return;
152
+ }
153
+ if (!isPlainSliceRange(slice)) {
154
+ throw new InvalidSliceError(
155
+ `${label}: slice must be a non-negative integer or { start, end }.`
156
+ );
157
+ }
158
+ const { start, end } = slice;
159
+ if (typeof start !== "number" || !Number.isInteger(start) || start < 0) {
160
+ throw new InvalidSliceError(
161
+ `${label}: slice.start must be a non-negative integer (got ${String(start)}).`
162
+ );
163
+ }
164
+ if (typeof end !== "number" || !Number.isInteger(end) || end < 0) {
165
+ throw new InvalidSliceError(
166
+ `${label}: slice.end must be a non-negative integer (got ${String(end)}).`
167
+ );
168
+ }
169
+ if (end < start) {
170
+ throw new InvalidSliceError(
171
+ `${label}: slice.end (${end}) must not be before slice.start (${start}).`
172
+ );
173
+ }
174
+ }
175
+
176
+ // packages/mocking/src/mock-api.ts
177
+ var SELECTION_KEYS = ["defaultOperations", "readOnly", "writeOnly", "operationGroups"];
178
+ var ROOT_OPTIONS = ["resources", ...SELECTION_KEYS];
179
+ var RESOURCE_OPTIONS = ["type", "slice", "seed", "pagination", "operations", ...SELECTION_KEYS];
180
+ var GROUPS = ["read", "write", "many", "extended"];
181
+ var EXPECTED_SHAPE = 'defineMockApi() expects { resources: { users: { type: "users-mock" } } } (or the shorthand { users: "users-mock" }).';
182
+ function isPlainObject(value) {
183
+ return value !== null && typeof value === "object" && !Array.isArray(value);
184
+ }
185
+ function isRootForm(config) {
186
+ const { resources } = config;
187
+ if (!isPlainObject(resources)) return false;
188
+ return typeof resources.type !== "string";
189
+ }
190
+ function assertSettings(settings, label) {
191
+ for (const key of ["defaultOperations", "readOnly", "writeOnly"]) {
192
+ const value = settings[key];
193
+ if (value !== void 0 && typeof value !== "boolean") {
194
+ throw new MockApiError(
195
+ "INVALID_CONFIG",
196
+ `${label}: ${key} must be a boolean (got ${String(value)}).`
197
+ );
198
+ }
199
+ }
200
+ if (settings.readOnly === true && settings.writeOnly === true) {
201
+ throw new MockApiError(
202
+ "INVALID_CONFIG",
203
+ `${label}: readOnly and writeOnly cannot both be true.`
204
+ );
205
+ }
206
+ const groups = settings.operationGroups;
207
+ if (groups === void 0) return;
208
+ if (!isPlainObject(groups)) {
209
+ throw new MockApiError("INVALID_CONFIG", `${label}: operationGroups must be an object.`);
210
+ }
211
+ for (const [group, choice] of Object.entries(groups)) {
212
+ if (!GROUPS.includes(group)) {
213
+ throw new MockApiError(
214
+ "INVALID_CONFIG",
215
+ `${label}: unknown operation group "${group}". Supported groups: ${GROUPS.join(", ")}.`
216
+ );
217
+ }
218
+ if (choice !== void 0 && typeof choice !== "boolean") {
219
+ throw new MockApiError(
220
+ "INVALID_CONFIG",
221
+ `${label}: operationGroups.${group} must be a boolean (got ${String(choice)}).`
222
+ );
223
+ }
224
+ }
225
+ }
226
+ function assertOperations(operations, label) {
227
+ if (operations === void 0) return;
228
+ if (!isPlainObject(operations)) {
229
+ throw new MockApiError(
230
+ "INVALID_CONFIG",
231
+ `${label}: operations must be an object of { name: true | false | function }.`
232
+ );
233
+ }
234
+ for (const [name, value] of Object.entries(operations)) {
235
+ if (value === void 0 || value === false || typeof value === "function") continue;
236
+ if (value === true) {
237
+ if (Object.hasOwn(BUILTIN_CONVENTIONS, name)) continue;
238
+ throw new MockApiError(
239
+ "INVALID_CONFIG",
240
+ `${label}: unknown builtin operation "${name}". \`true\` only enables a builtin; give a custom operation a function.`
241
+ );
242
+ }
243
+ throw new MockApiError(
244
+ "INVALID_CONFIG",
245
+ `${label}: operation "${name}" must be true, false, or a function. HTTP forms ({ method, path, \u2026 }) are not supported by a standalone mock.`
246
+ );
247
+ }
248
+ }
249
+ function assertSeed(seed, label) {
250
+ if (!isPlainObject(seed)) {
251
+ throw new MockApiError("INVALID_CONFIG", `${label}: seed must be { limit?, offset? }.`);
252
+ }
253
+ for (const [key, value] of Object.entries(seed)) {
254
+ if (key !== "limit" && key !== "offset") {
255
+ throw new MockApiError(
256
+ "INVALID_CONFIG",
257
+ `${label}: seed has unknown option "${key}". Supported: limit, offset.`
258
+ );
259
+ }
260
+ if (value !== void 0 && (typeof value !== "number" || !Number.isInteger(value) || value < 0)) {
261
+ throw new MockApiError(
262
+ "INVALID_CONFIG",
263
+ `${label}: seed.${key} must be a non-negative integer (got ${String(value)}).`
264
+ );
265
+ }
266
+ }
267
+ }
268
+ function assertResource(name, resource) {
269
+ const label = `Mock resource "${name}"`;
270
+ if (!isPlainObject(resource)) {
271
+ throw new MockApiError(
272
+ "INVALID_CONFIG",
273
+ `${label} must be a dataset id string or an object like { type: "users-mock" }.`
274
+ );
275
+ }
276
+ for (const key of Object.keys(resource)) {
277
+ if (!RESOURCE_OPTIONS.includes(key)) {
278
+ throw new MockApiError(
279
+ "INVALID_CONFIG",
280
+ `${label} has unsupported option "${key}". Supported options: ${RESOURCE_OPTIONS.join(", ")}.`
281
+ );
282
+ }
283
+ }
284
+ const { type, slice, seed, pagination, operations } = resource;
285
+ if (!isDatasetId(type)) {
286
+ throw new MockApiError(
287
+ "UNKNOWN_DATASET",
288
+ `${label}: ${type === void 0 ? 'missing "type"' : `unknown dataset ${JSON.stringify(type)}`}. Available: ${listDatasetIds().join(", ")}.`
289
+ );
290
+ }
291
+ if (slice !== void 0) assertSliceConfig(slice, label);
292
+ if (seed !== void 0) assertSeed(seed, label);
293
+ if (pagination !== void 0 && typeof pagination !== "boolean" && pagination !== "page" && pagination !== "cursor") {
294
+ throw new MockApiError(
295
+ "INVALID_CONFIG",
296
+ `${label}: pagination must be true, false, "page" or "cursor" (got ${String(pagination)}).`
297
+ );
298
+ }
299
+ assertSettings(resource, label);
300
+ assertOperations(operations, label);
301
+ }
302
+ function pickSettings(source) {
303
+ const out = {};
304
+ for (const key of SELECTION_KEYS) {
305
+ if (source[key] !== void 0) out[key] = source[key];
306
+ }
307
+ return out;
308
+ }
309
+ function mergeSettings(root, resource) {
310
+ const merged = { ...root, ...resource };
311
+ if (root.operationGroups || resource.operationGroups) {
312
+ merged.operationGroups = { ...root.operationGroups, ...resource.operationGroups };
313
+ }
314
+ return merged;
315
+ }
316
+ function defineMockApi(config) {
317
+ if (!isPlainObject(config)) throw new MockApiError("INVALID_CONFIG", EXPECTED_SHAPE);
318
+ let root = {};
319
+ let resources;
320
+ if (isRootForm(config)) {
321
+ for (const key of Object.keys(config)) {
322
+ if (!ROOT_OPTIONS.includes(key)) {
323
+ throw new MockApiError(
324
+ "INVALID_CONFIG",
325
+ `defineMockApi() has unsupported option "${key}". Supported options: ${ROOT_OPTIONS.join(", ")}.`
326
+ );
327
+ }
328
+ }
329
+ assertSettings(config, "defineMockApi()");
330
+ root = pickSettings(config);
331
+ resources = config.resources;
332
+ } else {
333
+ resources = config;
334
+ }
335
+ const entries = Object.entries(resources);
336
+ if (entries.length === 0) {
337
+ throw new MockApiError("INVALID_CONFIG", "defineMockApi() needs at least one resource.");
338
+ }
339
+ const api = {};
340
+ for (const [name, input] of entries) {
341
+ const resource = typeof input === "string" ? { type: input } : input;
342
+ assertResource(name, resource);
343
+ const raw = resource;
344
+ const settings = mergeSettings(root, pickSettings(raw));
345
+ api[name] = createResource(name, resource.type, {
346
+ slice: resource.slice,
347
+ seed: resource.seed,
348
+ pagination: resource.pagination,
349
+ operations: expandOperations(
350
+ resource.operations,
351
+ settings
352
+ )
353
+ });
354
+ }
355
+ return api;
356
+ }
357
+
358
+ export {
359
+ defineMockApi
360
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  data_default
3
- } from "./chunk-DGSIZXRI.js";
3
+ } from "./chunk-YZ7TR6HL.js";
4
4
 
5
5
  // packages/mocking/src/dataset-modules/companies.ts
6
6
  var companies = data_default;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  data_default
3
- } from "./chunk-QY5YMHHN.js";
3
+ } from "./chunk-3RDQXC6Q.js";
4
4
 
5
5
  // packages/mocking/src/dataset-modules/comments.ts
6
6
  var comments = data_default;