@classytic/arc-next 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +7 -0
- package/dist/api.d.ts +33 -96
- package/dist/api.js +2 -1
- package/dist/cache.d.ts +8 -5
- package/dist/client.d.ts +46 -3
- package/dist/client.js +50 -3
- package/dist/encryption.d.ts +0 -1
- package/dist/hooks.d.ts +24 -21
- package/dist/mutation.d.ts +1 -3
- package/dist/prefetch.d.ts +0 -1
- package/dist/presets/bulk.d.ts +0 -1
- package/dist/presets/history.d.ts +0 -1
- package/dist/presets/search.d.ts +17 -8
- package/dist/presets/slug.d.ts +0 -1
- package/dist/presets/soft-delete.d.ts +0 -1
- package/dist/presets/tree.d.ts +0 -1
- package/dist/query-client.d.ts +0 -1
- package/dist/query-options.d.ts +32 -26
- package/dist/query.d.ts +6 -46
- package/dist/sse.d.ts +0 -1
- package/dist/sse.js +3 -2
- package/dist/upload.d.ts +0 -1
- package/dist/upload.js +2 -1
- package/dist/ws.d.ts +0 -1
- package/package.json +3 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -650,3 +650,10 @@ const { mutateAsync: publish, isPending } = useMutationWithTransition({
|
|
|
650
650
|
## License
|
|
651
651
|
|
|
652
652
|
MIT
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
## Trademark
|
|
656
|
+
|
|
657
|
+
The code is MIT-licensed. **"Classytic", "arc", and the logos are trademarks of
|
|
658
|
+
Classytic LLC** and are **not** licensed under MIT — see [TRADEMARK.md](TRADEMARK.md).
|
|
659
|
+
Forks must be renamed; the license covers the code, not the brand.
|
package/dist/api.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { ArcClient, NextFetchOptions } from "./client.js";
|
|
|
2
2
|
import { BracketOperator, BracketOperator as BracketOperator$1, ParsedPopulate } from "@classytic/repo-core/query-parser";
|
|
3
3
|
import { AggregatePaginationResult, KeysetPaginationResult, OffsetPaginationResult, PaginatedResult, SortDirection as SortDirection$1 } from "@classytic/repo-core/pagination";
|
|
4
4
|
import { AggResult, AggRow, BulkCreateResult, DeleteManyResult, DeleteResult, UpdateManyResult } from "@classytic/repo-core/repository";
|
|
5
|
-
|
|
6
5
|
//#region src/api.d.ts
|
|
7
6
|
/**
|
|
8
7
|
* URL-emittable subset of repo-core's canonical {@link ParsedPopulate} —
|
|
@@ -100,7 +99,18 @@ interface BaseApiConfig {
|
|
|
100
99
|
};
|
|
101
100
|
cache?: RequestCache;
|
|
102
101
|
headers?: Record<string, string>;
|
|
103
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Transport for this API instance.
|
|
104
|
+
*
|
|
105
|
+
* - `ArcClient` — RETAINED: the instance is captured and every request goes
|
|
106
|
+
* through it (isolated multi-client setups, tests, background jobs).
|
|
107
|
+
* - `() => ArcClient` — PROVIDER: re-resolved on EVERY request, so a
|
|
108
|
+
* consumer SDK can swap/reconfigure the underlying client after APIs are
|
|
109
|
+
* constructed without Proxy tricks or stale-capture bugs (the reason the
|
|
110
|
+
* commerce SDK previously wrapped its default client in a `Proxy`).
|
|
111
|
+
* - omitted — the module-global transport (`configureClient`/`configureAuth`).
|
|
112
|
+
*/
|
|
113
|
+
client?: ArcClient | (() => ArcClient);
|
|
104
114
|
}
|
|
105
115
|
declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, TUpdate = Partial<TDoc>> {
|
|
106
116
|
readonly entity: string;
|
|
@@ -129,12 +139,7 @@ declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, T
|
|
|
129
139
|
private withCacheDefault;
|
|
130
140
|
createQueryString(params?: Record<string, unknown>): string;
|
|
131
141
|
prepareParams(params?: QueryParams): Record<string, unknown>;
|
|
132
|
-
getAll({
|
|
133
|
-
token,
|
|
134
|
-
organizationId,
|
|
135
|
-
params,
|
|
136
|
-
options
|
|
137
|
-
}?: {
|
|
142
|
+
getAll({ token, organizationId, params, options }?: {
|
|
138
143
|
token?: string | null;
|
|
139
144
|
organizationId?: string | null;
|
|
140
145
|
params?: QueryParams;
|
|
@@ -145,37 +150,21 @@ declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, T
|
|
|
145
150
|
* (`?_count=true`): same permissions/row-filters/tenant scoping as
|
|
146
151
|
* `getAll`, ZERO documents fetched. Cheapest way to answer "how many".
|
|
147
152
|
*/
|
|
148
|
-
count({
|
|
149
|
-
token,
|
|
150
|
-
organizationId,
|
|
151
|
-
params,
|
|
152
|
-
options
|
|
153
|
-
}?: {
|
|
153
|
+
count({ token, organizationId, params, options }?: {
|
|
154
154
|
token?: string | null;
|
|
155
155
|
organizationId?: string | null;
|
|
156
156
|
params?: QueryParams;
|
|
157
157
|
options?: Omit<RequestOptions, "token" | "organizationId">;
|
|
158
158
|
}): Promise<number>;
|
|
159
159
|
/** Whether ANY record matches the filters (`?_exists=true`). */
|
|
160
|
-
exists({
|
|
161
|
-
token,
|
|
162
|
-
organizationId,
|
|
163
|
-
params,
|
|
164
|
-
options
|
|
165
|
-
}?: {
|
|
160
|
+
exists({ token, organizationId, params, options }?: {
|
|
166
161
|
token?: string | null;
|
|
167
162
|
organizationId?: string | null;
|
|
168
163
|
params?: QueryParams;
|
|
169
164
|
options?: Omit<RequestOptions, "token" | "organizationId">;
|
|
170
165
|
}): Promise<boolean>;
|
|
171
166
|
/** Distinct values of a field across matching records (`?_distinct=field`). */
|
|
172
|
-
distinct<TValue = unknown>({
|
|
173
|
-
token,
|
|
174
|
-
organizationId,
|
|
175
|
-
field,
|
|
176
|
-
params,
|
|
177
|
-
options
|
|
178
|
-
}: {
|
|
167
|
+
distinct<TValue = unknown>({ token, organizationId, field, params, options }: {
|
|
179
168
|
token?: string | null;
|
|
180
169
|
organizationId?: string | null;
|
|
181
170
|
field: string;
|
|
@@ -184,13 +173,7 @@ declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, T
|
|
|
184
173
|
}): Promise<TValue[]>;
|
|
185
174
|
/** Shared raw GET against the list route (dispatch verbs bypass pagination parsing). */
|
|
186
175
|
private getAllRaw;
|
|
187
|
-
getById({
|
|
188
|
-
token,
|
|
189
|
-
organizationId,
|
|
190
|
-
id,
|
|
191
|
-
params,
|
|
192
|
-
options
|
|
193
|
-
}: {
|
|
176
|
+
getById({ token, organizationId, id, params, options }: {
|
|
194
177
|
token?: string | null;
|
|
195
178
|
organizationId?: string | null;
|
|
196
179
|
id: string;
|
|
@@ -200,60 +183,33 @@ declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, T
|
|
|
200
183
|
};
|
|
201
184
|
options?: Omit<RequestOptions, "token" | "organizationId">;
|
|
202
185
|
}): Promise<TDoc>;
|
|
203
|
-
create({
|
|
204
|
-
token,
|
|
205
|
-
organizationId,
|
|
206
|
-
data,
|
|
207
|
-
options
|
|
208
|
-
}: {
|
|
186
|
+
create({ token, organizationId, data, options }: {
|
|
209
187
|
token?: string | null;
|
|
210
188
|
organizationId?: string | null;
|
|
211
189
|
data: TCreate;
|
|
212
190
|
options?: Omit<RequestOptions, "token" | "organizationId">;
|
|
213
191
|
}): Promise<TDoc>;
|
|
214
|
-
update({
|
|
215
|
-
token,
|
|
216
|
-
organizationId,
|
|
217
|
-
id,
|
|
218
|
-
data,
|
|
219
|
-
options
|
|
220
|
-
}: {
|
|
192
|
+
update({ token, organizationId, id, data, options }: {
|
|
221
193
|
token?: string | null;
|
|
222
194
|
organizationId?: string | null;
|
|
223
195
|
id: string;
|
|
224
196
|
data: TUpdate;
|
|
225
197
|
options?: Omit<RequestOptions, "token" | "organizationId">;
|
|
226
198
|
}): Promise<TDoc>;
|
|
227
|
-
delete({
|
|
228
|
-
token,
|
|
229
|
-
organizationId,
|
|
230
|
-
id,
|
|
231
|
-
options
|
|
232
|
-
}: {
|
|
199
|
+
delete({ token, organizationId, id, options }: {
|
|
233
200
|
token?: string | null;
|
|
234
201
|
organizationId?: string | null;
|
|
235
202
|
id: string;
|
|
236
203
|
options?: Omit<RequestOptions, "token" | "organizationId">;
|
|
237
204
|
}): Promise<DeleteResult>;
|
|
238
|
-
upload({
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
id
|
|
243
|
-
path,
|
|
244
|
-
options
|
|
245
|
-
}: ScopedArgs & {
|
|
246
|
-
data: FormData; /** Resource ID — shorthand for path, appended as `baseUrl/{id}/upload` */
|
|
247
|
-
id?: string; /** Custom sub-path appended as `baseUrl/{path}`. Takes precedence over `id`. */
|
|
205
|
+
upload({ token, organizationId, data, id, path, options }: ScopedArgs & {
|
|
206
|
+
data: FormData;
|
|
207
|
+
/** Resource ID — shorthand for path, appended as `baseUrl/{id}/upload` */
|
|
208
|
+
id?: string;
|
|
209
|
+
/** Custom sub-path appended as `baseUrl/{path}`. Takes precedence over `id`. */
|
|
248
210
|
path?: string;
|
|
249
211
|
}): Promise<TDoc>;
|
|
250
|
-
request<TResponse = unknown>(method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE", endpoint: string, {
|
|
251
|
-
token,
|
|
252
|
-
organizationId,
|
|
253
|
-
data,
|
|
254
|
-
params,
|
|
255
|
-
options
|
|
256
|
-
}?: ScopedArgs & {
|
|
212
|
+
request<TResponse = unknown>(method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE", endpoint: string, { token, organizationId, data, params, options }?: ScopedArgs & {
|
|
257
213
|
data?: unknown;
|
|
258
214
|
params?: QueryParams;
|
|
259
215
|
}): Promise<TResponse>;
|
|
@@ -290,16 +246,9 @@ declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, T
|
|
|
290
246
|
* data: { source: 'csv', items: [...] },
|
|
291
247
|
* });
|
|
292
248
|
*/
|
|
293
|
-
invokeRoute<TResponse = unknown>({
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
method,
|
|
297
|
-
path,
|
|
298
|
-
data,
|
|
299
|
-
params,
|
|
300
|
-
options
|
|
301
|
-
}: ScopedArgs & {
|
|
302
|
-
method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE"; /** Path relative to the resource baseUrl. Leading slash optional. */
|
|
249
|
+
invokeRoute<TResponse = unknown>({ token, organizationId, method, path, data, params, options }: ScopedArgs & {
|
|
250
|
+
method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
|
|
251
|
+
/** Path relative to the resource baseUrl. Leading slash optional. */
|
|
303
252
|
path: string;
|
|
304
253
|
data?: unknown;
|
|
305
254
|
params?: QueryParams;
|
|
@@ -313,14 +262,9 @@ declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, T
|
|
|
313
262
|
* filter: { from: '2025-01-01', to: '2025-12-31' },
|
|
314
263
|
* });
|
|
315
264
|
*/
|
|
316
|
-
aggregate<TRow extends AggRow = AggRow>({
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
name,
|
|
320
|
-
filter,
|
|
321
|
-
options
|
|
322
|
-
}: ScopedArgs & {
|
|
323
|
-
/** Aggregation name as declared on the resource. */name: string;
|
|
265
|
+
aggregate<TRow extends AggRow = AggRow>({ token, organizationId, name, filter, options }: ScopedArgs & {
|
|
266
|
+
/** Aggregation name as declared on the resource. */
|
|
267
|
+
name: string;
|
|
324
268
|
/**
|
|
325
269
|
* URL-encoded filter narrows + dimension args. Reserved keys (`page`,
|
|
326
270
|
* `limit`, etc.) are stripped server-side; everything else flows into
|
|
@@ -328,14 +272,7 @@ declare class BaseApi<TDoc = Record<string, unknown>, TCreate = Partial<TDoc>, T
|
|
|
328
272
|
*/
|
|
329
273
|
filter?: Record<string, unknown>;
|
|
330
274
|
}): Promise<AggResult<TRow>>;
|
|
331
|
-
dispatchAction<TResult = unknown, TBody extends Record<string, unknown> = Record<string, unknown>>({
|
|
332
|
-
token,
|
|
333
|
-
organizationId,
|
|
334
|
-
id,
|
|
335
|
-
action,
|
|
336
|
-
data,
|
|
337
|
-
options
|
|
338
|
-
}: ScopedArgs & {
|
|
275
|
+
dispatchAction<TResult = unknown, TBody extends Record<string, unknown> = Record<string, unknown>>({ token, organizationId, id, action, data, options }: ScopedArgs & {
|
|
339
276
|
id: string;
|
|
340
277
|
action: string;
|
|
341
278
|
data?: TBody;
|
package/dist/api.js
CHANGED
|
@@ -14,7 +14,8 @@ var BaseApi = class {
|
|
|
14
14
|
requestFn;
|
|
15
15
|
constructor(entity, config = {}) {
|
|
16
16
|
this.entity = entity;
|
|
17
|
-
|
|
17
|
+
const client = config.client;
|
|
18
|
+
this.requestFn = typeof client === "function" ? (method, endpoint, options) => client().request(method, endpoint, options) : client?.request ?? handleApiRequest;
|
|
18
19
|
this.config = {
|
|
19
20
|
basePath: config.basePath ?? "/api/v1",
|
|
20
21
|
defaultParams: {
|
package/dist/cache.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { QueryClient, QueryKey } from "@tanstack/react-query";
|
|
2
|
-
|
|
3
2
|
//#region src/cache.d.ts
|
|
4
3
|
interface PaginationData {
|
|
5
4
|
/** Pagination method detected from response (offset | keyset | aggregate) */
|
|
@@ -21,16 +20,20 @@ declare const DEFAULT_QUERY_CONFIG: {
|
|
|
21
20
|
};
|
|
22
21
|
/** Pre-built query config presets for common data freshness patterns. */
|
|
23
22
|
declare const QUERY_CONFIGS: {
|
|
24
|
-
/** Live data: 20s stale, 30s polling */
|
|
23
|
+
/** Live data: 20s stale, 30s polling */
|
|
24
|
+
readonly realtime: {
|
|
25
25
|
readonly staleTime: 20000;
|
|
26
26
|
readonly refetchInterval: 30000;
|
|
27
|
-
};
|
|
27
|
+
};
|
|
28
|
+
/** Frequently updated: 60s stale */
|
|
28
29
|
readonly frequent: {
|
|
29
30
|
readonly staleTime: 60000;
|
|
30
|
-
};
|
|
31
|
+
};
|
|
32
|
+
/** Stable data: 5min stale (same as default) */
|
|
31
33
|
readonly stable: {
|
|
32
34
|
readonly staleTime: 300000;
|
|
33
|
-
};
|
|
35
|
+
};
|
|
36
|
+
/** Rarely changes: 10min stale */
|
|
34
37
|
readonly static: {
|
|
35
38
|
readonly staleTime: 600000;
|
|
36
39
|
};
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ErrorDetail } from "@classytic/repo-core/errors";
|
|
2
|
-
|
|
3
2
|
//#region src/client.d.ts
|
|
4
3
|
interface ToastHandler {
|
|
5
4
|
success: (message: string) => void;
|
|
@@ -34,7 +33,7 @@ type UseRouterHook = () => {
|
|
|
34
33
|
* `(string & {})` keeps the type open so domain packages and custom
|
|
35
34
|
* `errorMappers` codes still satisfy it.
|
|
36
35
|
*/
|
|
37
|
-
declare const KNOWN_ARC_ERROR_CODES: readonly [...("validation_error" | "not_found" | "conflict" | "unauthorized" | "forbidden" | "rate_limited" | "idempotency_conflict" | "precondition_failed" | "internal_error" | "service_unavailable" | "timeout")[], "arc.bad_request", "arc.unauthorized", "arc.forbidden", "arc.not_found", "arc.conflict", "arc.unprocessable_entity", "arc.rate_limited", "arc.internal_error", "arc.bad_gateway", "arc.service_unavailable", "arc.gateway_timeout", "arc.validation_error", "arc.invalid_id", "arc.org.selection_required", "arc.org.access_denied", "ORG_CONTEXT_REQUIRED", "ORG_ROLE_REQUIRED", "OWNERSHIP_DENIED", "MIXED_UPDATE_SHAPE", "ALL_FIELDS_STRIPPED", "BEFORE_RESTORE_HOOK_ERROR", "duplicate_key"];
|
|
36
|
+
declare const KNOWN_ARC_ERROR_CODES: readonly [...("validation_error" | "not_found" | "conflict" | "unauthorized" | "forbidden" | "rate_limited" | "idempotency_conflict" | "precondition_failed" | "internal_error" | "service_unavailable" | "timeout")[], "arc.bad_request", "arc.unauthorized", "arc.forbidden", "arc.not_found", "arc.conflict", "arc.unprocessable_entity", "arc.rate_limited", "arc.internal_error", "arc.bad_gateway", "arc.service_unavailable", "arc.gateway_timeout", "arc.validation_error", "arc.invalid_id", "arc.tier_required", "arc.org.selection_required", "arc.org.access_denied", "ORG_CONTEXT_REQUIRED", "ORG_ROLE_REQUIRED", "OWNERSHIP_DENIED", "MIXED_UPDATE_SHAPE", "ALL_FIELDS_STRIPPED", "BEFORE_RESTORE_HOOK_ERROR", "duplicate_key"];
|
|
38
37
|
/**
|
|
39
38
|
* Canonical arc error code union. `(string & {})` keeps the type open so
|
|
40
39
|
* domain packages can extend hierarchically (`'order.cart.locked'`,
|
|
@@ -194,6 +193,43 @@ declare function getQuotaDetails(error: unknown): QuotaDetails | null;
|
|
|
194
193
|
* }
|
|
195
194
|
*/
|
|
196
195
|
declare function isOrgContextRequiredError(error: unknown): error is ArcApiError;
|
|
196
|
+
/** The tier/mode a `arc.tier_required` error asked for, plus the active one. */
|
|
197
|
+
interface TierRequirement {
|
|
198
|
+
/** Minimum tier/mode the feature needs (e.g. `"enterprise"`). */
|
|
199
|
+
requiredMode: string;
|
|
200
|
+
/** The deployment's current tier/mode (e.g. `"standard"`). */
|
|
201
|
+
currentMode?: string;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* TIER/CAPABILITY gate predicate. True when the backend refused because the
|
|
205
|
+
* deployment's tier (FLOW_MODE / feature tier) is below what the route needs —
|
|
206
|
+
* a `arc.tier_required` error (arc-inventory's mode gate → arc's
|
|
207
|
+
* `createDomainError`). This is the DISCRIMINABLE counterpart to a bare
|
|
208
|
+
* `arc.forbidden` (a role/permission denial): switch on THIS to render an
|
|
209
|
+
* "upgrade required / requires Enterprise" surface, and on `arc.forbidden` for
|
|
210
|
+
* "access denied". The required tier is available via {@link getTierRequirement}.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* if (isTierRequiredError(error)) {
|
|
214
|
+
* const { requiredMode } = getTierRequirement(error)!;
|
|
215
|
+
* showUpgradePanel(requiredMode); // "requires Enterprise"
|
|
216
|
+
* } else if (isArcErrorCode(error, "arc.forbidden")) {
|
|
217
|
+
* showAccessDenied(); // role/branch problem
|
|
218
|
+
* }
|
|
219
|
+
*/
|
|
220
|
+
declare function isTierRequiredError(error: unknown): error is ArcApiError;
|
|
221
|
+
/**
|
|
222
|
+
* Extract the tier requirement from a `arc.tier_required` error's structured
|
|
223
|
+
* machine-readable context (`{ requiredMode, currentMode }`). Returns `null` for
|
|
224
|
+
* any other error, so the FE never has to hardcode a route→tier map or
|
|
225
|
+
* string-match a message.
|
|
226
|
+
*
|
|
227
|
+
* Reads `meta` (the canonical ErrorContract Record — where both arc gate paths
|
|
228
|
+
* put it: the global error handler serializes `ArcError.meta`, and the
|
|
229
|
+
* permission-slot applier emits the same `meta`). Falls back to `details` for
|
|
230
|
+
* resilience against any backend still emitting the pre-2026-07 shape.
|
|
231
|
+
*/
|
|
232
|
+
declare function getTierRequirement(error: unknown): TierRequirement | null;
|
|
197
233
|
/**
|
|
198
234
|
* Specific predicate for validation failures (Fastify AJV + Mongoose
|
|
199
235
|
* ValidationError). When true, `error.fieldErrors` is populated with the
|
|
@@ -267,6 +303,13 @@ interface ClientConfig {
|
|
|
267
303
|
* @example '2' // sends Accept-Version: 2
|
|
268
304
|
*/
|
|
269
305
|
apiVersion?: string;
|
|
306
|
+
/**
|
|
307
|
+
* Default request cache mode applied to every request that expresses no
|
|
308
|
+
* caching intent of its own (no per-call `cache`, `revalidate`, or `next`) —
|
|
309
|
+
* the client-level analog of `BaseApiConfig.cache`, same precedence rule.
|
|
310
|
+
* Unset = the runtime's fetch default.
|
|
311
|
+
*/
|
|
312
|
+
cache?: RequestCache;
|
|
270
313
|
/**
|
|
271
314
|
* Auto-generate `Idempotency-Key` header for POST/PUT/PATCH requests.
|
|
272
315
|
* Prevents duplicate mutations on network retries.
|
|
@@ -973,4 +1016,4 @@ declare const arc: {
|
|
|
973
1016
|
delete: <T = unknown>(path: string, opts?: ArcFetchOptions) => Promise<T>;
|
|
974
1017
|
};
|
|
975
1018
|
//#endregion
|
|
976
|
-
export { AfterResponseContext, AfterResponseInterceptor, ApiRequestOptions, ArcApiError, ArcApiErrorOptions, ArcClient, ArcClientConfig, ArcErrorCode, ArcFetchOptions, AuthConfig, AuthErrorContext, AuthErrorHandler, BeforeRequestContext, BeforeRequestInterceptor, BlobResponse, ClientConfig, ClientEncryptionConfig, HttpMethod, KNOWN_ARC_ERROR_CODES, NextFetchOptions, QuotaDetails, RetryConfig, ServerClientConfig, StreamUrlProtocol, TextResponse, ToastHandler, UseRouterHook, _getAuthErrorHandler, _isAuthRecoverable, _resetArcFetchClient, _resetAuthRecovery, _resetAuthWarnings, _resolveRefreshedToken, _runAuthRecovery, arc, arcAuthHeaders, arcFetch, buildStreamUrl, configureAuth, configureClient, createAuthAwareClient, createAuthRefreshHandler, createClient, createQueryString, createServerClient, getAuthContext, getAuthMode, getBaseUrl, getClientAuthContext, getQuotaDetails, handleApiRequest, hasGlobalStaticAuth, isAbortError, isArcApiError, isArcErrorCode, isAutoIdempotency, isDuplicateKeyError, isOrgContextRequiredError, isQuotaExceeded, isValidationError };
|
|
1019
|
+
export { AfterResponseContext, AfterResponseInterceptor, ApiRequestOptions, ArcApiError, ArcApiErrorOptions, ArcClient, ArcClientConfig, ArcErrorCode, ArcFetchOptions, AuthConfig, AuthErrorContext, AuthErrorHandler, BeforeRequestContext, BeforeRequestInterceptor, BlobResponse, ClientConfig, ClientEncryptionConfig, HttpMethod, KNOWN_ARC_ERROR_CODES, NextFetchOptions, QuotaDetails, RetryConfig, ServerClientConfig, StreamUrlProtocol, TextResponse, TierRequirement, ToastHandler, UseRouterHook, _getAuthErrorHandler, _isAuthRecoverable, _resetArcFetchClient, _resetAuthRecovery, _resetAuthWarnings, _resolveRefreshedToken, _runAuthRecovery, arc, arcAuthHeaders, arcFetch, buildStreamUrl, configureAuth, configureClient, createAuthAwareClient, createAuthRefreshHandler, createClient, createQueryString, createServerClient, getAuthContext, getAuthMode, getBaseUrl, getClientAuthContext, getQuotaDetails, getTierRequirement, handleApiRequest, hasGlobalStaticAuth, isAbortError, isArcApiError, isArcErrorCode, isAutoIdempotency, isDuplicateKeyError, isOrgContextRequiredError, isQuotaExceeded, isTierRequiredError, isValidationError };
|
package/dist/client.js
CHANGED
|
@@ -37,6 +37,7 @@ const KNOWN_ARC_ERROR_CODES = [
|
|
|
37
37
|
"arc.gateway_timeout",
|
|
38
38
|
"arc.validation_error",
|
|
39
39
|
"arc.invalid_id",
|
|
40
|
+
"arc.tier_required",
|
|
40
41
|
"arc.org.selection_required",
|
|
41
42
|
"arc.org.access_denied",
|
|
42
43
|
"ORG_CONTEXT_REQUIRED",
|
|
@@ -243,6 +244,48 @@ function isOrgContextRequiredError(error) {
|
|
|
243
244
|
return isArcErrorCode(error, "ORG_CONTEXT_REQUIRED");
|
|
244
245
|
}
|
|
245
246
|
/**
|
|
247
|
+
* TIER/CAPABILITY gate predicate. True when the backend refused because the
|
|
248
|
+
* deployment's tier (FLOW_MODE / feature tier) is below what the route needs —
|
|
249
|
+
* a `arc.tier_required` error (arc-inventory's mode gate → arc's
|
|
250
|
+
* `createDomainError`). This is the DISCRIMINABLE counterpart to a bare
|
|
251
|
+
* `arc.forbidden` (a role/permission denial): switch on THIS to render an
|
|
252
|
+
* "upgrade required / requires Enterprise" surface, and on `arc.forbidden` for
|
|
253
|
+
* "access denied". The required tier is available via {@link getTierRequirement}.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* if (isTierRequiredError(error)) {
|
|
257
|
+
* const { requiredMode } = getTierRequirement(error)!;
|
|
258
|
+
* showUpgradePanel(requiredMode); // "requires Enterprise"
|
|
259
|
+
* } else if (isArcErrorCode(error, "arc.forbidden")) {
|
|
260
|
+
* showAccessDenied(); // role/branch problem
|
|
261
|
+
* }
|
|
262
|
+
*/
|
|
263
|
+
function isTierRequiredError(error) {
|
|
264
|
+
return isArcErrorCode(error, "arc.tier_required");
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Extract the tier requirement from a `arc.tier_required` error's structured
|
|
268
|
+
* machine-readable context (`{ requiredMode, currentMode }`). Returns `null` for
|
|
269
|
+
* any other error, so the FE never has to hardcode a route→tier map or
|
|
270
|
+
* string-match a message.
|
|
271
|
+
*
|
|
272
|
+
* Reads `meta` (the canonical ErrorContract Record — where both arc gate paths
|
|
273
|
+
* put it: the global error handler serializes `ArcError.meta`, and the
|
|
274
|
+
* permission-slot applier emits the same `meta`). Falls back to `details` for
|
|
275
|
+
* resilience against any backend still emitting the pre-2026-07 shape.
|
|
276
|
+
*/
|
|
277
|
+
function getTierRequirement(error) {
|
|
278
|
+
if (!isTierRequiredError(error)) return null;
|
|
279
|
+
const j = error.json ?? {};
|
|
280
|
+
const bag = j.meta ?? j.details ?? {};
|
|
281
|
+
const requiredMode = bag.requiredMode;
|
|
282
|
+
if (typeof requiredMode !== "string") return null;
|
|
283
|
+
return {
|
|
284
|
+
requiredMode,
|
|
285
|
+
...typeof bag.currentMode === "string" ? { currentMode: bag.currentMode } : {}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
246
289
|
* Specific predicate for validation failures (Fastify AJV + Mongoose
|
|
247
290
|
* ValidationError). When true, `error.fieldErrors` is populated with the
|
|
248
291
|
* `{ field: message }` map. Matches arc's `arc.validation_error` and the
|
|
@@ -756,6 +799,10 @@ async function executeRequest(config, method, endpoint, options = {}) {
|
|
|
756
799
|
...options,
|
|
757
800
|
idempotencyKey: globalThis.crypto.randomUUID()
|
|
758
801
|
};
|
|
802
|
+
if (config.cache !== void 0 && options.cache === void 0 && options.revalidate === void 0 && options.next === void 0) options = {
|
|
803
|
+
...options,
|
|
804
|
+
cache: config.cache
|
|
805
|
+
};
|
|
759
806
|
const handler = authConfig?.onAuthError;
|
|
760
807
|
if (!handler) return executeWithBackoff(config, method, endpoint, options);
|
|
761
808
|
const retryOn403 = authConfig?.retryOn403 ?? false;
|
|
@@ -899,7 +946,7 @@ async function executeAttempt(config, method, endpoint, options, attempt) {
|
|
|
899
946
|
if (revalidate !== void 0) nextCfg.revalidate = revalidate;
|
|
900
947
|
if (tags) nextCfg.tags = nextCfg.tags ? [...nextCfg.tags, ...tags] : tags;
|
|
901
948
|
if (nextCfg.revalidate !== void 0 || nextCfg.tags) fetchOptions.next = nextCfg;
|
|
902
|
-
if (!/^https?:\/\//i.test(endpoint) && !config.baseUrl) throw new Error(`[arc-next] handleApiRequest(${method} ${endpoint}): baseUrl is empty.
|
|
949
|
+
if (!/^https?:\/\//i.test(endpoint) && !config.baseUrl) throw new Error(`[arc-next] handleApiRequest(${method} ${endpoint}): baseUrl is empty. ` + (typeof window === "undefined" ? "On the server, configureClient() is a no-op — configure a request-scoped client instead: createServerClient({ baseUrl }), or your SDK's server config (e.g. a server env baseUrl / runWithSDKConfig) so SSR reads resolve." : "Call configureClient({ baseUrl: '...' }) at app boot (Providers) BEFORE the first request — e.g. in a useState() initializer, before the children render."));
|
|
903
950
|
const response = await fetch(`${config.baseUrl}${endpoint}`, fetchOptions);
|
|
904
951
|
if (!response.ok) {
|
|
905
952
|
let json = null;
|
|
@@ -1105,7 +1152,7 @@ function arcAuthHeaders() {
|
|
|
1105
1152
|
* Lower-cased on lookup so case-insensitive HTTP header semantics are
|
|
1106
1153
|
* honored (`Authorization` vs `authorization` both protected).
|
|
1107
1154
|
*/
|
|
1108
|
-
const ARC_FETCH_PROTECTED_HEADERS = new Set([
|
|
1155
|
+
const ARC_FETCH_PROTECTED_HEADERS = /* @__PURE__ */ new Set([
|
|
1109
1156
|
"authorization",
|
|
1110
1157
|
"x-organization-id",
|
|
1111
1158
|
"x-internal-api-key"
|
|
@@ -1227,4 +1274,4 @@ const arc = {
|
|
|
1227
1274
|
};
|
|
1228
1275
|
|
|
1229
1276
|
//#endregion
|
|
1230
|
-
export { ArcApiError, KNOWN_ARC_ERROR_CODES, _getAuthErrorHandler, _isAuthRecoverable, _resetArcFetchClient, _resetAuthRecovery, _resetAuthWarnings, _resolveRefreshedToken, _runAuthRecovery, arc, arcAuthHeaders, arcFetch, buildStreamUrl, configureAuth, configureClient, createAuthAwareClient, createAuthRefreshHandler, createClient, createQueryString, createServerClient, getAuthContext, getAuthMode, getBaseUrl, getClientAuthContext, getQuotaDetails, handleApiRequest, hasGlobalStaticAuth, isAbortError, isArcApiError, isArcErrorCode, isAutoIdempotency, isDuplicateKeyError, isOrgContextRequiredError, isQuotaExceeded, isValidationError };
|
|
1277
|
+
export { ArcApiError, KNOWN_ARC_ERROR_CODES, _getAuthErrorHandler, _isAuthRecoverable, _resetArcFetchClient, _resetAuthRecovery, _resetAuthWarnings, _resolveRefreshedToken, _runAuthRecovery, arc, arcAuthHeaders, arcFetch, buildStreamUrl, configureAuth, configureClient, createAuthAwareClient, createAuthRefreshHandler, createClient, createQueryString, createServerClient, getAuthContext, getAuthMode, getBaseUrl, getClientAuthContext, getQuotaDetails, getTierRequirement, handleApiRequest, hasGlobalStaticAuth, isAbortError, isArcApiError, isArcErrorCode, isAutoIdempotency, isDuplicateKeyError, isOrgContextRequiredError, isQuotaExceeded, isTierRequiredError, isValidationError };
|
package/dist/encryption.d.ts
CHANGED
package/dist/hooks.d.ts
CHANGED
|
@@ -10,7 +10,6 @@ import { TreeMethods } from "./presets/tree.js";
|
|
|
10
10
|
import { DetailQueryOptions, DetailQueryResult, InfiniteListQueryOptions, InfiniteListQueryResult, ListQueryOptions, ListQueryResult, RequestPassthrough } from "./query.js";
|
|
11
11
|
import { QueryKey, UseQueryResult } from "@tanstack/react-query";
|
|
12
12
|
import { PaginatedResult } from "@classytic/repo-core/pagination";
|
|
13
|
-
|
|
14
13
|
//#region src/hooks.d.ts
|
|
15
14
|
/**
|
|
16
15
|
* CRUD API interface accepted by createCrudHooks.
|
|
@@ -25,7 +24,8 @@ import { PaginatedResult } from "@classytic/repo-core/pagination";
|
|
|
25
24
|
type CrudApi<T = unknown, TCreate = Partial<T>, TUpdate = Partial<T>> = Pick<BaseApi<T, TCreate, TUpdate>, "getAll" | "getById" | "create" | "update" | "delete" | "count"> & {
|
|
26
25
|
upload?: BaseApi<T, TCreate, TUpdate>["upload"];
|
|
27
26
|
dispatchAction?: BaseApi<T, TCreate, TUpdate>["dispatchAction"];
|
|
28
|
-
invokeRoute?: BaseApi<T, TCreate, TUpdate>["invokeRoute"];
|
|
27
|
+
invokeRoute?: BaseApi<T, TCreate, TUpdate>["invokeRoute"];
|
|
28
|
+
/** Declared aggregations (arc 2.13+). Always available on BaseApi. */
|
|
29
29
|
aggregate?: BaseApi<T, TCreate, TUpdate>["aggregate"];
|
|
30
30
|
} & Partial<SoftDeleteMethods<T>> & Partial<BulkMethods<T, TCreate, TUpdate>> & Partial<SlugLookupMethods<T>> & Partial<TreeMethods<T>> & Partial<SearchPresetMethods<T>>;
|
|
31
31
|
/** Args + options for `useAggregation`. Mirrors `ListQueryOptions` for DX consistency. */
|
|
@@ -182,11 +182,15 @@ interface CrudHooksReturn<T, TCreate, TUpdate> {
|
|
|
182
182
|
KEYS: QueryKeys;
|
|
183
183
|
cache: CacheUtils<T>;
|
|
184
184
|
useList: {
|
|
185
|
-
/** New signature — auto-injects token/orgId from configureAuth() context */
|
|
185
|
+
/** New signature — auto-injects token/orgId from configureAuth() context */
|
|
186
|
+
(params?: Record<string, unknown>, options?: ListQueryOptions<T>): ListQueryResult<T>;
|
|
187
|
+
/** Legacy signature — explicit token */
|
|
186
188
|
(token: string | null, params?: Record<string, unknown>, options?: ListQueryOptions<T>): ListQueryResult<T>;
|
|
187
189
|
};
|
|
188
190
|
useDetail: {
|
|
189
|
-
/** New signature — auto-injects token from configureAuth() context */
|
|
191
|
+
/** New signature — auto-injects token from configureAuth() context */
|
|
192
|
+
(id: string | null, options?: DetailQueryOptions<T>): DetailQueryResult<T>;
|
|
193
|
+
/** Legacy signature — explicit token */
|
|
190
194
|
(id: string | null, token: string | null, options?: DetailQueryOptions<T>): DetailQueryResult<T>;
|
|
191
195
|
};
|
|
192
196
|
/**
|
|
@@ -202,7 +206,9 @@ interface CrudHooksReturn<T, TCreate, TUpdate> {
|
|
|
202
206
|
*/
|
|
203
207
|
useSuspenseDetail: (id: string, options?: Omit<DetailQueryOptions<T>, "enabled">) => DetailQueryResult<T>;
|
|
204
208
|
useInfiniteList: {
|
|
205
|
-
/** New signature — auto-injects token/orgId from configureAuth() context */
|
|
209
|
+
/** New signature — auto-injects token/orgId from configureAuth() context */
|
|
210
|
+
(params?: Record<string, unknown>, options?: InfiniteListQueryOptions): InfiniteListQueryResult<T>;
|
|
211
|
+
/** Legacy signature — explicit token */
|
|
206
212
|
(token: string | null, params?: Record<string, unknown>, options?: InfiniteListQueryOptions): InfiniteListQueryResult<T>;
|
|
207
213
|
};
|
|
208
214
|
useActions: () => CrudActions<T, TCreate, TUpdate>;
|
|
@@ -223,7 +229,8 @@ interface CrudHooksReturn<T, TCreate, TUpdate> {
|
|
|
223
229
|
* (approve/cancel/dispatch) instead of bespoke routes.
|
|
224
230
|
*/
|
|
225
231
|
useAction: <TResult = T, TBody extends Record<string, unknown> = Record<string, unknown>>(options?: {
|
|
226
|
-
invalidateQueries?: QueryKey[];
|
|
232
|
+
invalidateQueries?: QueryKey[];
|
|
233
|
+
/** Default action name. Can be overridden per-call via `mutate({ action })`. */
|
|
227
234
|
action?: string;
|
|
228
235
|
messages?: MutationMessages<TResult, {
|
|
229
236
|
id: string;
|
|
@@ -335,15 +342,20 @@ interface CrudHooksReturn<T, TCreate, TUpdate> {
|
|
|
335
342
|
* `ssePlugin` (`/events/stream`). Pass `enabled: false` to opt out.
|
|
336
343
|
*/
|
|
337
344
|
useResourceSync: (options?: {
|
|
338
|
-
source?: "ws" | "sse";
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
345
|
+
source?: "ws" | "sse";
|
|
346
|
+
/** Override resource name. Defaults to the factory's `entityKey`. */
|
|
347
|
+
resource?: string;
|
|
348
|
+
/** Override path (default: `/ws` or `/events/stream`). */
|
|
349
|
+
path?: string;
|
|
350
|
+
/** Whether the connection is active. Default: true. */
|
|
351
|
+
enabled?: boolean;
|
|
352
|
+
/** Per-event hook fired AFTER cache invalidation. */
|
|
342
353
|
onEvent?: (event: {
|
|
343
354
|
operation: "created" | "updated" | "deleted";
|
|
344
355
|
id?: string;
|
|
345
356
|
data: unknown;
|
|
346
|
-
}) => void;
|
|
357
|
+
}) => void;
|
|
358
|
+
/** Connection-state listener. */
|
|
347
359
|
onConnectionChange?: (connected: boolean) => void;
|
|
348
360
|
}) => {
|
|
349
361
|
isConnected: boolean;
|
|
@@ -360,15 +372,6 @@ interface CrudHooksReturn<T, TCreate, TUpdate> {
|
|
|
360
372
|
* configureNavigation(useRouter);
|
|
361
373
|
*/
|
|
362
374
|
declare function configureNavigation(hook: UseRouterHook): void;
|
|
363
|
-
declare function createCrudHooks<T, TCreate = Partial<T>, TUpdate = Partial<T>>({
|
|
364
|
-
api,
|
|
365
|
-
entityKey,
|
|
366
|
-
singular,
|
|
367
|
-
plural,
|
|
368
|
-
idField,
|
|
369
|
-
defaults,
|
|
370
|
-
callbacks,
|
|
371
|
-
client
|
|
372
|
-
}: CrudHooksConfig<T, TCreate, TUpdate>): CrudHooksReturn<T, TCreate, TUpdate>;
|
|
375
|
+
declare function createCrudHooks<T, TCreate = Partial<T>, TUpdate = Partial<T>>({ api, entityKey, singular, plural, idField, defaults, callbacks, client }: CrudHooksConfig<T, TCreate, TUpdate>): CrudHooksReturn<T, TCreate, TUpdate>;
|
|
373
376
|
//#endregion
|
|
374
377
|
export { AggregationQueryOptions, BulkActions, CallOptions, CrudActions, CrudApi, CrudHooksConfig, CrudHooksReturn, DeleteParams, MutationParams, NavigateFn, NavigationOptions, UpdateParams, configureNavigation, createCrudHooks };
|
package/dist/mutation.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { ToastHandler } from "./client.js";
|
|
2
|
-
import * as _$_tanstack_react_query0 from "@tanstack/react-query";
|
|
3
2
|
import { QueryClient, QueryKey, UseMutateAsyncFunction, UseMutateFunction } from "@tanstack/react-query";
|
|
4
|
-
|
|
5
3
|
//#region src/mutation.d.ts
|
|
6
4
|
/**
|
|
7
5
|
* Toast copy for a mutation. Generic over the mutation's result/variables so
|
|
@@ -152,7 +150,7 @@ interface CreateOptimisticMutationConfig<TData, TVariables> {
|
|
|
152
150
|
shouldToast?: () => boolean;
|
|
153
151
|
toastHandler?: ToastHandler;
|
|
154
152
|
}
|
|
155
|
-
declare function useOptimisticMutation<TData, TVariables>(config: CreateOptimisticMutationConfig<TData, TVariables>):
|
|
153
|
+
declare function useOptimisticMutation<TData, TVariables>(config: CreateOptimisticMutationConfig<TData, TVariables>): import("@tanstack/react-query").UseMutationResult<TData, Error, TVariables, {
|
|
156
154
|
previous: {
|
|
157
155
|
key: readonly unknown[];
|
|
158
156
|
data: [readonly unknown[], unknown][];
|
package/dist/prefetch.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { EntityReadApi } from "./query-options.js";
|
|
2
2
|
import { HydrationBoundary, InfiniteData, QueryClient, dehydrate } from "@tanstack/react-query";
|
|
3
|
-
|
|
4
3
|
//#region src/prefetch.d.ts
|
|
5
4
|
interface PrefetchAuthContext {
|
|
6
5
|
/** Auth token for protected endpoints. Required for bearer/header auth on server. */
|
package/dist/presets/bulk.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnyBaseApi, CreateOf, DocOf, ScopedArgs, UpdateOf } from "../api.js";
|
|
2
2
|
import { BulkCreateResult, DeleteManyResult, UpdateManyResult } from "@classytic/repo-core/repository";
|
|
3
|
-
|
|
4
3
|
//#region src/presets/bulk.d.ts
|
|
5
4
|
interface BulkMethods<TDoc, TCreate = Partial<TDoc>, TUpdate = Partial<TDoc>> {
|
|
6
5
|
/** Insert many docs in one round-trip. Backend mounts `POST /:resource/bulk`. */
|
package/dist/presets/search.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnyBaseApi, DocOf, ScopedArgs } from "../api.js";
|
|
2
2
|
import { PaginatedResult } from "@classytic/repo-core/pagination";
|
|
3
|
-
|
|
4
3
|
//#region src/presets/search.d.ts
|
|
5
4
|
interface SearchPresetMethods<TDoc> {
|
|
6
5
|
/**
|
|
@@ -8,8 +7,11 @@ interface SearchPresetMethods<TDoc> {
|
|
|
8
7
|
* Backend mounts `POST /:resource/search` via `searchPreset()`.
|
|
9
8
|
*/
|
|
10
9
|
searchEngine<TResult = TDoc, TBody extends Record<string, unknown> = Record<string, unknown>>(args?: ScopedArgs & {
|
|
11
|
-
/** Free-text query forwarded as `body.query`. */
|
|
12
|
-
|
|
10
|
+
/** Free-text query forwarded as `body.query`. */
|
|
11
|
+
query?: string;
|
|
12
|
+
/** Engine-specific options merged into the request body. */
|
|
13
|
+
body?: TBody;
|
|
14
|
+
/** Override path (default `/search`). */
|
|
13
15
|
path?: string;
|
|
14
16
|
}): Promise<TResult[] | PaginatedResult<TResult>>;
|
|
15
17
|
/**
|
|
@@ -17,9 +19,13 @@ interface SearchPresetMethods<TDoc> {
|
|
|
17
19
|
* Backend mounts `POST /:resource/search-similar`.
|
|
18
20
|
*/
|
|
19
21
|
searchSimilar<TResult = TDoc, TBody extends Record<string, unknown> = Record<string, unknown>>(args?: ScopedArgs & {
|
|
20
|
-
/** Text query — backend embeds and searches for nearest neighbors. */
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
/** Text query — backend embeds and searches for nearest neighbors. */
|
|
23
|
+
query?: string;
|
|
24
|
+
/** Pre-computed embedding vector — used directly for similarity search. */
|
|
25
|
+
vector?: number[];
|
|
26
|
+
/** Vector-engine options (`topK`, `filter`, `index`, ...). */
|
|
27
|
+
body?: TBody;
|
|
28
|
+
/** Override path (default `/search-similar`). */
|
|
23
29
|
path?: string;
|
|
24
30
|
}): Promise<TResult[]>;
|
|
25
31
|
/**
|
|
@@ -27,8 +33,11 @@ interface SearchPresetMethods<TDoc> {
|
|
|
27
33
|
* Backend mounts `POST /:resource/embed`.
|
|
28
34
|
*/
|
|
29
35
|
embed(args: ScopedArgs & {
|
|
30
|
-
/** Text or array of texts to embed. */
|
|
31
|
-
|
|
36
|
+
/** Text or array of texts to embed. */
|
|
37
|
+
input: string | string[];
|
|
38
|
+
/** Embed-engine options (`model`, `dimensions`, ...). */
|
|
39
|
+
body?: Record<string, unknown>;
|
|
40
|
+
/** Override path (default `/embed`). */
|
|
32
41
|
path?: string;
|
|
33
42
|
}): Promise<number[] | number[][]>;
|
|
34
43
|
}
|
package/dist/presets/slug.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnyBaseApi, DocOf, QueryParams, ScopedArgs } from "../api.js";
|
|
2
2
|
import { PaginatedResult } from "@classytic/repo-core/pagination";
|
|
3
|
-
|
|
4
3
|
//#region src/presets/soft-delete.d.ts
|
|
5
4
|
interface SoftDeleteMethods<TDoc> {
|
|
6
5
|
/** List soft-deleted docs. Backend mounts `GET /:resource/deleted`. */
|
package/dist/presets/tree.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnyBaseApi, DocOf, QueryParams, ScopedArgs } from "../api.js";
|
|
2
2
|
import { PaginatedResult } from "@classytic/repo-core/pagination";
|
|
3
|
-
|
|
4
3
|
//#region src/presets/tree.d.ts
|
|
5
4
|
interface TreeMethods<TDoc> {
|
|
6
5
|
/** Fetch the full hierarchy. Backend mounts `GET /:resource/tree`. */
|
package/dist/query-client.d.ts
CHANGED
package/dist/query-options.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { QueryKeys } from "./cache.js";
|
|
2
|
-
import * as _$_tanstack_react_query0 from "@tanstack/react-query";
|
|
3
|
-
|
|
4
2
|
//#region src/query-options.d.ts
|
|
5
3
|
/** Per-call request context: auth + Next.js fetch caching passthrough. */
|
|
6
4
|
interface QueryFnContext {
|
|
@@ -91,57 +89,65 @@ type EntityQueries = ReturnType<typeof createEntityQueries>;
|
|
|
91
89
|
* await queryClient.ensureQueryData(productQueries.detail(id, { token }));
|
|
92
90
|
*/
|
|
93
91
|
declare function createEntityQueries(api: EntityReadApi, entityKey: string): {
|
|
94
|
-
/** The entity's key factory — for invalidation / setQueryData at call sites. */
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
/** The entity's key factory — for invalidation / setQueryData at call sites. */
|
|
93
|
+
keys: QueryKeys;
|
|
94
|
+
/** GET /:resource — mirrors `useList`'s key (scoped, org-normalized). */
|
|
95
|
+
list(params?: Record<string, unknown>, ctx?: QueryFnContext): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, readonly unknown[]>, "queryFn"> & {
|
|
96
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, readonly unknown[], never> | undefined;
|
|
97
97
|
} & {
|
|
98
98
|
queryKey: readonly unknown[] & {
|
|
99
99
|
[dataTagSymbol]: unknown;
|
|
100
100
|
[dataTagErrorSymbol]: Error;
|
|
101
101
|
};
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
};
|
|
103
|
+
/** GET /:resource/:id — mirrors `useDetail`'s scoped key (+ params variant). */
|
|
104
|
+
detail(id: string, opts?: DetailQueryOpts): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, readonly unknown[]>, "queryFn"> & {
|
|
105
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, readonly unknown[], never> | undefined;
|
|
105
106
|
} & {
|
|
106
107
|
queryKey: readonly unknown[] & {
|
|
107
108
|
[dataTagSymbol]: unknown;
|
|
108
109
|
[dataTagErrorSymbol]: Error;
|
|
109
110
|
};
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
};
|
|
112
|
+
/** GET /:resource/slug/:slug — mirrors `useDetailBySlug`'s key. */
|
|
113
|
+
bySlug(slug: string, opts?: DetailQueryOpts): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, readonly unknown[]>, "queryFn"> & {
|
|
114
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, readonly unknown[], never> | undefined;
|
|
113
115
|
} & {
|
|
114
116
|
queryKey: readonly unknown[] & {
|
|
115
117
|
[dataTagSymbol]: unknown;
|
|
116
118
|
[dataTagErrorSymbol]: Error;
|
|
117
119
|
};
|
|
118
|
-
};
|
|
119
|
-
deleted
|
|
120
|
-
|
|
120
|
+
};
|
|
121
|
+
/** GET /:resource/deleted — mirrors `useDeleted`'s key. */
|
|
122
|
+
deleted(params?: Record<string, unknown>, ctx?: QueryFnContext): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, readonly unknown[]>, "queryFn"> & {
|
|
123
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, readonly unknown[], never> | undefined;
|
|
121
124
|
} & {
|
|
122
125
|
queryKey: readonly unknown[] & {
|
|
123
126
|
[dataTagSymbol]: unknown;
|
|
124
127
|
[dataTagErrorSymbol]: Error;
|
|
125
128
|
};
|
|
126
|
-
};
|
|
127
|
-
tree
|
|
128
|
-
|
|
129
|
+
};
|
|
130
|
+
/** GET /:resource/tree — mirrors `useTree`'s key. */
|
|
131
|
+
tree(params?: Record<string, unknown>, ctx?: QueryFnContext): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, readonly unknown[]>, "queryFn"> & {
|
|
132
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, readonly unknown[], never> | undefined;
|
|
129
133
|
} & {
|
|
130
134
|
queryKey: readonly unknown[] & {
|
|
131
135
|
[dataTagSymbol]: unknown;
|
|
132
136
|
[dataTagErrorSymbol]: Error;
|
|
133
137
|
};
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
};
|
|
139
|
+
/** GET /:resource/:parentId/children — mirrors `useChildren`'s key. */
|
|
140
|
+
children(parentId: string, params?: Record<string, unknown>, ctx?: QueryFnContext): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, readonly unknown[]>, "queryFn"> & {
|
|
141
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, readonly unknown[], never> | undefined;
|
|
137
142
|
} & {
|
|
138
143
|
queryKey: readonly unknown[] & {
|
|
139
144
|
[dataTagSymbol]: unknown;
|
|
140
145
|
[dataTagErrorSymbol]: Error;
|
|
141
146
|
};
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
};
|
|
148
|
+
/** GET /:resource/aggregations/:name — mirrors `useAggregation`'s tenant-scoped key. */
|
|
149
|
+
aggregation(name: string, filter?: Record<string, unknown>, ctx?: QueryFnContext): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, readonly unknown[]>, "queryFn"> & {
|
|
150
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, readonly unknown[], never> | undefined;
|
|
145
151
|
} & {
|
|
146
152
|
queryKey: readonly unknown[] & {
|
|
147
153
|
[dataTagSymbol]: unknown;
|
|
@@ -152,11 +158,11 @@ declare function createEntityQueries(api: EntityReadApi, entityKey: string): {
|
|
|
152
158
|
* Infinite list — mirrors `useInfiniteList`'s key (`scopedList + 'infinite'`)
|
|
153
159
|
* and its page-param semantics (keyset cursor or offset page + 1).
|
|
154
160
|
*/
|
|
155
|
-
infiniteList(params?: Record<string, unknown>, ctx?: QueryFnContext):
|
|
156
|
-
queryFn?:
|
|
161
|
+
infiniteList(params?: Record<string, unknown>, ctx?: QueryFnContext): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseInfiniteQueryOptions<unknown, Error, import("@tanstack/react-query").InfiniteData<unknown, unknown>, unknown[], unknown>, "queryFn"> & {
|
|
162
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<unknown, unknown[], unknown> | undefined;
|
|
157
163
|
} & {
|
|
158
164
|
queryKey: unknown[] & {
|
|
159
|
-
[dataTagSymbol]:
|
|
165
|
+
[dataTagSymbol]: import("@tanstack/react-query").InfiniteData<unknown, unknown>;
|
|
160
166
|
[dataTagErrorSymbol]: Error;
|
|
161
167
|
};
|
|
162
168
|
};
|
package/dist/query.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { CacheUtils, DEFAULT_QUERY_CONFIG, PaginationData, QUERY_CONFIGS, QueryKeys, createCacheUtils, createQueryKeys, extractItem, extractItems, getItemId, normalizePagination, updateListCache } from "./cache.js";
|
|
2
2
|
import { InfiniteData, QueryClient, QueryKey } from "@tanstack/react-query";
|
|
3
|
-
|
|
4
3
|
//#region src/query.d.ts
|
|
5
4
|
/** Request-level options passed through to the fetch call */
|
|
6
5
|
interface RequestPassthrough {
|
|
@@ -143,13 +142,7 @@ interface CreateListQueryConfig {
|
|
|
143
142
|
* directly via `placeholderData`, so the detail GET still fires while the
|
|
144
143
|
* consumer sees an instant list-shaped preview. See `findItemInListCache`.
|
|
145
144
|
*/
|
|
146
|
-
declare function useListQuery<T>({
|
|
147
|
-
queryKey,
|
|
148
|
-
queryFn,
|
|
149
|
-
enabled,
|
|
150
|
-
options,
|
|
151
|
-
select
|
|
152
|
-
}: CreateListQueryConfig): ListQueryResult<T>;
|
|
145
|
+
declare function useListQuery<T>({ queryKey, queryFn, enabled, options, select }: CreateListQueryConfig): ListQueryResult<T>;
|
|
153
146
|
/**
|
|
154
147
|
* Find an item in any list cache for this entity by ID.
|
|
155
148
|
*
|
|
@@ -187,28 +180,11 @@ interface CreateDetailQueryConfig<T = unknown> {
|
|
|
187
180
|
*/
|
|
188
181
|
placeholderData?: () => T | undefined;
|
|
189
182
|
}
|
|
190
|
-
declare function useDetailQuery<T>({
|
|
191
|
-
queryKey,
|
|
192
|
-
queryFn,
|
|
193
|
-
enabled,
|
|
194
|
-
options,
|
|
195
|
-
select,
|
|
196
|
-
placeholderData
|
|
197
|
-
}: CreateDetailQueryConfig<T>): DetailQueryResult<T>;
|
|
183
|
+
declare function useDetailQuery<T>({ queryKey, queryFn, enabled, options, select, placeholderData }: CreateDetailQueryConfig<T>): DetailQueryResult<T>;
|
|
198
184
|
/** Suspense variant of {@link useListQuery}. Always enabled; suspends until resolved. */
|
|
199
|
-
declare function useSuspenseListQuery<T>({
|
|
200
|
-
queryKey,
|
|
201
|
-
queryFn,
|
|
202
|
-
options,
|
|
203
|
-
select
|
|
204
|
-
}: Omit<CreateListQueryConfig, "enabled">): ListQueryResult<T>;
|
|
185
|
+
declare function useSuspenseListQuery<T>({ queryKey, queryFn, options, select }: Omit<CreateListQueryConfig, "enabled">): ListQueryResult<T>;
|
|
205
186
|
/** Suspense variant of {@link useDetailQuery}. Always enabled; suspends until resolved. */
|
|
206
|
-
declare function useSuspenseDetailQuery<T>({
|
|
207
|
-
queryKey,
|
|
208
|
-
queryFn,
|
|
209
|
-
options,
|
|
210
|
-
select
|
|
211
|
-
}: Omit<CreateDetailQueryConfig<T>, "enabled" | "placeholderData">): DetailQueryResult<T>;
|
|
187
|
+
declare function useSuspenseDetailQuery<T>({ queryKey, queryFn, options, select }: Omit<CreateDetailQueryConfig<T>, "enabled" | "placeholderData">): DetailQueryResult<T>;
|
|
212
188
|
interface InfiniteListQueryOptions {
|
|
213
189
|
public?: boolean;
|
|
214
190
|
enabled?: boolean;
|
|
@@ -257,16 +233,7 @@ interface CreateInfiniteListQueryConfig {
|
|
|
257
233
|
/** Max pages to keep in memory. Old pages are evicted when exceeded. */
|
|
258
234
|
maxPages?: number;
|
|
259
235
|
}
|
|
260
|
-
declare function useInfiniteListQuery<T>({
|
|
261
|
-
queryKey,
|
|
262
|
-
queryFn,
|
|
263
|
-
enabled,
|
|
264
|
-
options,
|
|
265
|
-
initialPageParam,
|
|
266
|
-
getNextPageParam,
|
|
267
|
-
getPreviousPageParam,
|
|
268
|
-
maxPages
|
|
269
|
-
}: CreateInfiniteListQueryConfig): InfiniteListQueryResult<T>;
|
|
236
|
+
declare function useInfiniteListQuery<T>({ queryKey, queryFn, enabled, options, initialPageParam, getNextPageParam, getPreviousPageParam, maxPages }: CreateInfiniteListQueryConfig): InfiniteListQueryResult<T>;
|
|
270
237
|
/** Recognized data-freshness presets. Maps to QUERY_CONFIGS. */
|
|
271
238
|
type QueryFreshness = keyof typeof QUERY_CONFIGS;
|
|
272
239
|
/**
|
|
@@ -342,13 +309,6 @@ interface UseApiQueryResult<TData> {
|
|
|
342
309
|
* select: (res) => res.entries,
|
|
343
310
|
* });
|
|
344
311
|
*/
|
|
345
|
-
declare function useApiQuery<TResponse = unknown, TData = ExtractData<TResponse>>({
|
|
346
|
-
queryKey,
|
|
347
|
-
queryFn,
|
|
348
|
-
enabled,
|
|
349
|
-
freshness,
|
|
350
|
-
select,
|
|
351
|
-
options
|
|
352
|
-
}: UseApiQueryConfig<TResponse, TData>): UseApiQueryResult<TData>;
|
|
312
|
+
declare function useApiQuery<TResponse = unknown, TData = ExtractData<TResponse>>({ queryKey, queryFn, enabled, freshness, select, options }: UseApiQueryConfig<TResponse, TData>): UseApiQueryResult<TData>;
|
|
353
313
|
//#endregion
|
|
354
314
|
export { type CacheUtils, CreateDetailQueryConfig, CreateInfiniteListQueryConfig, CreateListQueryConfig, DEFAULT_QUERY_CONFIG, DetailQueryOptions, DetailQueryResult, ExtractData, InfiniteListQueryOptions, InfiniteListQueryResult, ListQueryOptions, ListQueryResult, type PaginationData, QUERY_CONFIGS, QueryFreshness, type QueryKeys, RequestPassthrough, UseApiQueryConfig, UseApiQueryOptions, UseApiQueryResult, createCacheUtils, createQueryKeys, extractItem, extractItems, findItemInListCache, getItemId, normalizePagination, updateListCache, useApiQuery, useDetailQuery, useInfiniteListQuery, useListQuery, useSuspenseDetailQuery, useSuspenseListQuery };
|
package/dist/sse.d.ts
CHANGED
package/dist/sse.js
CHANGED
|
@@ -113,13 +113,14 @@ function subscribeToEvents(options) {
|
|
|
113
113
|
} catch {
|
|
114
114
|
payload = event.data;
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
const parsed = typeof payload === "object" && payload !== null && "type" in payload && "data" in payload ? payload : {
|
|
117
117
|
type: eventType,
|
|
118
118
|
resource: resource ?? eventType.split(".")[0] ?? "",
|
|
119
119
|
data: payload,
|
|
120
120
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
121
121
|
...event.lastEventId ? { id: event.lastEventId } : {}
|
|
122
|
-
}
|
|
122
|
+
};
|
|
123
|
+
dispatch(parsed);
|
|
123
124
|
});
|
|
124
125
|
es.onerror = () => {
|
|
125
126
|
try {
|
package/dist/upload.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ArcClient, HttpMethod, ToastHandler } from "./client.js";
|
|
2
2
|
import { MutationMessages } from "./mutation.js";
|
|
3
3
|
import { QueryKey } from "@tanstack/react-query";
|
|
4
|
-
|
|
5
4
|
//#region src/upload.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* Upload-progress snapshot. Emitted on every native `xhr.upload.progress`
|
package/dist/upload.js
CHANGED
|
@@ -150,8 +150,9 @@ function uploadAttempt(options) {
|
|
|
150
150
|
const lengthComputable = event.lengthComputable;
|
|
151
151
|
const total = lengthComputable ? event.total : 0;
|
|
152
152
|
const loaded = event.loaded;
|
|
153
|
+
const percent = lengthComputable && total > 0 ? Math.min(100, Math.round(loaded / total * 100)) : 0;
|
|
153
154
|
onProgress({
|
|
154
|
-
percent
|
|
155
|
+
percent,
|
|
155
156
|
loaded,
|
|
156
157
|
total,
|
|
157
158
|
lengthComputable
|
package/dist/ws.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc-next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "React + TanStack Query SDK for Arc resources",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
172
172
|
"@biomejs/biome": "^2.5.5",
|
|
173
173
|
"@classytic/dev-tools": "^0.2.0",
|
|
174
|
-
"@classytic/repo-core": "^0.
|
|
174
|
+
"@classytic/repo-core": "^0.19.0",
|
|
175
175
|
"@tanstack/react-query": "^5.97.0",
|
|
176
176
|
"@testing-library/react": "^16.3.2",
|
|
177
177
|
"@types/react": "^19.2.14",
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
"publint": "^0.3.21",
|
|
183
183
|
"react": "^19.2.5",
|
|
184
184
|
"react-dom": "^19.2.5",
|
|
185
|
-
"tsdown": "^0.
|
|
185
|
+
"tsdown": "^0.22.14",
|
|
186
186
|
"typescript": "^6.0.2",
|
|
187
187
|
"vitest": "^4.1.4"
|
|
188
188
|
}
|