@classytic/arc-next 0.2.1 → 0.3.1

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/README.md CHANGED
@@ -30,13 +30,13 @@ import { useRouter } from "next/navigation";
30
30
  // Required — sets the API base URL and auth mode
31
31
  configureClient({
32
32
  baseUrl: process.env.NEXT_PUBLIC_API_URL!,
33
- authMode: "cookie", // 'cookie' for Better Auth, 'bearer' for token auth (default)
34
- internalApiKey: process.env.NEXT_PUBLIC_INTERNAL_API_KEY, // optional
33
+ authMode: "cookie", // 'cookie' for Better Auth, 'bearer' for token auth (default)
34
+ // credentials: 'omit', // override if you don't want cookies sent cross-origin
35
35
  });
36
36
 
37
- // Optional — auto-inject org context into queries/mutations
37
+ // Optional — auto-inject tenant context into queries/mutations
38
38
  configureAuth({
39
- getOrgId: () => activeOrgId, // return current org ID
39
+ getOrgId: () => activeTenantId, // return current tenant/org/workspace ID
40
40
  getToken: () => null, // null for cookie auth (token only for bearer)
41
41
  });
42
42
 
@@ -51,10 +51,11 @@ configureNavigation(useRouter);
51
51
 
52
52
  | Import | Purpose | `"use client"` |
53
53
  | ----------------------------------- | ---------------------------------------------------------------------------- | :-------------: |
54
+ | `@classytic/arc-next` | Root — same as `/hooks` (`createCrudHooks`, `configureNavigation`) | Yes |
54
55
  | `@classytic/arc-next/client` | `configureClient`, `configureAuth`, `createClient`, `handleApiRequest`, `createQueryString`, `ArcApiError`, `isArcApiError`, `getAuthMode`, `getAuthContext` | No |
55
56
  | `@classytic/arc-next/api` | `BaseApi`, `createCrudApi`, response types, type guards | No |
56
- | `@classytic/arc-next/query` | `createQueryKeys`, `createCacheUtils`, `createListQuery`, `createDetailQuery`| Yes |
57
- | `@classytic/arc-next/mutation` | `configureToast`, `useMutationWithTransition`, `createOptimisticMutation` | Yes |
57
+ | `@classytic/arc-next/query` | `createQueryKeys`, `createCacheUtils`, `useListQuery`, `useDetailQuery` | Yes |
58
+ | `@classytic/arc-next/mutation` | `configureToast`, `useMutationWithTransition`, `useOptimisticMutation` | Yes |
58
59
  | `@classytic/arc-next/hooks` | `createCrudHooks`, `configureNavigation` | Yes |
59
60
  | `@classytic/arc-next/query-client` | `getQueryClient` (SSR-safe singleton) | No |
60
61
  | `@classytic/arc-next/prefetch` | `createCrudPrefetcher`, `dehydrate` (SSR prefetch) | No |
