@codecks/fetch 0.1.7 → 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.
- package/README.md +43 -18
- package/dist/_exploration/api-requester.d.ts +1 -1
- package/dist/_exploration/api-requester.js +19 -7
- package/dist/_exploration/store.js +3 -0
- package/dist/collection-utils-T3bx0BS1.js +78 -0
- package/dist/index.d.ts +6 -7
- package/dist/index.js +27 -13
- package/dist/loader-utils-hvdC-xsQ.d.ts +42 -0
- package/package.json +1 -1
- package/schema/query-syntax.md +2 -2
- package/dist/collection-utils-CYJaA1a9.js +0 -32
- package/dist/loader-utils-BqZKAn_v.d.ts +0 -19
package/README.md
CHANGED
|
@@ -11,26 +11,51 @@ npm install @codecks/fetch
|
|
|
11
11
|
## Getting started
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
const {fetchFromRoot, fetchInstance, fetchInstances, fetchFromInstance} =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
subdomain: "my-org",
|
|
20
|
-
accessToken: "your-token",
|
|
21
|
-
});
|
|
14
|
+
import {buildFetchers} from "@codecks/fetch";
|
|
15
|
+
|
|
16
|
+
const {fetchFromRoot, fetchInstance, fetchInstances, fetchFromInstance} = buildFetchers({
|
|
17
|
+
token: "cdxat_…",
|
|
18
|
+
});
|
|
22
19
|
```
|
|
23
20
|
|
|
21
|
+
`token` is an organization token (`cdxat_…`) or a personal token (`cdxut_…`). Create one under
|
|
22
|
+
**Organization Settings → Integrations → API Tokens** or **Your Profile → API Tokens**. It is sent
|
|
23
|
+
as `Authorization: Bearer <token>` and already names its organization, so no subdomain is needed.
|
|
24
|
+
|
|
24
25
|
### Configuration options
|
|
25
26
|
|
|
26
|
-
| Option
|
|
27
|
-
|
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
33
|
-
|
|
27
|
+
| Option | Type | Description |
|
|
28
|
+
| --------- | ------------------------ | ---------------------------------------------------- |
|
|
29
|
+
| `token` | `string` | API token, `cdxat_…` or `cdxut_…` (required) |
|
|
30
|
+
| `baseUrl` | `string` | API base URL, defaults to `https://api.codecks.io/` |
|
|
31
|
+
| `headers` | `Record<string, string>` | Additional request headers |
|
|
32
|
+
| `timeout` | `number` | Request timeout in ms; the request aborts after that |
|
|
33
|
+
| `fetch` | `typeof fetch` | Custom fetch implementation |
|
|
34
|
+
|
|
35
|
+
### Errors
|
|
36
|
+
|
|
37
|
+
A non-2xx answer throws a `CodecksApiError`:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import {CodecksApiError} from "@codecks/fetch";
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
await fetchFromRoot({account: {fields: ["name"]}});
|
|
44
|
+
} catch (e) {
|
|
45
|
+
if (e instanceof CodecksApiError) {
|
|
46
|
+
e.status; // 400, 401, 403, 429, …
|
|
47
|
+
e.code; // "invalid_token", "token_expired", "missing_scope", "unknown_field", …
|
|
48
|
+
e.path; // "_root.account.cards.titel" for a query error
|
|
49
|
+
e.body; // the full response body, e.g. `hint` or `requiredScope`
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Legacy tokens
|
|
55
|
+
|
|
56
|
+
`buildLegacyFetchers({accessToken, subdomain, baseUrl, …})` sends the old `X-Auth-Token` and
|
|
57
|
+
`X-Account` headers. The API stops accepting `X-Auth-Token` on **2026-12-31**; move to an API token
|
|
58
|
+
before then.
|
|
34
59
|
|
|
35
60
|
## Fetching data
|
|
36
61
|
|
|
@@ -324,9 +349,9 @@ Point your LLM's project instructions (e.g. `CLAUDE.md`) at `schema/overview.md`
|
|
|
324
349
|
For advanced use cases (batching, caching, custom transports), you can provide your own `DataLoader`:
|
|
325
350
|
|
|
326
351
|
```ts
|
|
327
|
-
import {
|
|
352
|
+
import {buildFetchersFromLoader} from "@codecks/fetch";
|
|
328
353
|
|
|
329
|
-
const {fetchFromRoot} =
|
|
354
|
+
const {fetchFromRoot} = buildFetchersFromLoader({
|
|
330
355
|
fetchModel: async (model, ids, query) => {
|
|
331
356
|
// your custom loading logic
|
|
332
357
|
return recordOfResults;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../query-type-BqQ9oX_U.js";
|
|
2
2
|
import "../index-k-KPWV9R.js";
|
|
3
|
-
import { FetchOptions } from "../loader-utils-
|
|
3
|
+
import { FetchOptions } from "../loader-utils-hvdC-xsQ.js";
|
|
4
4
|
import { BaseRequester, MissingDataRequest } from "../loader-types-fd5tV0FD.js";
|
|
5
5
|
|
|
6
6
|
//#region src/_exploration/api-requester.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { configuredFetch, ensureMapValue } from "../collection-utils-
|
|
1
|
+
import { bearerTransport, configuredFetch, ensureMapValue } from "../collection-utils-T3bx0BS1.js";
|
|
2
2
|
import { serializeModel } from "../query-helpers-iX1fiqLv.js";
|
|
3
3
|
|
|
4
4
|
//#region src/_exploration/utils/concurrency-limiter.ts
|
|
@@ -66,7 +66,7 @@ var ApiRequester = class {
|
|
|
66
66
|
fetchOptions;
|
|
67
67
|
limiter;
|
|
68
68
|
constructor(fetchOptions, maxConcurrent = 3) {
|
|
69
|
-
this.fetchOptions = fetchOptions;
|
|
69
|
+
this.fetchOptions = bearerTransport(fetchOptions);
|
|
70
70
|
this.limiter = new ConcurrencyLimiter(maxConcurrent);
|
|
71
71
|
}
|
|
72
72
|
async request(requests) {
|
|
@@ -108,11 +108,23 @@ var ApiRequester = class {
|
|
|
108
108
|
key: "",
|
|
109
109
|
partialInstance: instances
|
|
110
110
|
});
|
|
111
|
-
else for (const [id, data] of Object.entries(instances))
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
else for (const [id, data] of Object.entries(instances)) {
|
|
112
|
+
if (data == null) {
|
|
113
|
+
const requested = dataByModel.get(modelName)?.get(id);
|
|
114
|
+
if (!requested) continue;
|
|
115
|
+
results.push({
|
|
116
|
+
model: modelName,
|
|
117
|
+
key: id,
|
|
118
|
+
partialInstance: Object.fromEntries([...requested.fields, ...requested.relations.keys()].map((key) => [key, null]))
|
|
119
|
+
});
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
results.push({
|
|
123
|
+
model: modelName,
|
|
124
|
+
key: id,
|
|
125
|
+
partialInstance: data
|
|
126
|
+
});
|
|
127
|
+
}
|
|
116
128
|
return results;
|
|
117
129
|
}
|
|
118
130
|
};
|
|
@@ -118,6 +118,9 @@ var Store = class {
|
|
|
118
118
|
data[`~${fieldName}`] = cachedValue.value.map((v) => `${v}`);
|
|
119
119
|
data[fieldName] = relationResults.map((result) => result.data);
|
|
120
120
|
if (relationResults.some((result) => !result.allPresent)) allPresent = false;
|
|
121
|
+
} else if (cachedValue.value == null) {
|
|
122
|
+
data[`~${fieldName}`] = null;
|
|
123
|
+
data[fieldName] = null;
|
|
121
124
|
} else {
|
|
122
125
|
const relationResult = this.checkQueryRecursive(relatedModelDesc, relatedModel, `${cachedValue.value}`, relQuery, missingRequests, acceptDirty);
|
|
123
126
|
data[`~${fieldName}`] = cachedValue.value != null ? `${cachedValue.value}` : null;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/loaders/loader-utils.ts
|
|
2
|
+
const DEFAULT_BASE_URL = "https://api.codecks.io/";
|
|
3
|
+
const bearerTransport = (opts) => {
|
|
4
|
+
const { token,...rest } = opts;
|
|
5
|
+
if (!/^cdx[au]t_/.test(token)) throw new Error("Expected an API token starting with `cdxat_` or `cdxut_`. Legacy tokens need `buildLegacyFetchers`.");
|
|
6
|
+
return {
|
|
7
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
8
|
+
...rest,
|
|
9
|
+
authHeaders: { Authorization: `Bearer ${token}` }
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
const legacyTransport = (opts) => {
|
|
13
|
+
const { accessToken, subdomain,...rest } = opts;
|
|
14
|
+
const authHeaders = {};
|
|
15
|
+
if (accessToken) authHeaders["X-Auth-Token"] = accessToken;
|
|
16
|
+
if (subdomain) authHeaders["X-Account"] = subdomain;
|
|
17
|
+
return {
|
|
18
|
+
...rest,
|
|
19
|
+
authHeaders
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
/** A non-2xx answer. `code`, `path` and the rest of the body follow the API's error format. */
|
|
23
|
+
var CodecksApiError = class extends Error {
|
|
24
|
+
status;
|
|
25
|
+
/** e.g. `invalid_token`, `token_expired`, `missing_scope`, `unknown_field`, `rate_limit` */
|
|
26
|
+
code;
|
|
27
|
+
/** where in the query the error sits, e.g. `_root.account.cards.titel` */
|
|
28
|
+
path;
|
|
29
|
+
/** the parsed JSON body, or the raw text if it wasn't JSON — holds `hint`, `requiredScope`, … */
|
|
30
|
+
body;
|
|
31
|
+
constructor(status, body) {
|
|
32
|
+
const obj = typeof body === "object" && body !== null ? body : {};
|
|
33
|
+
const str = (v) => typeof v === "string" ? v : null;
|
|
34
|
+
const code = str(obj.error);
|
|
35
|
+
super(`[${status}] ${str(obj.message) ?? code ?? (str(body) || "request failed")}`);
|
|
36
|
+
this.name = "CodecksApiError";
|
|
37
|
+
this.status = status;
|
|
38
|
+
this.code = code;
|
|
39
|
+
this.path = str(obj.path);
|
|
40
|
+
this.body = body;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const readErrorBody = async (r) => {
|
|
44
|
+
const text = await r.text();
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(text);
|
|
47
|
+
} catch {
|
|
48
|
+
return text;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const configuredFetch = async (opts, url, init = {}) => {
|
|
52
|
+
const fetchImpl = opts.fetch || globalThis.fetch;
|
|
53
|
+
const headers = new Headers(init.headers);
|
|
54
|
+
for (const [key, value] of Object.entries(opts.authHeaders)) headers.set(key, value);
|
|
55
|
+
if (opts.headers) for (const [key, value] of Object.entries(opts.headers)) headers.set(key, value);
|
|
56
|
+
const fullUrl = opts.baseUrl ? `${opts.baseUrl}${url}` : url;
|
|
57
|
+
const signal = opts.timeout ? AbortSignal.timeout(opts.timeout) : init.signal;
|
|
58
|
+
const r = await fetchImpl(fullUrl, {
|
|
59
|
+
...init,
|
|
60
|
+
headers,
|
|
61
|
+
signal
|
|
62
|
+
});
|
|
63
|
+
if (r.status < 200 || r.status >= 300) throw new CodecksApiError(r.status, await readErrorBody(r));
|
|
64
|
+
return await r.json();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/collection-utils.ts
|
|
69
|
+
const ensureMapValue = (map, key, fallback) => {
|
|
70
|
+
const exist = map.get(key);
|
|
71
|
+
if (exist) return exist;
|
|
72
|
+
const newValue = fallback();
|
|
73
|
+
map.set(key, newValue);
|
|
74
|
+
return newValue;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
export { CodecksApiError, bearerTransport, configuredFetch, ensureMapValue, legacyTransport };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { InferModelQuery, InferRelQuery, Instance, ModelQuery, RelQuery } from "./query-type-BqQ9oX_U.js";
|
|
2
2
|
import { modelMap$1 as modelMap } from "./index-k-KPWV9R.js";
|
|
3
|
-
import { DataLoader, FetchOptions } from "./loader-utils-
|
|
3
|
+
import { CodecksApiError$1 as CodecksApiError, DataLoader, FetchOptions, LegacyFetchOptions } from "./loader-utils-hvdC-xsQ.js";
|
|
4
4
|
import { _rootDesc$1 as _rootDesc } from "./_root-BW9uzB79.js";
|
|
5
5
|
|
|
6
|
-
//#region src/loaders/simple-loader.d.ts
|
|
7
|
-
type SimpleLoaderOptions = FetchOptions;
|
|
8
|
-
//#endregion
|
|
9
6
|
//#region src/index.d.ts
|
|
10
7
|
type ModelMap = typeof modelMap;
|
|
11
8
|
type Fetchers = {
|
|
@@ -14,7 +11,9 @@ type Fetchers = {
|
|
|
14
11
|
fetchInstance: <K extends keyof ModelMap, const Q extends ModelQuery<ModelMap[K], ModelMap>>(model: K, id: string, q: Q) => Promise<InferModelQuery<ModelMap[K], Q, ModelMap>>;
|
|
15
12
|
fetchInstances: <K extends keyof ModelMap, Id extends string, const Q extends ModelQuery<ModelMap[K], ModelMap>>(model: K, id: Id[], q: Q) => Promise<Record<Id, InferModelQuery<ModelMap[K], Q, ModelMap>>>;
|
|
16
13
|
};
|
|
17
|
-
declare const
|
|
18
|
-
|
|
14
|
+
declare const buildFetchers: (opts: FetchOptions) => Fetchers;
|
|
15
|
+
/** @deprecated `X-Auth-Token` stops working on 2026-12-31. Use `buildFetchers` with an API token. */
|
|
16
|
+
declare const buildLegacyFetchers: (opts: LegacyFetchOptions) => Fetchers;
|
|
17
|
+
declare const buildFetchersFromLoader: (loader: DataLoader) => Fetchers;
|
|
19
18
|
//#endregion
|
|
20
|
-
export { buildFetchers,
|
|
19
|
+
export { CodecksApiError, type DataLoader, type FetchOptions, type LegacyFetchOptions, buildFetchers, buildFetchersFromLoader, buildLegacyFetchers };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { configuredFetch, ensureMapValue } from "./collection-utils-
|
|
1
|
+
import { CodecksApiError, bearerTransport, configuredFetch, ensureMapValue, legacyTransport } from "./collection-utils-T3bx0BS1.js";
|
|
2
2
|
import { _rootDesc, getRelKey, makeModelQuerySerializable, modelMap, serializeInstanceQuery } from "./query-helpers-iX1fiqLv.js";
|
|
3
3
|
|
|
4
4
|
//#region src/model-pool.ts
|
|
@@ -41,6 +41,7 @@ var ModelPool = class {
|
|
|
41
41
|
Object.entries(data).forEach(([modelName, payload]) => {
|
|
42
42
|
if (modelName === _rootDesc.name) this.addModelInstance(modelName, ROOT_ID, payload);
|
|
43
43
|
else Object.entries(payload).forEach(([id, payload$1]) => {
|
|
44
|
+
if (payload$1 == null) return;
|
|
44
45
|
this.addModelInstance(modelName, id, payload$1);
|
|
45
46
|
});
|
|
46
47
|
});
|
|
@@ -53,10 +54,16 @@ var ModelPool = class {
|
|
|
53
54
|
|
|
54
55
|
//#endregion
|
|
55
56
|
//#region src/reconcile-query.ts
|
|
57
|
+
/**
|
|
58
|
+
* The API names an id but answers `null` for it when the token may not read that
|
|
59
|
+
* record. Such an id never enters the pool, and the caller can do nothing about it —
|
|
60
|
+
* unlike an id the response never mentioned at all, which points at a bug worth a warning.
|
|
61
|
+
*/
|
|
62
|
+
const isWithheldByApi = (response, model, key) => response[model]?.[key] === null;
|
|
56
63
|
const reconcileInstanceQuery = (query, response, instanceModel, key, store) => {
|
|
57
64
|
const instance = store.get(instanceModel.name, key);
|
|
58
65
|
if (!instance) {
|
|
59
|
-
console.warn(`no instance found in pool: [${instanceModel.name}, ${key}]`);
|
|
66
|
+
if (!isWithheldByApi(response, instanceModel.name, key)) console.warn(`no instance found in pool: [${instanceModel.name}, ${key}]`);
|
|
60
67
|
return null;
|
|
61
68
|
}
|
|
62
69
|
const result = instanceModel.name === "_root" ? {} : {
|
|
@@ -80,7 +87,7 @@ const reconcileInstanceQuery = (query, response, instanceModel, key, store) => {
|
|
|
80
87
|
break;
|
|
81
88
|
case "hasOne":
|
|
82
89
|
result[`~${relName}`] = instance[relName] != null ? `${instance[relName]}` : null;
|
|
83
|
-
result[relName] = reconcileInstanceQuery(relEntry, response, relModel, `${instance[relName]}`, store);
|
|
90
|
+
result[relName] = instance[relName] != null ? reconcileInstanceQuery(relEntry, response, relModel, `${instance[relName]}`, store) : null;
|
|
84
91
|
break;
|
|
85
92
|
case "hasMany":
|
|
86
93
|
const asName = relEntry.as ?? relName;
|
|
@@ -94,12 +101,20 @@ const reconcileInstanceQuery = (query, response, instanceModel, key, store) => {
|
|
|
94
101
|
}
|
|
95
102
|
case "first":
|
|
96
103
|
result[`~${asName}`] = val != null ? `${val}` : null;
|
|
97
|
-
result[asName] = reconcileInstanceQuery(relEntry, response, relModel, `${val}`, store);
|
|
104
|
+
result[asName] = val != null ? reconcileInstanceQuery(relEntry, response, relModel, `${val}`, store) : null;
|
|
98
105
|
break;
|
|
99
106
|
default: {
|
|
100
107
|
const ids = val ?? [];
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
const members = [];
|
|
109
|
+
for (const id of ids) {
|
|
110
|
+
const instance$1 = reconcileInstanceQuery(relEntry, response, relModel, `${id}`, store);
|
|
111
|
+
if (instance$1 != null) members.push({
|
|
112
|
+
key: `${id}`,
|
|
113
|
+
instance: instance$1
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
result[`~${asName}`] = members.map((m) => m.key);
|
|
117
|
+
result[asName] = members.map((m) => m.instance);
|
|
103
118
|
}
|
|
104
119
|
}
|
|
105
120
|
break;
|
|
@@ -111,7 +126,7 @@ const reconcileInstanceQuery = (query, response, instanceModel, key, store) => {
|
|
|
111
126
|
|
|
112
127
|
//#endregion
|
|
113
128
|
//#region src/loaders/simple-loader.ts
|
|
114
|
-
const createSimpleLoader = (opts
|
|
129
|
+
const createSimpleLoader = (opts) => {
|
|
115
130
|
const fetchWithQuery = async (query) => {
|
|
116
131
|
return configuredFetch(opts, "", {
|
|
117
132
|
method: "POST",
|
|
@@ -134,11 +149,10 @@ const createSimpleLoader = (opts = {}) => {
|
|
|
134
149
|
|
|
135
150
|
//#endregion
|
|
136
151
|
//#region src/index.ts
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const buildFetchers = (loader) => {
|
|
152
|
+
const buildFetchers = (opts) => buildFetchersFromLoader(createSimpleLoader(bearerTransport(opts)));
|
|
153
|
+
/** @deprecated `X-Auth-Token` stops working on 2026-12-31. Use `buildFetchers` with an API token. */
|
|
154
|
+
const buildLegacyFetchers = (opts) => buildFetchersFromLoader(createSimpleLoader(legacyTransport(opts)));
|
|
155
|
+
const buildFetchersFromLoader = (loader) => {
|
|
142
156
|
return {
|
|
143
157
|
fetchFromRoot: async (q) => {
|
|
144
158
|
const res = await loader.fetchModel("_root", [""], { relations: q });
|
|
@@ -158,4 +172,4 @@ const buildFetchers = (loader) => {
|
|
|
158
172
|
};
|
|
159
173
|
|
|
160
174
|
//#endregion
|
|
161
|
-
export { buildFetchers,
|
|
175
|
+
export { CodecksApiError, buildFetchers, buildFetchersFromLoader, buildLegacyFetchers };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { InferModelQuery, ModelQuery } from "./query-type-BqQ9oX_U.js";
|
|
2
|
+
import { modelMap$1 as modelMap } from "./index-k-KPWV9R.js";
|
|
3
|
+
|
|
4
|
+
//#region src/loaders/loader-utils.d.ts
|
|
5
|
+
type ModelMap = typeof modelMap;
|
|
6
|
+
type DataLoader = {
|
|
7
|
+
fetchModel: <K extends keyof ModelMap, Id extends string, const Q extends ModelQuery<ModelMap[K], ModelMap>>(model: K, id: Id[], q: Q) => Promise<Record<Id, InferModelQuery<ModelMap[K], Q, ModelMap>>>;
|
|
8
|
+
};
|
|
9
|
+
type FetchFunction = (url: string, init?: RequestInit) => Promise<Response>;
|
|
10
|
+
type BaseFetchOptions = {
|
|
11
|
+
fetch?: FetchFunction;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
/** in milliseconds */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
};
|
|
17
|
+
type FetchOptions = BaseFetchOptions & {
|
|
18
|
+
/** an organization (`cdxat_…`) or personal (`cdxut_…`) API token */
|
|
19
|
+
token: string;
|
|
20
|
+
};
|
|
21
|
+
/** @deprecated `X-Auth-Token` stops working on 2026-12-31. Use `FetchOptions` with an API token. */
|
|
22
|
+
type LegacyFetchOptions = BaseFetchOptions & {
|
|
23
|
+
/** sent as `X-Auth-Token` */
|
|
24
|
+
accessToken?: string;
|
|
25
|
+
/** sent as `X-Account` */
|
|
26
|
+
subdomain?: string;
|
|
27
|
+
};
|
|
28
|
+
/** Fetch options with the auth headers already folded into `headers`. */
|
|
29
|
+
|
|
30
|
+
/** A non-2xx answer. `code`, `path` and the rest of the body follow the API's error format. */
|
|
31
|
+
declare class CodecksApiError extends Error {
|
|
32
|
+
readonly status: number;
|
|
33
|
+
/** e.g. `invalid_token`, `token_expired`, `missing_scope`, `unknown_field`, `rate_limit` */
|
|
34
|
+
readonly code: string | null;
|
|
35
|
+
/** where in the query the error sits, e.g. `_root.account.cards.titel` */
|
|
36
|
+
readonly path: string | null;
|
|
37
|
+
/** the parsed JSON body, or the raw text if it wasn't JSON — holds `hint`, `requiredScope`, … */
|
|
38
|
+
readonly body: unknown;
|
|
39
|
+
constructor(status: number, body: unknown);
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { CodecksApiError as CodecksApiError$1, DataLoader, FetchOptions, LegacyFetchOptions };
|
package/package.json
CHANGED
package/schema/query-syntax.md
CHANGED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
//#region src/loaders/loader-utils.ts
|
|
2
|
-
const configuredFetch = async (opts, url, init = {}) => {
|
|
3
|
-
const fetchImpl = opts.fetch || globalThis.fetch;
|
|
4
|
-
const headers = new Headers(init.headers);
|
|
5
|
-
if (opts.accessToken) headers.set("X-Auth-Token", opts.accessToken);
|
|
6
|
-
if (opts.subdomain) headers.set("X-Account", opts.subdomain);
|
|
7
|
-
if (opts.headers) Object.entries(opts.headers).forEach(([key, value]) => {
|
|
8
|
-
headers.set(key, value);
|
|
9
|
-
});
|
|
10
|
-
const fullUrl = opts.baseUrl ? `${opts.baseUrl}${url}` : url;
|
|
11
|
-
return fetchImpl(fullUrl, {
|
|
12
|
-
...init,
|
|
13
|
-
headers
|
|
14
|
-
}).then(async (r) => {
|
|
15
|
-
const content = await r.json();
|
|
16
|
-
if (r.status !== 200) throw new Error(`[${r.status}] ${JSON.stringify(content)}`);
|
|
17
|
-
return content;
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region src/collection-utils.ts
|
|
23
|
-
const ensureMapValue = (map, key, fallback) => {
|
|
24
|
-
const exist = map.get(key);
|
|
25
|
-
if (exist) return exist;
|
|
26
|
-
const newValue = fallback();
|
|
27
|
-
map.set(key, newValue);
|
|
28
|
-
return newValue;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
|
-
export { configuredFetch, ensureMapValue };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { InferModelQuery, ModelQuery } from "./query-type-BqQ9oX_U.js";
|
|
2
|
-
import { modelMap$1 as modelMap } from "./index-k-KPWV9R.js";
|
|
3
|
-
|
|
4
|
-
//#region src/loaders/loader-utils.d.ts
|
|
5
|
-
type ModelMap = typeof modelMap;
|
|
6
|
-
type DataLoader = {
|
|
7
|
-
fetchModel: <K extends keyof ModelMap, Id extends string, const Q extends ModelQuery<ModelMap[K], ModelMap>>(model: K, id: Id[], q: Q) => Promise<Record<Id, InferModelQuery<ModelMap[K], Q, ModelMap>>>;
|
|
8
|
-
};
|
|
9
|
-
type FetchFunction = (url: string, init?: RequestInit) => Promise<Response>;
|
|
10
|
-
type FetchOptions = {
|
|
11
|
-
fetch?: FetchFunction;
|
|
12
|
-
accessToken?: string;
|
|
13
|
-
subdomain?: string;
|
|
14
|
-
baseUrl?: string;
|
|
15
|
-
headers?: Record<string, string>;
|
|
16
|
-
timeout?: number;
|
|
17
|
-
};
|
|
18
|
-
//#endregion
|
|
19
|
-
export { DataLoader, FetchOptions };
|