@codecks/fetch 0.1.5 → 0.1.6
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 +317 -10
- package/dist/_exploration/api-requester.d.ts +4 -4
- package/dist/_exploration/api-requester.js +5 -4
- package/dist/_exploration/create-hooks.d.ts +5 -5
- package/dist/_exploration/create-hooks.js +193 -88
- package/dist/_exploration/loader.d.ts +2 -2
- package/dist/_exploration/loader.js +7 -2
- package/dist/_exploration/store.d.ts +4 -4
- package/dist/_exploration/store.js +76 -73
- package/dist/{_root-D1Faf8cg.d.ts → _root-rBEjvjCJ.d.ts} +1 -1
- package/dist/immediate-cache-DiH8tpJM.js +237 -0
- package/dist/{index-DUBsesYl.d.ts → index-obQtSRRg.d.ts} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/{loader-types-Dp0CSVTf.d.ts → loader-types-Y0OHlOEK.d.ts} +4 -8
- package/dist/{loader-utils-Du-CTKH-.d.ts → loader-utils-rQFSDhwf.d.ts} +2 -2
- package/dist/{query-helpers-DsMMOtSO.js → query-helpers-DgC42MEH.js} +13 -9
- package/dist/{query-type-Dx5ZCv5N.d.ts → query-type-B0L3hwCo.d.ts} +2 -2
- package/dist/{store-B6JWZnAO.d.ts → store-LSWKTuHv.d.ts} +97 -6
- package/package.json +4 -3
- package/schema/models/account.md +104 -0
- package/schema/models/accountOnboarding.md +15 -0
- package/schema/models/accountOnboardingStep.md +14 -0
- package/schema/models/accountRole.md +19 -0
- package/schema/models/accountUserAchievement.md +17 -0
- package/schema/models/accountUserSetting.md +20 -0
- package/schema/models/activeTimeTracker.md +19 -0
- package/schema/models/activity.md +30 -0
- package/schema/models/affiliateCode.md +30 -0
- package/schema/models/affiliateCodeStat.md +19 -0
- package/schema/models/app.md +10 -0
- package/schema/models/appInstallation.md +19 -0
- package/schema/models/assigneeAssignment.md +18 -0
- package/schema/models/assigneeDeckAssignment.md +20 -0
- package/schema/models/attachment.md +23 -0
- package/schema/models/autoFinishedTimeTrackingSegment.md +20 -0
- package/schema/models/card.md +82 -0
- package/schema/models/cardDiffNotification.md +22 -0
- package/schema/models/cardHistory.md +20 -0
- package/schema/models/cardOrder.md +17 -0
- package/schema/models/cardOrderInDeck.md +18 -0
- package/schema/models/cardPreset.md +19 -0
- package/schema/models/cardSubscription.md +19 -0
- package/schema/models/cardUpvote.md +21 -0
- package/schema/models/cardsEffortHistory.md +9 -0
- package/schema/models/cardsFinishedHistory.md +16 -0
- package/schema/models/cardsStatusHistory.md +9 -0
- package/schema/models/cardsTimeToFinished.md +18 -0
- package/schema/models/dailyDiscordGuildVoteMembership.md +15 -0
- package/schema/models/dailyPublicProjectMembership.md +15 -0
- package/schema/models/deck.md +53 -0
- package/schema/models/deckAssignment.md +18 -0
- package/schema/models/deckGuardian.md +17 -0
- package/schema/models/deckSubscription.md +18 -0
- package/schema/models/discordGuild.md +30 -0
- package/schema/models/discordMember.md +21 -0
- package/schema/models/discordProjectNotification.md +19 -0
- package/schema/models/discordSlashCommand.md +28 -0
- package/schema/models/dueCard.md +18 -0
- package/schema/models/file.md +26 -0
- package/schema/models/handCard.md +18 -0
- package/schema/models/integration.md +23 -0
- package/schema/models/invoice.md +21 -0
- package/schema/models/lastSeenCardUpvote.md +17 -0
- package/schema/models/milestone.md +39 -0
- package/schema/models/milestoneProgress.md +14 -0
- package/schema/models/milestoneProject.md +17 -0
- package/schema/models/pinnedMilestone.md +22 -0
- package/schema/models/project.md +58 -0
- package/schema/models/projectOrder.md +18 -0
- package/schema/models/projectSelection.md +18 -0
- package/schema/models/projectTag.md +19 -0
- package/schema/models/projectUser.md +18 -0
- package/schema/models/projectUserSetting.md +15 -0
- package/schema/models/publicProjectInfo.md +20 -0
- package/schema/models/publicProjectMembership.md +17 -0
- package/schema/models/publicProjectVisit.md +16 -0
- package/schema/models/queueEntry.md +21 -0
- package/schema/models/queueSelection.md +19 -0
- package/schema/models/release.md +12 -0
- package/schema/models/resolvable.md +32 -0
- package/schema/models/resolvableEntry.md +28 -0
- package/schema/models/resolvableEntryHistory.md +20 -0
- package/schema/models/resolvableEntryReaction.md +23 -0
- package/schema/models/resolvableNotification.md +30 -0
- package/schema/models/resolvableParticipant.md +25 -0
- package/schema/models/resolvableParticipantHistory.md +23 -0
- package/schema/models/savedSearch.md +18 -0
- package/schema/models/sprint.md +42 -0
- package/schema/models/sprintConfig.md +38 -0
- package/schema/models/sprintConfigProgress.md +14 -0
- package/schema/models/sprintProgress.md +14 -0
- package/schema/models/sprintProject.md +17 -0
- package/schema/models/stripeAccountSync.md +29 -0
- package/schema/models/timeTrackingSegment.md +24 -0
- package/schema/models/timeTrackingSum.md +18 -0
- package/schema/models/user.md +67 -0
- package/schema/models/userDismissedHint.md +16 -0
- package/schema/models/userEmail.md +18 -0
- package/schema/models/userInvitation.md +20 -0
- package/schema/models/userInviteCode.md +23 -0
- package/schema/models/userOnboarding.md +14 -0
- package/schema/models/userProjectAccess.md +17 -0
- package/schema/models/userReportEmail.md +19 -0
- package/schema/models/userReportSetting.md +23 -0
- package/schema/models/userReportToken.md +18 -0
- package/schema/models/userTag.md +18 -0
- package/schema/models/visionBoard.md +21 -0
- package/schema/models/visionBoardQuery.md +22 -0
- package/schema/models/wizard.md +19 -0
- package/schema/models/workflowItem.md +45 -0
- package/schema/models/workflowItemHistory.md +18 -0
- package/schema/overview.md +110 -0
- package/schema/query-syntax.md +155 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
//#region src/_exploration/optimistic-manager.ts
|
|
2
|
+
/**
|
|
3
|
+
* Represents a single optimistic update layer
|
|
4
|
+
* Contains field updates for one mutation
|
|
5
|
+
* Internal implementation - wrapped by ImmediateCache to provide full OptimisticUpdater interface
|
|
6
|
+
*/
|
|
7
|
+
var OptimisticLayer = class {
|
|
8
|
+
data = new Map();
|
|
9
|
+
affectedFields = new Set();
|
|
10
|
+
setField(model, id, field, value) {
|
|
11
|
+
const fieldKey = getFieldKey(model, id, field);
|
|
12
|
+
this.data.set(fieldKey, value);
|
|
13
|
+
this.affectedFields.add(fieldKey);
|
|
14
|
+
}
|
|
15
|
+
hasChanges() {
|
|
16
|
+
return this.affectedFields.size > 0;
|
|
17
|
+
}
|
|
18
|
+
getAffectedFieldKeys() {
|
|
19
|
+
return this.affectedFields;
|
|
20
|
+
}
|
|
21
|
+
entries() {
|
|
22
|
+
return this.data.entries();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Manages a stack of optimistic layers with O(1) lookups
|
|
27
|
+
*
|
|
28
|
+
* Design:
|
|
29
|
+
* - Maintains a stack of layers (one per in-flight mutation)
|
|
30
|
+
* - Rebuilds flattened view when layers added/removed for fast reads
|
|
31
|
+
* - Later layers override earlier ones (parallel updates supported)
|
|
32
|
+
* - Auto-cleanup via promise lifecycle
|
|
33
|
+
*/
|
|
34
|
+
var OptimisticManager = class {
|
|
35
|
+
layers = [];
|
|
36
|
+
flatView = new Map();
|
|
37
|
+
/**
|
|
38
|
+
* Add a new optimistic layer
|
|
39
|
+
* @returns Object with the layer and a dispose function that returns affected field keys
|
|
40
|
+
*/
|
|
41
|
+
addLayer() {
|
|
42
|
+
const layer = new OptimisticLayer();
|
|
43
|
+
this.layers.push(layer);
|
|
44
|
+
const dispose = () => this.removeLayer(layer);
|
|
45
|
+
return {
|
|
46
|
+
layer,
|
|
47
|
+
dispose
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get optimistic value for a field (O(1) via flat view)
|
|
52
|
+
* Returns undefined if no optimistic update exists for this field
|
|
53
|
+
*/
|
|
54
|
+
get(model, id, field) {
|
|
55
|
+
const fieldKey = getFieldKey(model, id, field);
|
|
56
|
+
const entry = this.flatView.get(fieldKey);
|
|
57
|
+
if (!entry) return void 0;
|
|
58
|
+
const meta = { state: "optimistic" };
|
|
59
|
+
return {
|
|
60
|
+
value: entry.value,
|
|
61
|
+
partKeys: [fieldKey],
|
|
62
|
+
meta
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Remove a layer from the stack
|
|
67
|
+
* Returns affected field keys for notification
|
|
68
|
+
*/
|
|
69
|
+
removeLayer(layer) {
|
|
70
|
+
const layerIndex = this.layers.indexOf(layer);
|
|
71
|
+
if (layerIndex === -1) return;
|
|
72
|
+
this.layers.splice(layerIndex, 1);
|
|
73
|
+
this.rebuildFlatView();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Rebuild the flattened view from the layer stack
|
|
77
|
+
* Later layers override earlier ones for the same field
|
|
78
|
+
*/
|
|
79
|
+
rebuildFlatView() {
|
|
80
|
+
this.flatView.clear();
|
|
81
|
+
for (let i = 0; i < this.layers.length; i++) {
|
|
82
|
+
const layer = this.layers[i];
|
|
83
|
+
for (const [fieldKey, value] of layer.entries()) this.flatView.set(fieldKey, {
|
|
84
|
+
value,
|
|
85
|
+
layerIndex: i
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/_exploration/immediate-cache.ts
|
|
93
|
+
const getFieldKey = (model, id, field) => `${model}:${id}:${field}`;
|
|
94
|
+
/**
|
|
95
|
+
* Wrapper that provides full OptimisticUpdater interface
|
|
96
|
+
* Delegates writes to OptimisticLayer and reads to ImmediateCache
|
|
97
|
+
*/
|
|
98
|
+
var OptimisticUpdater = class {
|
|
99
|
+
constructor(layer, cache) {
|
|
100
|
+
this.layer = layer;
|
|
101
|
+
this.cache = cache;
|
|
102
|
+
}
|
|
103
|
+
setField(model, id, field, value) {
|
|
104
|
+
this.layer.setField(model, id, field, value);
|
|
105
|
+
}
|
|
106
|
+
getField(model, id, field) {
|
|
107
|
+
return this.cache.get(model, id, field);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var ImmediateCache = class {
|
|
111
|
+
cache = new Map();
|
|
112
|
+
partKeyToFields = new Map();
|
|
113
|
+
fieldSubscriptions = new Map();
|
|
114
|
+
optimisticManager = new OptimisticManager();
|
|
115
|
+
getInstanceKey(model, id) {
|
|
116
|
+
return `${model}:${id}`;
|
|
117
|
+
}
|
|
118
|
+
get(model, key, field) {
|
|
119
|
+
const optimistic = this.optimisticManager.get(model, key, field);
|
|
120
|
+
if (optimistic) return optimistic;
|
|
121
|
+
return this.cache.get(this.getInstanceKey(model, key))?.get(field);
|
|
122
|
+
}
|
|
123
|
+
subscribe(fieldKey, notifyFn) {
|
|
124
|
+
const exists = this.fieldSubscriptions.get(fieldKey);
|
|
125
|
+
if (exists) exists.add(notifyFn);
|
|
126
|
+
else this.fieldSubscriptions.set(fieldKey, new Set([notifyFn]));
|
|
127
|
+
return () => {
|
|
128
|
+
const subs = this.fieldSubscriptions.get(fieldKey);
|
|
129
|
+
if (!subs) return;
|
|
130
|
+
subs.delete(notifyFn);
|
|
131
|
+
if (subs.size === 0) this.fieldSubscriptions.delete(fieldKey);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
set(model, key, partialInstance, meta) {
|
|
135
|
+
const instanceKey = this.getInstanceKey(model, key);
|
|
136
|
+
let entry = this.cache.get(instanceKey);
|
|
137
|
+
if (!entry) {
|
|
138
|
+
entry = new Map();
|
|
139
|
+
this.cache.set(instanceKey, entry);
|
|
140
|
+
}
|
|
141
|
+
const subs = [];
|
|
142
|
+
for (const field in partialInstance) {
|
|
143
|
+
const f = partialInstance[field];
|
|
144
|
+
const oldEntry = entry.get(field);
|
|
145
|
+
const oldValue = oldEntry?.value;
|
|
146
|
+
const newValue = f.value;
|
|
147
|
+
const fieldEntry = {
|
|
148
|
+
value: newValue,
|
|
149
|
+
partKeys: f.partKeys,
|
|
150
|
+
meta
|
|
151
|
+
};
|
|
152
|
+
const fieldKey = getFieldKey(model, key, field);
|
|
153
|
+
entry.set(field, fieldEntry);
|
|
154
|
+
for (const partKey of f.partKeys) {
|
|
155
|
+
const location = {
|
|
156
|
+
model,
|
|
157
|
+
id: key,
|
|
158
|
+
field,
|
|
159
|
+
fieldKey,
|
|
160
|
+
cache: fieldEntry,
|
|
161
|
+
type: f.type
|
|
162
|
+
};
|
|
163
|
+
const maybeFields = this.partKeyToFields.get(partKey);
|
|
164
|
+
if (!maybeFields) this.partKeyToFields.set(partKey, [location]);
|
|
165
|
+
else maybeFields.push(location);
|
|
166
|
+
}
|
|
167
|
+
if (oldValue !== newValue) {
|
|
168
|
+
const fieldSubs = this.fieldSubscriptions.get(fieldKey);
|
|
169
|
+
if (fieldSubs) subs.push(...fieldSubs);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return subs;
|
|
173
|
+
}
|
|
174
|
+
markDirty(partKeys) {
|
|
175
|
+
const subscribedFields = [];
|
|
176
|
+
for (const partKey of partKeys) {
|
|
177
|
+
const locations = this.partKeyToFields.get(partKey);
|
|
178
|
+
console.log(locations);
|
|
179
|
+
if (!locations) continue;
|
|
180
|
+
for (const location of locations) {
|
|
181
|
+
location.cache.meta = { state: "dirty" };
|
|
182
|
+
if (this.fieldSubscriptions.has(location.fieldKey)) if (location.type === "field") subscribedFields.push({
|
|
183
|
+
type: "field",
|
|
184
|
+
model: location.model,
|
|
185
|
+
id: location.id,
|
|
186
|
+
field: location.field
|
|
187
|
+
});
|
|
188
|
+
else subscribedFields.push({
|
|
189
|
+
type: "relation",
|
|
190
|
+
model: location.model,
|
|
191
|
+
id: location.id,
|
|
192
|
+
relKey: location.fieldKey,
|
|
193
|
+
contents: {
|
|
194
|
+
asField: false,
|
|
195
|
+
fields: []
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return subscribedFields;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Create a new optimistic layer bound to a promise and apply updates
|
|
204
|
+
* The layer will be automatically removed when the promise settles
|
|
205
|
+
* @param promise - Promise to bind the layer lifecycle to
|
|
206
|
+
* @param updateFn - Function to apply optimistic updates to the layer
|
|
207
|
+
* @returns The updater object with both read and write capabilities
|
|
208
|
+
*/
|
|
209
|
+
createOptimisticLayer(promise, updateFn) {
|
|
210
|
+
const { layer, dispose } = this.optimisticManager.addLayer();
|
|
211
|
+
const updater = new OptimisticUpdater(layer, this);
|
|
212
|
+
updateFn(updater);
|
|
213
|
+
if (layer.hasChanges()) {
|
|
214
|
+
this.optimisticManager.rebuildFlatView();
|
|
215
|
+
const affectedFields = layer.getAffectedFieldKeys();
|
|
216
|
+
const notify = () => {
|
|
217
|
+
const subs = [];
|
|
218
|
+
for (const fieldKey of affectedFields) {
|
|
219
|
+
const fieldSubs = this.fieldSubscriptions.get(fieldKey);
|
|
220
|
+
if (fieldSubs) subs.push(...fieldSubs);
|
|
221
|
+
}
|
|
222
|
+
new Set(subs).forEach((fn) => fn());
|
|
223
|
+
};
|
|
224
|
+
notify();
|
|
225
|
+
promise.finally(() => {
|
|
226
|
+
dispose();
|
|
227
|
+
notify();
|
|
228
|
+
});
|
|
229
|
+
} else promise.finally(() => {
|
|
230
|
+
dispose();
|
|
231
|
+
});
|
|
232
|
+
return updater;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
//#endregion
|
|
237
|
+
export { ImmediateCache, getFieldKey };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ModelDesc, Nominal, RelationEntry, TypedField } from "./query-type-
|
|
1
|
+
import { ModelDesc, Nominal, RelationEntry, TypedField } from "./query-type-B0L3hwCo.js";
|
|
2
2
|
|
|
3
3
|
//#region src/models/AccountOnboardingStep.d.ts
|
|
4
4
|
type AccountOnboardingStepId = Nominal<string, "accountOnboardingStep">;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { InferModelQuery, InferRelQuery, Instance, ModelQuery, RelQuery } from "./query-type-
|
|
2
|
-
import { modelMap$1 as modelMap } from "./index-
|
|
3
|
-
import { DataLoader, FetchOptions } from "./loader-utils-
|
|
4
|
-
import { _rootDesc$1 as _rootDesc } from "./_root-
|
|
1
|
+
import { InferModelQuery, InferRelQuery, Instance, ModelQuery, RelQuery } from "./query-type-B0L3hwCo.js";
|
|
2
|
+
import { modelMap$1 as modelMap } from "./index-obQtSRRg.js";
|
|
3
|
+
import { DataLoader, FetchOptions } from "./loader-utils-rQFSDhwf.js";
|
|
4
|
+
import { _rootDesc$1 as _rootDesc } from "./_root-rBEjvjCJ.js";
|
|
5
5
|
|
|
6
6
|
//#region src/loaders/simple-loader.d.ts
|
|
7
7
|
type SimpleLoaderOptions = FetchOptions;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { configuredFetch, ensureMapValue } from "./collection-utils-CYJaA1a9.js";
|
|
2
|
-
import { _rootDesc, getRelKey, makeModelQuerySerializable, modelMap, serializeInstanceQuery } from "./query-helpers-
|
|
2
|
+
import { _rootDesc, getRelKey, makeModelQuerySerializable, modelMap, serializeInstanceQuery } from "./query-helpers-DgC42MEH.js";
|
|
3
3
|
|
|
4
4
|
//#region src/model-pool.ts
|
|
5
5
|
const ROOT_ID = "";
|
|
@@ -12,7 +12,7 @@ const dateStrToDay = (dateAsStr) => {
|
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
14
|
const parseField = (v, field) => {
|
|
15
|
-
if (!field) return v;
|
|
15
|
+
if (!field || v == null) return v;
|
|
16
16
|
switch (field.type) {
|
|
17
17
|
case "date": return new Date(v);
|
|
18
18
|
case "day": return dateStrToDay(v);
|
|
@@ -76,7 +76,7 @@ const reconcileInstanceQuery = (query, response, instanceModel, key, store) => {
|
|
|
76
76
|
case "belongsTo":
|
|
77
77
|
result[opts.fk] = instance[relName];
|
|
78
78
|
result[`~${relName}`] = instance[relName] != null ? `${instance[relName]}` : null;
|
|
79
|
-
result[relName] =
|
|
79
|
+
result[relName] = instance[relName] != null ? reconcileInstanceQuery(relEntry, response, relModel, `${instance[relName]}`, store) : null;
|
|
80
80
|
break;
|
|
81
81
|
case "hasOne":
|
|
82
82
|
result[`~${relName}`] = instance[relName] != null ? `${instance[relName]}` : null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SerializableRelationQuery } from "./query-type-
|
|
1
|
+
import { SerializableRelationQuery } from "./query-type-B0L3hwCo.js";
|
|
2
2
|
|
|
3
3
|
//#region src/_exploration/loader-types.d.ts
|
|
4
4
|
type OnLoadedFn = (model: string, key: string, partialInstance: Record<string, unknown>) => void;
|
|
@@ -6,16 +6,12 @@ interface BaseLoader {
|
|
|
6
6
|
setOnLoaded(onLoaded: OnLoadedFn): void;
|
|
7
7
|
loadBatch(requests: MissingDataRequest[]): Promise<unknown>;
|
|
8
8
|
}
|
|
9
|
-
type LoaderPayload = {
|
|
10
|
-
value: unknown;
|
|
11
|
-
partKeys: string[];
|
|
12
|
-
};
|
|
13
9
|
type LoaderResult = {
|
|
14
10
|
state: "resolved";
|
|
15
|
-
payload:
|
|
11
|
+
payload: unknown;
|
|
16
12
|
} | {
|
|
17
13
|
state: "pending";
|
|
18
|
-
promise: Promise<
|
|
14
|
+
promise: Promise<unknown>;
|
|
19
15
|
};
|
|
20
16
|
type MissingDataRequest = {
|
|
21
17
|
type: "field";
|
|
@@ -27,7 +23,7 @@ type MissingDataRequest = {
|
|
|
27
23
|
model: string;
|
|
28
24
|
id: string;
|
|
29
25
|
relKey: string;
|
|
30
|
-
|
|
26
|
+
contents: SerializableRelationQuery;
|
|
31
27
|
};
|
|
32
28
|
interface BaseRequester {
|
|
33
29
|
request: (requests: MissingDataRequest[]) => Promise<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { InferModelQuery, ModelQuery } from "./query-type-
|
|
2
|
-
import { modelMap$1 as modelMap } from "./index-
|
|
1
|
+
import { InferModelQuery, ModelQuery } from "./query-type-B0L3hwCo.js";
|
|
2
|
+
import { modelMap$1 as modelMap } from "./index-obQtSRRg.js";
|
|
3
3
|
|
|
4
4
|
//#region src/loaders/loader-utils.d.ts
|
|
5
5
|
type ModelMap = typeof modelMap;
|
|
@@ -33,33 +33,37 @@ const _rootDesc = makeModel({
|
|
|
33
33
|
const id = () => {
|
|
34
34
|
return { type: "id" };
|
|
35
35
|
};
|
|
36
|
+
const withOpts = (type, opts) => opts.optional ? {
|
|
37
|
+
type,
|
|
38
|
+
optional: true
|
|
39
|
+
} : { type };
|
|
36
40
|
const string = (opts) => {
|
|
37
|
-
return
|
|
41
|
+
return withOpts("string", opts);
|
|
38
42
|
};
|
|
39
43
|
const int = (opts) => {
|
|
40
|
-
return
|
|
44
|
+
return withOpts("int", opts);
|
|
41
45
|
};
|
|
42
46
|
const bigint = (opts) => {
|
|
43
|
-
return
|
|
47
|
+
return withOpts("bigint", opts);
|
|
44
48
|
};
|
|
45
49
|
const bool = (opts) => {
|
|
46
|
-
return
|
|
50
|
+
return withOpts("bool", opts);
|
|
47
51
|
};
|
|
48
52
|
const date = (opts) => {
|
|
49
|
-
return
|
|
53
|
+
return withOpts("date", opts);
|
|
50
54
|
};
|
|
51
55
|
const day = (opts) => {
|
|
52
|
-
return
|
|
56
|
+
return withOpts("day", opts);
|
|
53
57
|
};
|
|
54
58
|
const object = (opts) => {
|
|
55
|
-
return
|
|
59
|
+
return withOpts("obj", opts);
|
|
56
60
|
};
|
|
57
61
|
const array = (opts) => {
|
|
58
|
-
return
|
|
62
|
+
return withOpts("array", opts);
|
|
59
63
|
};
|
|
60
64
|
const belongsTo = (opts) => {
|
|
61
65
|
return { type: () => {
|
|
62
|
-
return
|
|
66
|
+
return withOpts("belongsTo", opts);
|
|
63
67
|
} };
|
|
64
68
|
};
|
|
65
69
|
|
|
@@ -16,7 +16,7 @@ type BaseOpts = {
|
|
|
16
16
|
type FieldEntry = TypedField<string, any, any>;
|
|
17
17
|
type InferSimpleFieldEntry<T extends FieldEntry> = T extends TypedField<any, infer X, infer Opts> ? Opts extends {
|
|
18
18
|
optional: true;
|
|
19
|
-
} ? X | null
|
|
19
|
+
} ? X | null : X : never;
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/models/_desc.d.ts
|
|
22
22
|
type ModelDesc<TName extends string, TFields extends FieldDesc, TRelations extends RelationsDesc, TKey extends (keyof TFields & string)[]> = {
|
|
@@ -165,7 +165,7 @@ type ExtractRelQueryArray<M extends AnyDesc, TMap extends ModelMap, Q extends Re
|
|
|
165
165
|
type InferHasMany<M extends AnyDesc, TMap extends ModelMap, QM extends HasManyQuery<M, TMap>> = QM extends {
|
|
166
166
|
type: "count";
|
|
167
167
|
} ? number : QM extends {
|
|
168
|
-
type: "
|
|
168
|
+
type: "exists";
|
|
169
169
|
} ? boolean : QM extends {
|
|
170
170
|
type: "first";
|
|
171
171
|
} ? InferModelQuery<M, EnsureModelQuery<QM>, TMap> | null : InferModelQuery<M, EnsureModelQuery<QM>, TMap>[];
|
|
@@ -1,9 +1,36 @@
|
|
|
1
|
-
import { ModelDesc, ModelQuery, RelationEntry, TypedField } from "./query-type-
|
|
2
|
-
import { AccountId, AccountOnboardingStepId, ActiveTimeTrackerId, ActivityId, AffiliateCodeId, AppId, AppInstallationId, AttachmentId, CardId, CardPresetId, CardSubscriptionId, CardUpvoteId, DeckId, DeckSubscriptionId, DiscordGuildId, DiscordMemberId, DiscordProjectNotificationId, DiscordSlashCommandId, FileId, IntegrationId, InvoiceId, MilestoneId, PinnedMilestoneId, ProjectId, ProjectSelectionId, ProjectTagId, QueueEntryId, QueueSelectionId, ReleaseId, ResolvableEntryId, ResolvableEntryReactionId, ResolvableId, SavedSearchId, SprintConfigId, SprintId, TimeTrackingSegmentId, UserEmailId, UserId, UserInvitationId, UserInviteCodeId, UserReportEmailId, UserReportSettingId, UserReportTokenId, UserTagId, VisionBoardId, VisionBoardQueryId, WizardId, WorkflowItemId, modelMap$1 as modelMap } from "./index-
|
|
3
|
-
import { BaseLoader, LoaderResult } from "./loader-types-
|
|
1
|
+
import { ModelDesc, ModelQuery, RelationEntry, TypedField } from "./query-type-B0L3hwCo.js";
|
|
2
|
+
import { AccountId, AccountOnboardingStepId, ActiveTimeTrackerId, ActivityId, AffiliateCodeId, AppId, AppInstallationId, AttachmentId, CardId, CardPresetId, CardSubscriptionId, CardUpvoteId, DeckId, DeckSubscriptionId, DiscordGuildId, DiscordMemberId, DiscordProjectNotificationId, DiscordSlashCommandId, FileId, IntegrationId, InvoiceId, MilestoneId, PinnedMilestoneId, ProjectId, ProjectSelectionId, ProjectTagId, QueueEntryId, QueueSelectionId, ReleaseId, ResolvableEntryId, ResolvableEntryReactionId, ResolvableId, SavedSearchId, SprintConfigId, SprintId, TimeTrackingSegmentId, UserEmailId, UserId, UserInvitationId, UserInviteCodeId, UserReportEmailId, UserReportSettingId, UserReportTokenId, UserTagId, VisionBoardId, VisionBoardQueryId, WizardId, WorkflowItemId, modelMap$1 as modelMap } from "./index-obQtSRRg.js";
|
|
3
|
+
import { BaseLoader, LoaderResult, MissingDataRequest } from "./loader-types-Y0OHlOEK.js";
|
|
4
4
|
|
|
5
|
+
//#region src/_exploration/optimistic-manager.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a single optimistic update layer
|
|
9
|
+
* Contains field updates for one mutation
|
|
10
|
+
* Internal implementation - wrapped by ImmediateCache to provide full OptimisticUpdater interface
|
|
11
|
+
*/
|
|
12
|
+
declare class OptimisticLayer {
|
|
13
|
+
private data;
|
|
14
|
+
private affectedFields;
|
|
15
|
+
setField(model: string, id: string, field: string, value: any): void;
|
|
16
|
+
hasChanges(): boolean;
|
|
17
|
+
getAffectedFieldKeys(): Iterable<string>;
|
|
18
|
+
entries(): IterableIterator<[string, any]>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Manages a stack of optimistic layers with O(1) lookups
|
|
22
|
+
*
|
|
23
|
+
* Design:
|
|
24
|
+
* - Maintains a stack of layers (one per in-flight mutation)
|
|
25
|
+
* - Rebuilds flattened view when layers added/removed for fast reads
|
|
26
|
+
* - Later layers override earlier ones (parallel updates supported)
|
|
27
|
+
* - Auto-cleanup via promise lifecycle
|
|
28
|
+
*/
|
|
29
|
+
//#endregion
|
|
5
30
|
//#region src/_exploration/immediate-cache.d.ts
|
|
6
31
|
type FieldMeta = {
|
|
32
|
+
state: "optimistic";
|
|
33
|
+
} | {
|
|
7
34
|
state: "fresh";
|
|
8
35
|
} | {
|
|
9
36
|
state: "dirty";
|
|
@@ -13,21 +40,58 @@ interface FieldCache<T = any> {
|
|
|
13
40
|
partKeys: string[];
|
|
14
41
|
meta: FieldMeta;
|
|
15
42
|
}
|
|
43
|
+
type FieldLocation = {
|
|
44
|
+
model: string;
|
|
45
|
+
id: string;
|
|
46
|
+
field: string;
|
|
47
|
+
fieldKey: string;
|
|
48
|
+
type: "field" | "relation";
|
|
49
|
+
cache: FieldCache;
|
|
50
|
+
};
|
|
16
51
|
type ModelInstance = Map<string, FieldCache>;
|
|
17
52
|
type ModelCache = Map<string, ModelInstance>;
|
|
53
|
+
type FieldSub = () => void;
|
|
54
|
+
/**
|
|
55
|
+
* Wrapper that provides full OptimisticUpdater interface
|
|
56
|
+
* Delegates writes to OptimisticLayer and reads to ImmediateCache
|
|
57
|
+
*/
|
|
58
|
+
declare class OptimisticUpdater {
|
|
59
|
+
private layer;
|
|
60
|
+
private cache;
|
|
61
|
+
constructor(layer: OptimisticLayer,
|
|
62
|
+
// OptimisticLayer from optimistic-manager
|
|
63
|
+
cache: ImmediateCache);
|
|
64
|
+
setField(model: string, id: string, field: string, value: any): void;
|
|
65
|
+
getField(model: string, id: string, field: string): FieldCache | undefined;
|
|
66
|
+
}
|
|
18
67
|
declare class ImmediateCache {
|
|
19
68
|
cache: ModelCache;
|
|
20
|
-
partKeyToFields: Map<string,
|
|
69
|
+
partKeyToFields: Map<string, FieldLocation[]>;
|
|
70
|
+
private fieldSubscriptions;
|
|
71
|
+
private optimisticManager;
|
|
21
72
|
private getInstanceKey;
|
|
22
73
|
get(model: string, key: string, field: string): FieldCache | undefined;
|
|
74
|
+
subscribe(fieldKey: string, notifyFn: FieldSub): () => void;
|
|
23
75
|
set(model: string, key: string, partialInstance: Record<string, {
|
|
24
76
|
value: unknown;
|
|
25
77
|
partKeys: string[];
|
|
26
|
-
|
|
27
|
-
|
|
78
|
+
type: "field" | "relation";
|
|
79
|
+
}>, meta: FieldMeta): FieldSub[];
|
|
80
|
+
markDirty(partKeys: string[]): MissingDataRequest[];
|
|
81
|
+
/**
|
|
82
|
+
* Create a new optimistic layer bound to a promise and apply updates
|
|
83
|
+
* The layer will be automatically removed when the promise settles
|
|
84
|
+
* @param promise - Promise to bind the layer lifecycle to
|
|
85
|
+
* @param updateFn - Function to apply optimistic updates to the layer
|
|
86
|
+
* @returns The updater object with both read and write capabilities
|
|
87
|
+
*/
|
|
88
|
+
createOptimisticLayer(promise: Promise<any>, updateFn: (updater: OptimisticUpdater) => void): OptimisticUpdater;
|
|
28
89
|
}
|
|
29
90
|
//#endregion
|
|
30
91
|
//#region src/_exploration/store.d.ts
|
|
92
|
+
type QueryDep = {
|
|
93
|
+
keys: string[];
|
|
94
|
+
};
|
|
31
95
|
type ModelMap = typeof modelMap;
|
|
32
96
|
declare class Store {
|
|
33
97
|
private loader;
|
|
@@ -2556,7 +2620,10 @@ declare class Store {
|
|
|
2556
2620
|
}>;
|
|
2557
2621
|
}, ["itemId"]>;
|
|
2558
2622
|
};
|
|
2623
|
+
requestedRelationKeys: Map<string, QueryDep>;
|
|
2559
2624
|
constructor(loader: BaseLoader);
|
|
2625
|
+
subscribeToField(fieldKey: string, notifyFn: () => void): () => void;
|
|
2626
|
+
invalidate(partKeyPatterns: string[]): void;
|
|
2560
2627
|
loadData(model: keyof ModelMap, ids: string[], q: ModelQuery<any, any>, acceptDirty?: boolean, iteration?: number): LoaderResult;
|
|
2561
2628
|
onLoaded(model: string, key: string, partialInstance: Record<string, unknown>): void;
|
|
2562
2629
|
/**
|
|
@@ -2564,6 +2631,30 @@ declare class Store {
|
|
|
2564
2631
|
* Accumulates missing requests in the missingRequests array
|
|
2565
2632
|
*/
|
|
2566
2633
|
private checkQueryRecursive;
|
|
2634
|
+
/**
|
|
2635
|
+
* Execute a mutation with optimistic updates
|
|
2636
|
+
*
|
|
2637
|
+
* @example
|
|
2638
|
+
* ```typescript
|
|
2639
|
+
* await store.mutate(
|
|
2640
|
+
* () => api.updateCard('123', {title: 'New Title'}),
|
|
2641
|
+
* {
|
|
2642
|
+
* onMutate: (layer) => {
|
|
2643
|
+
* layer.setField('Card', '123', 'title', 'New Title');
|
|
2644
|
+
* },
|
|
2645
|
+
* onSuccess: () => {
|
|
2646
|
+
* // Optional: invalidate related queries
|
|
2647
|
+
* store.invalidate(['Card:123:title']);
|
|
2648
|
+
* }
|
|
2649
|
+
* }
|
|
2650
|
+
* );
|
|
2651
|
+
* ```
|
|
2652
|
+
*/
|
|
2653
|
+
mutate<T>(mutationFn: () => Promise<T>, options?: {
|
|
2654
|
+
onMutate?: (updater: OptimisticUpdater) => void;
|
|
2655
|
+
onSuccess?: (data: T) => void;
|
|
2656
|
+
onError?: (error: unknown) => void;
|
|
2657
|
+
}): Promise<T>;
|
|
2567
2658
|
}
|
|
2568
2659
|
//#endregion
|
|
2569
2660
|
export { Store };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codecks/fetch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Quickly create deeply nested queries for the Codecks API with advanced TypeScript support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"author": "Daniel Berndt <daniel@codecks.io>",
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"schema"
|
|
18
19
|
],
|
|
19
20
|
"main": "./dist/index.js",
|
|
20
21
|
"module": "./dist/index.js",
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"access": "public"
|
|
32
33
|
},
|
|
33
34
|
"scripts": {
|
|
34
|
-
"build": "tsdown",
|
|
35
|
+
"build": "tsdown && vite-node scripts/generate-schema-docs.ts",
|
|
35
36
|
"format": "prettier --write .",
|
|
36
37
|
"check-format": "prettier --check .",
|
|
37
38
|
"dev": "tsdown --watch",
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# account
|
|
2
|
+
|
|
3
|
+
Key: `id`
|
|
4
|
+
|
|
5
|
+
## Fields
|
|
6
|
+
|
|
7
|
+
- `id`: string
|
|
8
|
+
- `subdomain`: string
|
|
9
|
+
- `name`: string
|
|
10
|
+
- `billingName`: string, optional
|
|
11
|
+
- `billingLine1`: string, optional
|
|
12
|
+
- `billingLine2`: string, optional
|
|
13
|
+
- `billingZip`: string, optional
|
|
14
|
+
- `billingCity`: string, optional
|
|
15
|
+
- `billingCountryCode`: string, optional
|
|
16
|
+
- `billingEmail`: string, optional
|
|
17
|
+
- `netGiftAmount`: number
|
|
18
|
+
- `persona`: string, optional
|
|
19
|
+
- `createdAt`: Date (ISO string)
|
|
20
|
+
- `disabledAt`: Date (ISO string), optional
|
|
21
|
+
- `totalMediaByteUsage`: bigint
|
|
22
|
+
- `isDisabled`: string
|
|
23
|
+
- `milestonesEnabled`: string
|
|
24
|
+
- `sprintsEnabled`: string
|
|
25
|
+
- `priorityLabels`: object
|
|
26
|
+
- `effortScale`: object
|
|
27
|
+
- `statusChangeDurations`: object
|
|
28
|
+
- `activeFeatureFlags`: object
|
|
29
|
+
- `timeTrackingMode`: string
|
|
30
|
+
- `maxTimeTrackingSegmentMsDuration`: number
|
|
31
|
+
- `timeTrackingSwimLaneInfo`: boolean
|
|
32
|
+
- `workdays`: string
|
|
33
|
+
- `workflowMode`: string
|
|
34
|
+
- `isLearning`: boolean
|
|
35
|
+
- `isNonProfit`: boolean
|
|
36
|
+
- `dependenciesEnabled`: boolean
|
|
37
|
+
- `maxHandSlotCount`: number
|
|
38
|
+
- `seats`: number
|
|
39
|
+
- `activeProjectCount`: number
|
|
40
|
+
- `billingType`: string
|
|
41
|
+
- `allowInheritHeroCover`: boolean
|
|
42
|
+
- `attachmentCoverMode`: string
|
|
43
|
+
- `staffPermission`: string
|
|
44
|
+
- `offeringTrial`: boolean
|
|
45
|
+
- `coupon`: object, optional
|
|
46
|
+
- `hideCompletedCardCountForDecks`: boolean
|
|
47
|
+
- `visionBoardEnabled`: boolean
|
|
48
|
+
- `fallbackEffort`: number
|
|
49
|
+
- `timelineScaleType`: string
|
|
50
|
+
- `startWeekday`: string
|
|
51
|
+
- `disabledById`: string (foreign key ID) → user, optional
|
|
52
|
+
|
|
53
|
+
## Relations
|
|
54
|
+
|
|
55
|
+
### belongsTo
|
|
56
|
+
|
|
57
|
+
- `disabledBy` → [user](user.md) (via `disabledById`)
|
|
58
|
+
|
|
59
|
+
### hasOne
|
|
60
|
+
|
|
61
|
+
- `githubIntegration` → [integration](integration.md)
|
|
62
|
+
- `slackIntegration` → [integration](integration.md)
|
|
63
|
+
- `stripeAccountSync` → [stripeAccountSync](stripeAccountSync.md)
|
|
64
|
+
- `accountOnboarding` → [accountOnboarding](accountOnboarding.md)
|
|
65
|
+
|
|
66
|
+
### hasMany
|
|
67
|
+
|
|
68
|
+
- `cards` → [card](card.md)
|
|
69
|
+
- `invoices` → [invoice](invoice.md)
|
|
70
|
+
- `cardPresets` → [cardPreset](cardPreset.md)
|
|
71
|
+
- `attachments` → [attachment](attachment.md)
|
|
72
|
+
- `discordGuilds` → [discordGuild](discordGuild.md)
|
|
73
|
+
- `timeTrackingSegments` → [timeTrackingSegment](timeTrackingSegment.md)
|
|
74
|
+
- `workflowItems` → [workflowItem](workflowItem.md)
|
|
75
|
+
- `deckAssignments` → [deckAssignment](deckAssignment.md)
|
|
76
|
+
- `assigneeAssignments` → [assigneeAssignment](assigneeAssignment.md)
|
|
77
|
+
- `assigneeDeckAssignments` → [assigneeDeckAssignment](assigneeDeckAssignment.md)
|
|
78
|
+
- `wizards` → [wizard](wizard.md)
|
|
79
|
+
- `milestones` → [milestone](milestone.md)
|
|
80
|
+
- `sprints` → [sprint](sprint.md)
|
|
81
|
+
- `sprintConfigs` → [sprintConfig](sprintConfig.md)
|
|
82
|
+
- `handCards` → [handCard](handCard.md)
|
|
83
|
+
- `resolvables` → [resolvable](resolvable.md)
|
|
84
|
+
- `cardUpvotes` → [cardUpvote](cardUpvote.md)
|
|
85
|
+
- `resolvableParticipants` → [resolvableParticipant](resolvableParticipant.md)
|
|
86
|
+
- `userReportSettings` → [userReportSetting](userReportSetting.md)
|
|
87
|
+
- `cardOrders` → [cardOrder](cardOrder.md)
|
|
88
|
+
- `accountUserAchievements` → [accountUserAchievement](accountUserAchievement.md)
|
|
89
|
+
- `userInviteCodes` → [userInviteCode](userInviteCode.md)
|
|
90
|
+
- `visionBoards` → [visionBoard](visionBoard.md)
|
|
91
|
+
- `deckSubscriptions` → [deckSubscription](deckSubscription.md)
|
|
92
|
+
- `appInstallations` → [appInstallation](appInstallation.md)
|
|
93
|
+
- `files` → [file](file.md)
|
|
94
|
+
- `decks` → [deck](deck.md)
|
|
95
|
+
- `queueEntries` → [queueEntry](queueEntry.md)
|
|
96
|
+
- `visionBoardQueries` → [visionBoardQuery](visionBoardQuery.md)
|
|
97
|
+
- `anyDecks` → [deck](deck.md)
|
|
98
|
+
- `projects` → [project](project.md)
|
|
99
|
+
- `archivedProjects` → [project](project.md)
|
|
100
|
+
- `anyProjects` → [project](project.md)
|
|
101
|
+
- `roles` → [accountRole](accountRole.md)
|
|
102
|
+
- `invitations` → [userInvitation](userInvitation.md)
|
|
103
|
+
- `affiliateCodes` → [affiliateCode](affiliateCode.md)
|
|
104
|
+
- `activities` → [activity](activity.md)
|