@@ -148,13 +149,15 @@ export function ProductsPage() {
148
149
  configureClient({
149
150
  baseUrl: string; // Required — API base URL
150
151
  authMode?: 'cookie' | 'bearer'; // Default: 'bearer'
152
+ credentials?: RequestCredentials; // Default: derived from authMode
151
153
  internalApiKey?: string; // Optional — sent as x-internal-api-key header
152
154
  defaultHeaders?: Record<string, string>; // Optional — merged into every request
153
155
  });
154
156
  ```
155
157
 
156
- - `authMode: 'bearer'` (default) — requires a token for authenticated requests; queries are disabled until a token is provided
157
- - `authMode: 'cookie'` — auth via HTTP-only cookies (e.g. Better Auth); queries are always enabled, no token needed
158
+ - `authMode: 'bearer'` (default) — requires a token; queries disabled until token provided; `credentials: 'same-origin'`
159
+ - `authMode: 'cookie'` — HTTP-only cookies (e.g. Better Auth); queries always enabled; `credentials: 'include'`
160
+ - `credentials` — explicit override: `'include'` (send cookies cross-origin), `'same-origin'` (same-origin only), `'omit'` (never send cookies)
158
161
 
159
162
  Must be called before any API requests. Throws if not configured.
160
163
 
@@ -167,7 +170,7 @@ configureAuth({
167
170
  });
168
171
  ```
169
172
 
170
- Auto-injects `token` and `organizationId` into queries/mutations. Hooks use the new signature (no explicit token param) — legacy signature still works.
173
+ Auto-injects `token` and tenant ID (sent as `x-organization-id` header) into queries/mutations. The header name is a convention — your backend controls how it's read and which field it maps to (`organizationId`, `workspaceId`, `teamId`, etc.). Hooks use the new signature (no explicit token param) — legacy signature still works.
171
174
 
172
175
  ### `handleApiRequest<T>(method, endpoint, options?)`
173
176
 
@@ -226,7 +229,7 @@ const api = createCrudApi<Product, CreateProduct>("products", {
226
229
 
227
230
  ### `createCrudHooks<T, TCreate, TUpdate>(config)`
228
231
 
229
- Factory that returns everything you need:
232
+ Factory that returns everything you need. The `api` parameter accepts any `createCrudApi()` result directly — no casts needed. Types are derived from `BaseApi` via `Pick`, so generics thread through automatically:
230
233
 
231
234
  ```ts
232
235
  const {
@@ -235,7 +238,7 @@ const {
235
238
  useActions, useUpload, useSearch, useCustomMutation,
236
239
  useNavigation,
237
240
  } = createCrudHooks<Product, CreateProduct>({
238
- api: productsApi, // from createCrudApi()
241
+ api: productsApi, // from createCrudApi() — types inferred, no cast
239
242
  entityKey: "products", // TanStack Query key prefix
240
243
  singular: "Product", // for toast messages
241
244
  defaults: { // optional
@@ -263,7 +266,7 @@ const { items, pagination, isLoading, isFetching, refetch } = useList(
263
266
  );
264
267
  ```
265
268
 
266
- - Auto-scopes query keys by `organizationId` (tenant vs super-admin)
269
+ - Auto-scopes list query keys by tenant context (when present → `tenant` scope, otherwise → `super-admin`)
267
270
  - Normalizes pagination from `docs`/`data`/`items`/`results` formats
268
271
  - Prefills detail cache from list results (skips re-fetch on navigate)
269
272
  - `options.public: true` — enables query without token
@@ -534,7 +537,7 @@ useProducts(token, {}, { ...QUERY_CONFIGS.realtime });
534
537
 
535
538
  ### `updateListCache(listData, updater)`
536
539
 
537
- Transforms list cache regardless of format (`docs[]`, `data[]`, `items[]`, `results[]`, or raw array).
540
+ Transforms list cache regardless of format — well-known keys (`docs[]`, `data[]`, `items[]`, `results[]`), custom keys (`products[]`, `users[]`, etc.), or raw arrays.
538
541
  Automatically adjusts `total`/`totalDocs` counts when items are added or removed (optimistic add/delete).
539
542
 
540
543
  ```ts
@@ -551,11 +554,11 @@ Extracts `_id` or `id` from any item. Returns `string | null`.
551
554
 
552
555
  ### `normalizePagination(data)`
553
556
 
554
- Converts any pagination response format to a normalized `PaginationData` object. Handles `total`/`totalDocs`, `pages`/`totalPages`, `page`/`currentPage`, `hasNext`/`hasNextPage`/`hasMore`, `hasPrev`/`hasPrevPage`.
557
+ Converts any pagination response format to a normalized `PaginationData` object. Detects pagination method (`offset`, `keyset`, `aggregate`) and normalizes all fields: `total`/`totalDocs`, `pages`/`totalPages`, `page`/`currentPage`, `hasNext`/`hasNextPage`/`hasMore`, `hasPrev`/`hasPrevPage`, `next` (keyset cursor).
555
558
 
556
559
  ### `extractItems<T>(data)`
557
560
 
558
- Extracts the items array from any response format looks for `docs`, `data`, `items`, `results` fields, or returns the data directly if it's already an array.
561
+ Extracts the items array from any response format. Checks well-known keys first (`docs`, `data`, `items`, `results`), then falls back to finding the first top-level array so `{ products: [...] }` or `{ users: [...] }` works without configuration.
559
562
 
560
563
  ## Multi-Client (Multiple APIs)
561
564
 
@@ -654,8 +657,10 @@ try {
654
657
  ### Multi-tenant data fetching
655
658
 
656
659
  ```ts
657
- // organizationId in params → scoped query key → isolated cache per tenant
658
- const { items } = useProducts(token, { organizationId: currentOrg });
660
+ // Tenant ID in params → scoped query key → isolated cache per tenant
661
+ // The param name is up to you arc-next sends it as x-organization-id header,
662
+ // your backend maps it to whatever tenant field your schema uses.
663
+ const { items } = useProducts(token, { organizationId: currentTenantId });
659
664
  ```
660
665
 
661
666
  ### Public endpoints (no auth)
@@ -704,11 +709,11 @@ const adminApi = createCrudApi("users", {
704
709
 
705
710
  - **CRUD Factory** — `createCrudApi` + `createCrudHooks` generates typed API clients and React Query hooks
706
711
  - **Optimistic Updates** — Create, update, delete with instant UI feedback and automatic rollback
707
- - **Multi-Tenant Scoping** — `organizationId` in headers + scoped query keys
708
- - **Pagination Normalization** — Handles `docs`/`data`/`items`/`results` response formats, offset/keyset/aggregate pagination
712
+ - **Multi-Tenant Scoping** — Tenant ID sent via `x-organization-id` header + scoped list query keys. Backend controls the tenant field name and access enforcement.
713
+ - **Pagination Normalization** — Handles `docs`/`data`/`items`/`results` + any custom key, offset/keyset/aggregate pagination
709
714
  - **Detail Cache Prefilling** — List results auto-populate detail query cache
710
715
  - **React 19 Transitions** — `useMutationWithTransition` wraps invalidation in `startTransition`
711
- - **Cookie & Bearer Auth** — `authMode: 'cookie'` for Better Auth, `'bearer'` for token auth
716
+ - **Cookie & Bearer Auth** — `authMode: 'cookie'` for Better Auth, `'bearer'` for token auth, configurable `credentials` policy
712
717
  - **SSR Prefetch** — `createCrudPrefetcher` + `dehydrate` for server component data loading
713
718
  - **Multi-Client** — `createClient()` for multiple API backends side by side
714
719
  - **Pluggable Toast** — `configureToast()` — use sonner, react-hot-toast, or anything
package/dist/api.d.ts CHANGED
@@ -77,16 +77,6 @@ interface RequestOptions {
77
77
  responseType?: 'json' | 'blob' | 'text';
78
78
  signal?: AbortSignal;
79
79
  }
80
- /**
81
- * Arc scope for multi-tenant APIs.
82
- *
83
- * - `'tenant'` (default) — Org-scoped. Hooks auto-inject `organizationId` from auth context.
84
- * - `'platform'` — Platform admin scope. Skips org injection, sets `x-arc-scope: platform`
85
- * header so Arc's elevation plugin grants cross-org access for superadmins.
86
- */
87
- type ArcScope = 'tenant' | 'platform';
88
- /** Header name used by Arc's elevation plugin */
89
- declare const ARC_SCOPE_HEADER = "x-arc-scope";
90
80
  interface BaseApiConfig {
91
81
  basePath?: string;
92
82
  defaultParams?: {
@@ -96,32 +86,13 @@ interface BaseApiConfig {
96
86
  };
97
87
  cache?: RequestCache;
98
88
  headers?: Record<string, string>;
99
- /**
100
- * API scope — controls org context injection and Arc scope headers.
101
- *
102
- * @default 'tenant'
103
- *
104
- * @example
105
- * ```ts
106
- * // Org-scoped API (default) — auto-injects organizationId
107
- * const postsApi = createCrudApi('posts', { basePath: '/api' });
108
- *
109
- * // Platform admin API — skips org injection, adds x-arc-scope header
110
- * const adminApi = createCrudApi('subscriptions', {
111
- * basePath: '/api',
112
- * scope: 'platform',
113
- * });
114
- * ```
115
- */
116
- scope?: ArcScope;
117
89
  client?: ArcClient;
118
90
  }
119
91
  declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, TUpdate = Partial<TDoc>> {
120
92
  readonly entity: string;
121
- readonly config: Required<Omit<BaseApiConfig, 'client' | 'scope'>>;
93
+ readonly config: Required<Omit<BaseApiConfig, 'client'>>;
122
94
  readonly baseUrl: string;
123
95
  private readonly requestFn;
124
- readonly scope: ArcScope;
125
96
  constructor(entity: string, config?: BaseApiConfig);
126
97
  /** Merge per-instance headers into request options */
127
98
  private withHeaders;
@@ -254,5 +225,4 @@ declare function isOffsetPagination<T>(response: PaginatedResponse<T>): response
254
225
  declare function isKeysetPagination<T>(response: PaginatedResponse<T>): response is KeysetPaginationResponse<T>;
255
226
  declare function isAggregatePagination<T>(response: PaginatedResponse<T>): response is AggregatePaginationResponse<T>;
256
227
  //#endregion
257
- export { ARC_SCOPE_HEADER, AggregatePaginationResponse, ApiResponse, ArcScope, BaseApi, BaseApiConfig, DeleteResponse, ExtractDoc, FilterOperator, KeysetPaginationResponse, OffsetPaginationResponse, PaginatedResponse, PopulateOption, QueryParams, RequestOptions, SortDirection, SortSpec, createCrudApi, isAggregatePagination, isKeysetPagination, isOffsetPagination };
258
- //# sourceMappingURL=api.d.ts.map
228
+ export { AggregatePaginationResponse, ApiResponse, BaseApi, BaseApiConfig, DeleteResponse, ExtractDoc, FilterOperator, KeysetPaginationResponse, OffsetPaginationResponse, PaginatedResponse, PopulateOption, QueryParams, RequestOptions, SortDirection, SortSpec, createCrudApi, isAggregatePagination, isKeysetPagination, isOffsetPagination };
package/dist/api.js CHANGED
@@ -1,19 +1,14 @@
1
1
  import { createQueryString, handleApiRequest } from "./client.js";
2
2
 
3
3
  //#region src/api.ts
4
- /** Header name used by Arc's elevation plugin */
5
- const ARC_SCOPE_HEADER = "x-arc-scope";
6
4
  var BaseApi = class {
7
5
  entity;
8
6
  config;
9
7
  baseUrl;
10
8
  requestFn;
11
- scope;
12
9
  constructor(entity, config = {}) {
13
10
  this.entity = entity;
14
- this.scope = config.scope ?? "tenant";
15
11
  this.requestFn = config.client?.request ?? handleApiRequest;
16
- const scopeHeaders = this.scope === "platform" ? { [ARC_SCOPE_HEADER]: "platform" } : {};
17
12
  this.config = {
18
13
  basePath: config.basePath ?? "/api/v1",
19
14
  defaultParams: {
@@ -22,10 +17,7 @@ var BaseApi = class {
22
17
  ...config.defaultParams || {}
23
18
  },
24
19
  cache: config.cache ?? "no-store",
25
- headers: {
26
- ...scopeHeaders,
27
- ...config.headers || {}
28
- }
20
+ headers: { ...config.headers || {} }
29
21
  };
30
22
  this.baseUrl = `${this.config.basePath}/${this.entity}`;
31
23
  }
@@ -65,7 +57,11 @@ var BaseApi = class {
65
57
  return result;
66
58
  }
67
59
  async getAll({ token = null, organizationId = null, params = {}, options = {} } = {}) {
68
- const processedParams = this.prepareParams(params);
60
+ const mergedParams = {
61
+ ...this.config.defaultParams,
62
+ ...params
63
+ };
64
+ const processedParams = this.prepareParams(mergedParams);
69
65
  const queryString = this.createQueryString(processedParams);
70
66
  const requestOptions = {
71
67
  cache: this.config.cache,
@@ -126,6 +122,7 @@ var BaseApi = class {
126
122
  }
127
123
  async search({ token = null, organizationId = null, searchParams = {}, params = {}, options = {} } = {}) {
128
124
  const queryParams = {
125
+ ...this.config.defaultParams,
129
126
  ...params,
130
127
  ...searchParams
131
128
  };
@@ -141,7 +138,10 @@ var BaseApi = class {
141
138
  }
142
139
  async findBy({ token = null, organizationId = null, field, value, operator, params = {}, options = {} }) {
143
140
  if (!field || value === void 0) throw new Error("Field and value are required");
144
- const queryParams = { ...params };
141
+ const queryParams = {
142
+ ...this.config.defaultParams,
143
+ ...params
144
+ };
145
145
  if (operator) queryParams[`${field}[${operator}]`] = Array.isArray(value) ? value.join(",") : value;
146
146
  else queryParams[field] = value;
147
147
  const processedParams = this.prepareParams(queryParams);
@@ -184,5 +184,4 @@ function isAggregatePagination(response) {
184
184
  }
185
185
 
186
186
  //#endregion
187
- export { ARC_SCOPE_HEADER, BaseApi, createCrudApi, isAggregatePagination, isKeysetPagination, isOffsetPagination };
188
- //# sourceMappingURL=api.js.map
187
+ export { BaseApi, createCrudApi, isAggregatePagination, isKeysetPagination, isOffsetPagination };
package/dist/client.d.ts CHANGED
@@ -56,10 +56,25 @@ interface ClientConfig {
56
56
  * - 'cookie': Auth is handled via HTTP-only cookies (e.g. Better Auth). Queries are always enabled — no token needed.
57
57
  */
58
58
  authMode?: 'bearer' | 'cookie';
59
+ /**
60
+ * Fetch credentials policy.
61
+ * - 'include': Always send cookies cross-origin (required for cookie-based auth).
62
+ * - 'same-origin': Only send cookies to same-origin requests (browser default).
63
+ * - 'omit': Never send cookies.
64
+ *
65
+ * When not set, derived from `authMode`:
66
+ * - `authMode: 'cookie'` → `'include'`
67
+ * - `authMode: 'bearer'` (default) → `'same-origin'`
68
+ */
69
+ credentials?: RequestCredentials;
59
70
  }
60
71
  /**
61
72
  * Configure the API client. Call once at app init before any API requests.
62
73
  *
74
+ * **SSR safety:** This sets module-level state. In Next.js, call this only in
75
+ * client-side code (e.g. a `"use client"` provider or `useEffect`).
76
+ * Calling on the server risks leaking state between requests.
77
+ *
63
78
  * @example
64
79
  * // Bearer token auth (default)
65
80
  * configureClient({ baseUrl: process.env.NEXT_PUBLIC_API_URL! });
@@ -80,6 +95,8 @@ interface AuthConfig {
80
95
  * Configure auth context for automatic token/orgId injection.
81
96
  * When configured, hooks auto-inject these values so you don't need to pass them manually.
82
97
  *
98
+ * **SSR safety:** This sets module-level state. Call only in client-side code.
99
+ *
83
100
  * @example
84
101
  * // Cookie auth (no token needed)
85
102
  * configureAuth({ getOrgId: () => currentOrg.id });
@@ -168,5 +185,4 @@ declare function handleApiRequest<T = unknown>(method: HttpMethod, endpoint: str
168
185
  */
169
186
  declare function createQueryString<T extends Record<string, unknown>>(params?: T): string;
170
187
  //#endregion
171
- export { ApiRequestOptions, ArcApiError, ArcApiErrorOptions, ArcClient, ArcClientConfig, AuthConfig, BlobResponse, ClientConfig, HttpMethod, TextResponse, ToastHandler, UseRouterHook, configureAuth, configureClient, createClient, createQueryString, getAuthContext, getAuthMode, handleApiRequest, isArcApiError };
172
- //# sourceMappingURL=client.d.ts.map
188
+ export { ApiRequestOptions, ArcApiError, ArcApiErrorOptions, ArcClient, ArcClientConfig, AuthConfig, BlobResponse, ClientConfig, HttpMethod, TextResponse, ToastHandler, UseRouterHook, configureAuth, configureClient, createClient, createQueryString, getAuthContext, getAuthMode, handleApiRequest, isArcApiError };
package/dist/client.js CHANGED
@@ -43,6 +43,10 @@ let clientConfig = null;
43
43
  /**
44
44
  * Configure the API client. Call once at app init before any API requests.
45
45
  *
46
+ * **SSR safety:** This sets module-level state. In Next.js, call this only in
47
+ * client-side code (e.g. a `"use client"` provider or `useEffect`).
48
+ * Calling on the server risks leaking state between requests.
49
+ *
46
50
  * @example
47
51
  * // Bearer token auth (default)
48
52
  * configureClient({ baseUrl: process.env.NEXT_PUBLIC_API_URL! });
@@ -64,6 +68,8 @@ let authConfig = null;
64
68
  * Configure auth context for automatic token/orgId injection.
65
69
  * When configured, hooks auto-inject these values so you don't need to pass them manually.
66
70
  *
71
+ * **SSR safety:** This sets module-level state. Call only in client-side code.
72
+ *
67
73
  * @example
68
74
  * // Cookie auth (no token needed)
69
75
  * configureAuth({ getOrgId: () => currentOrg.id });
@@ -122,10 +128,11 @@ async function executeRequest(config, method, endpoint, options = {}) {
122
128
  ...headers,
123
129
  ...headerOptions
124
130
  };
131
+ const credentials = config.credentials ?? (config.authMode === "cookie" ? "include" : "same-origin");
125
132
  const fetchOptions = {
126
133
  method,
127
134
  headers,
128
- credentials: "include",
135
+ credentials,
129
136
  ...signal ? { signal } : {}
130
137
  };
131
138
  if (body !== void 0 && body !== null) fetchOptions.body = body instanceof FormData ? body : JSON.stringify(body);
@@ -177,8 +184,8 @@ async function executeRequest(config, method, endpoint, options = {}) {
177
184
  }
178
185
  return data;
179
186
  } catch (error) {
180
- if (error instanceof ArcApiError) throw error;
181
- throw new Error(error instanceof Error ? error.message : "An error occurred while fetching data.");
187
+ if (error instanceof Error) throw error;
188
+ throw new Error("An error occurred while fetching data.");
182
189
  }
183
190
  }
184
191
  /**
@@ -238,5 +245,4 @@ function createQueryString(params = {}) {
238
245
  }
239
246
 
240
247
  //#endregion
241
- export { ArcApiError, configureAuth, configureClient, createClient, createQueryString, getAuthContext, getAuthMode, handleApiRequest, isArcApiError };
242
- //# sourceMappingURL=client.js.map
248
+ export { ArcApiError, configureAuth, configureClient, createClient, createQueryString, getAuthContext, getAuthMode, handleApiRequest, isArcApiError };
package/dist/hooks.d.ts CHANGED
@@ -1,84 +1,26 @@
1
1
  import { ArcClient, UseRouterHook } from "./client.js";
2
+ import { BaseApi } from "./api.js";
2
3
  import { MutationCallbacks, MutationMessages, TransitionMutationReturn } from "./mutation.js";
3
4
  import { CacheUtils, DetailQueryOptions, DetailQueryResult, InfiniteListQueryOptions, InfiniteListQueryResult, ListQueryOptions, ListQueryResult, QueryKeys } from "./query.js";
4
5
  import { QueryKey } from "@tanstack/react-query";
5
6
 
6
7
  //#region src/hooks.d.ts
7
- interface CrudApi<T, TCreate = Partial<T>, TUpdate = Partial<T>> {
8
- /** Scope from BaseApi used to auto-detect platformScoped */
9
- scope?: 'tenant' | 'platform';
10
- getAll: (options: {
11
- token?: string | null;
12
- organizationId?: string | null;
13
- params?: Record<string, unknown>;
14
- options?: {
15
- signal?: AbortSignal;
16
- [key: string]: unknown;
17
- };
18
- }) => Promise<unknown>;
19
- getById: (options: {
20
- id: string;
21
- token?: string | null;
22
- organizationId?: string | null;
23
- params?: {
24
- select?: string;
25
- populate?: string | string[];
26
- };
27
- options?: {
28
- signal?: AbortSignal;
29
- [key: string]: unknown;
30
- };
31
- }) => Promise<unknown>;
32
- create: (options: {
33
- token?: string | null;
34
- organizationId?: string | null;
35
- data: TCreate;
36
- }) => Promise<unknown>;
37
- update: (options: {
38
- token?: string | null;
39
- organizationId?: string | null;
40
- id: string;
41
- data: TUpdate;
42
- }) => Promise<unknown>;
43
- delete: (options: {
44
- token?: string | null;
45
- organizationId?: string | null;
46
- id: string;
47
- }) => Promise<unknown>;
48
- upload?: (options: {
49
- token?: string | null;
50
- organizationId?: string | null;
51
- data: FormData;
52
- id?: string;
53
- path?: string;
54
- }) => Promise<unknown>;
55
- search?: (options: {
56
- token?: string | null;
57
- organizationId?: string | null;
58
- params?: Record<string, unknown>;
59
- options?: {
60
- signal?: AbortSignal;
61
- [key: string]: unknown;
62
- };
63
- }) => Promise<unknown>;
64
- }
8
+ /**
9
+ * CRUD API interface accepted by createCrudHooks.
10
+ *
11
+ * Derived from BaseApi via Pick so the types are always in sync.
12
+ * BaseApi instances satisfy this exactly (same source of truth).
13
+ * Custom implementations just need to match BaseApi's method signatures.
14
+ */
15
+ type CrudApi<T = unknown, TCreate = Partial<T>, TUpdate = Partial<T>> = Pick<BaseApi<T, TCreate, TUpdate>, 'getAll' | 'getById' | 'create' | 'update' | 'delete'> & {
16
+ upload?: BaseApi<T, TCreate, TUpdate>['upload'];
17
+ search?: BaseApi<T, TCreate, TUpdate>['search'];
18
+ };
65
19
  interface CrudHooksConfig<T, TCreate = Partial<T>, TUpdate = Partial<T>> {
66
20
  api: CrudApi<T, TCreate, TUpdate>;
67
21
  entityKey: string;
68
22
  singular: string;
69
23
  plural?: string;
70
- /**
71
- * Platform-scoped hooks skip automatic organizationId injection.
72
- *
73
- * Use this for admin/superadmin hooks that query across all orgs
74
- * (e.g., APIs configured with `x-arc-scope: platform`).
75
- *
76
- * When true, the hooks will NOT auto-inject the user's active
77
- * organizationId into requests — the API's own headers control scoping.
78
- *
79
- * @default false
80
- */
81
- platformScoped?: boolean;
82
24
  defaults?: {
83
25
  staleTime?: number;
84
26
  gcTime?: number;
@@ -181,6 +123,8 @@ interface CrudHooksReturn<T, TCreate, TUpdate> {
181
123
  /**
182
124
  * Configure the router hook for useNavigation. Call once at app init.
183
125
  *
126
+ * **SSR safety:** This sets module-level state. Call only in client-side code.
127
+ *
184
128
  * @example
185
129
  * import { useRouter } from "next/navigation";
186
130
  * configureNavigation(useRouter);
@@ -190,11 +134,9 @@ declare function createCrudHooks<T, TCreate = Partial<T>, TUpdate = Partial<T>>(
190
134
  api,
191
135
  entityKey,
192
136
  singular,
193
- platformScoped,
194
137
  defaults,
195
138
  callbacks,
196
139
  client
197
140
  }: CrudHooksConfig<T, TCreate, TUpdate>): CrudHooksReturn<T, TCreate, TUpdate>;
198
141
  //#endregion
199
- export { CallOptions, CrudActions, CrudApi, CrudHooksConfig, CrudHooksReturn, DeleteParams, MutationParams, NavigateFn, NavigationOptions, UpdateParams, type UseRouterHook, configureNavigation, createCrudHooks };
200
- //# sourceMappingURL=hooks.d.ts.map
142
+ export { CallOptions, CrudActions, CrudApi, CrudHooksConfig, CrudHooksReturn, DeleteParams, MutationParams, NavigateFn, NavigationOptions, UpdateParams, configureNavigation, createCrudHooks };