@dee-wan/cache 1.0.1 → 1.1.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 +177 -2
- package/dist/chunk-A4WV6RY4.js +311 -0
- package/dist/chunk-A4WV6RY4.js.map +1 -0
- package/dist/chunk-AENVFT2S.js +6 -0
- package/dist/chunk-AENVFT2S.js.map +1 -0
- package/dist/chunk-D2EESWMC.js +19 -0
- package/dist/chunk-D2EESWMC.js.map +1 -0
- package/dist/chunk-E6OZZ5UX.js +133 -0
- package/dist/chunk-E6OZZ5UX.js.map +1 -0
- package/dist/chunk-HGAUU4EU.js +388 -0
- package/dist/chunk-HGAUU4EU.js.map +1 -0
- package/dist/chunk-JPK2AF7X.js +18 -0
- package/dist/chunk-JPK2AF7X.js.map +1 -0
- package/dist/chunk-LHOK33GI.js +12 -0
- package/dist/chunk-LHOK33GI.js.map +1 -0
- package/dist/chunk-MOJBHU3S.js +431 -0
- package/dist/chunk-MOJBHU3S.js.map +1 -0
- package/dist/chunk-OOPPXK7Q.js +133 -0
- package/dist/chunk-OOPPXK7Q.js.map +1 -0
- package/dist/chunk-ZCMZJKGN.js +78 -0
- package/dist/chunk-ZCMZJKGN.js.map +1 -0
- package/dist/chunk-ZREX7LLC.js +545 -0
- package/dist/chunk-ZREX7LLC.js.map +1 -0
- package/dist/client.d.ts +50 -0
- package/dist/client.js +224 -0
- package/dist/client.js.map +1 -0
- package/dist/cloudflare/index.d.ts +15 -2
- package/dist/cloudflare/index.js +413 -45
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/d1/config.d.ts +41 -0
- package/dist/d1/config.js +102 -0
- package/dist/d1/config.js.map +1 -0
- package/dist/d1/index.d.ts +64 -0
- package/dist/d1/index.js +196 -0
- package/dist/d1/index.js.map +1 -0
- package/dist/d1/response-lease.d.ts +9 -0
- package/dist/d1/response-lease.js +42 -0
- package/dist/d1/response-lease.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -616
- package/dist/index.js.map +1 -1
- package/dist/profile--LBtbQI_.d.ts +30 -0
- package/dist/response-lease-DeeM-ofO.d.ts +19 -0
- package/dist/response-lease.d.ts +7 -0
- package/dist/response-lease.js +9 -0
- package/dist/response-lease.js.map +1 -0
- package/dist/response-warmup-BWQvnT1G.d.ts +38 -0
- package/dist/scoped-read.d.ts +12 -0
- package/dist/scoped-read.js +30 -0
- package/dist/scoped-read.js.map +1 -0
- package/dist/{types-DwtU0KpX.d.ts → types-D-Gd11to.d.ts} +13 -1
- package/docs/cache-contract.md +49 -1
- package/package.json +31 -2
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
import { PLANNER_VERSION, CONFIG_FORMAT, MAX_LOCK_MS, MAX_LEASE_MS, MAX_VALUE_BYTES, MAX_GENERATION_LENGTH, GLOBAL_FENCE, writeFence, modelFence, entityFence, TTL_JITTER_RATIO, MAX_SHAPE_TTL_SECONDS } from './chunk-OQRNVGQE.js';
|
|
2
|
+
import { sha256Hex, stableStringify, decode, encode } from './chunk-ZCMZJKGN.js';
|
|
3
|
+
|
|
4
|
+
// src/core/pk.ts
|
|
5
|
+
function isPlainRecord(value) {
|
|
6
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function encodePk(parts) {
|
|
9
|
+
return parts.map((part) => encodeURIComponent(String(part))).join(":");
|
|
10
|
+
}
|
|
11
|
+
function unwrapEquals(value) {
|
|
12
|
+
return isPlainRecord(value) && "equals" in value ? value.equals : value;
|
|
13
|
+
}
|
|
14
|
+
function isScalarPk(value) {
|
|
15
|
+
return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
|
|
16
|
+
}
|
|
17
|
+
function pkFromWhere(where, pkFields, compoundName) {
|
|
18
|
+
if (!isPlainRecord(where)) return null;
|
|
19
|
+
const compound = where[compoundName ?? pkFields.join("_")];
|
|
20
|
+
const source = pkFields.length > 1 && isPlainRecord(compound) ? compound : where;
|
|
21
|
+
const parts = [];
|
|
22
|
+
for (const field of pkFields) {
|
|
23
|
+
const value = source === where ? unwrapEquals(where[field]) : source[field];
|
|
24
|
+
if (!isScalarPk(value)) return null;
|
|
25
|
+
parts.push(value);
|
|
26
|
+
}
|
|
27
|
+
return encodePk(parts);
|
|
28
|
+
}
|
|
29
|
+
function pkFromRow(row, pkFields) {
|
|
30
|
+
if (!isPlainRecord(row)) return null;
|
|
31
|
+
const parts = [];
|
|
32
|
+
for (const field of pkFields) {
|
|
33
|
+
const value = row[field];
|
|
34
|
+
if (!isScalarPk(value)) return null;
|
|
35
|
+
parts.push(value);
|
|
36
|
+
}
|
|
37
|
+
return encodePk(parts);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/core/plan.ts
|
|
41
|
+
var MAX_NESTED_WRITE_DEPTH = 5;
|
|
42
|
+
var MAX_ENTITY_FENCES_PER_MODEL = 100;
|
|
43
|
+
var READ_OPERATIONS = /* @__PURE__ */ new Set(["aggregate", "count", "findFirst", "findFirstOrThrow", "findMany", "findUnique", "findUniqueOrThrow", "groupBy"]);
|
|
44
|
+
var WRITE_OPERATIONS = /* @__PURE__ */ new Set([
|
|
45
|
+
"create",
|
|
46
|
+
"createMany",
|
|
47
|
+
"createManyAndReturn",
|
|
48
|
+
"delete",
|
|
49
|
+
"deleteMany",
|
|
50
|
+
"update",
|
|
51
|
+
"updateMany",
|
|
52
|
+
"updateManyAndReturn",
|
|
53
|
+
"upsert"
|
|
54
|
+
]);
|
|
55
|
+
var pkFieldsOf = (config, model) => config.primaryKeyFieldsByModel[model] ?? ["id"];
|
|
56
|
+
function touch(plan, model) {
|
|
57
|
+
const existing = plan.touched.get(model);
|
|
58
|
+
if (existing) return existing;
|
|
59
|
+
const created = { pks: /* @__PURE__ */ new Set(), wide: false };
|
|
60
|
+
plan.touched.set(model, created);
|
|
61
|
+
return created;
|
|
62
|
+
}
|
|
63
|
+
var touchWrite = (ctx, model) => void touch(ctx.plan, model);
|
|
64
|
+
var touchWide = (ctx, model) => void (touch(ctx.plan, model).wide = true);
|
|
65
|
+
function touchEntity(ctx, model, where) {
|
|
66
|
+
const pk = pkFromWhere(where, pkFieldsOf(ctx.config, model), ctx.config.primaryKeyNameByModel[model]);
|
|
67
|
+
if (pk === null) touchWide(ctx, model);
|
|
68
|
+
else touch(ctx.plan, model).pks.add(pk);
|
|
69
|
+
}
|
|
70
|
+
function referencedFields(config, model) {
|
|
71
|
+
const fields = /* @__PURE__ */ new Set();
|
|
72
|
+
for (const relations of Object.values(config.relationGraph)) {
|
|
73
|
+
for (const relation of relations) {
|
|
74
|
+
if (relation.targetModel === model && relation.localFields.length > 0) {
|
|
75
|
+
for (const field of relation.foreignFields) fields.add(field);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return fields;
|
|
80
|
+
}
|
|
81
|
+
function touchReferencing(ctx, model, seen = /* @__PURE__ */ new Set()) {
|
|
82
|
+
if (seen.has(model)) return;
|
|
83
|
+
seen.add(model);
|
|
84
|
+
for (const [owner, relations] of Object.entries(ctx.config.relationGraph)) {
|
|
85
|
+
const references = relations.some((relation) => relation.targetModel === model && relation.localFields.length > 0);
|
|
86
|
+
if (!references) continue;
|
|
87
|
+
touchWide(ctx, owner);
|
|
88
|
+
touchReferencing(ctx, owner, seen);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function touchReferencingIfKeyChanges(ctx, model, data) {
|
|
92
|
+
if (!isPlainRecord(data)) return;
|
|
93
|
+
const referenced = referencedFields(ctx.config, model);
|
|
94
|
+
if (Object.keys(data).some((field) => referenced.has(field))) touchReferencing(ctx, model);
|
|
95
|
+
}
|
|
96
|
+
var asItems = (value) => Array.isArray(value) ? value : [value];
|
|
97
|
+
var ONE_TO_ONE_REPARENTING_OPS = /* @__PURE__ */ new Set(["connect", "connectOrCreate", "create", "upsert"]);
|
|
98
|
+
var FOREIGN_KEY_CHANGING_OPS = /* @__PURE__ */ new Set(["connect", "connectOrCreate", "create", "delete", "disconnect", "set", "upsert"]);
|
|
99
|
+
var overlaps = (fields, referenced) => fields.some((field) => referenced.has(field));
|
|
100
|
+
function widenIfForeignKeyReferenced(ctx, model, relation) {
|
|
101
|
+
if (overlaps(relation.localFields, referencedFields(ctx.config, model))) touchReferencing(ctx, model);
|
|
102
|
+
const opposite = (ctx.config.relationGraph[relation.targetModel] ?? []).find(
|
|
103
|
+
(candidate) => candidate !== relation && candidate.relationName !== void 0 && candidate.relationName === relation.relationName
|
|
104
|
+
);
|
|
105
|
+
if (opposite && overlaps(opposite.localFields, referencedFields(ctx.config, relation.targetModel))) {
|
|
106
|
+
touchReferencing(ctx, relation.targetModel);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function nestedWrites(ctx, model, data, depth) {
|
|
110
|
+
if (!isPlainRecord(data)) return;
|
|
111
|
+
for (const relation of ctx.config.relationGraph[model] ?? []) {
|
|
112
|
+
const ops = data[relation.fieldName];
|
|
113
|
+
if (!isPlainRecord(ops)) continue;
|
|
114
|
+
const target = relation.targetModel;
|
|
115
|
+
if (depth >= MAX_NESTED_WRITE_DEPTH) {
|
|
116
|
+
ctx.plan.all = true;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
touchWrite(ctx, target);
|
|
120
|
+
const recurse = (value) => nestedWrites(ctx, target, value, depth + 1);
|
|
121
|
+
for (const [op, value] of Object.entries(ops)) {
|
|
122
|
+
const items = asItems(value);
|
|
123
|
+
if (relation.oneToOne === true && ONE_TO_ONE_REPARENTING_OPS.has(op)) {
|
|
124
|
+
touchWide(ctx, target);
|
|
125
|
+
touchWide(ctx, model);
|
|
126
|
+
}
|
|
127
|
+
if (FOREIGN_KEY_CHANGING_OPS.has(op)) widenIfForeignKeyReferenced(ctx, model, relation);
|
|
128
|
+
switch (op) {
|
|
129
|
+
case "create":
|
|
130
|
+
items.forEach(recurse);
|
|
131
|
+
break;
|
|
132
|
+
case "createMany":
|
|
133
|
+
break;
|
|
134
|
+
case "connect":
|
|
135
|
+
items.forEach((item) => touchEntity(ctx, target, item));
|
|
136
|
+
break;
|
|
137
|
+
case "connectOrCreate":
|
|
138
|
+
for (const item of items) {
|
|
139
|
+
touchEntity(ctx, target, isPlainRecord(item) ? item.where : void 0);
|
|
140
|
+
if (isPlainRecord(item)) recurse(item.create);
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
143
|
+
case "disconnect":
|
|
144
|
+
items.forEach((item) => isPlainRecord(item) ? touchEntity(ctx, target, item) : touchWide(ctx, target));
|
|
145
|
+
break;
|
|
146
|
+
case "delete":
|
|
147
|
+
items.forEach((item) => isPlainRecord(item) ? touchEntity(ctx, target, item) : touchWide(ctx, target));
|
|
148
|
+
touchReferencing(ctx, target);
|
|
149
|
+
break;
|
|
150
|
+
case "deleteMany":
|
|
151
|
+
touchWide(ctx, target);
|
|
152
|
+
touchReferencing(ctx, target);
|
|
153
|
+
break;
|
|
154
|
+
case "update":
|
|
155
|
+
case "upsert":
|
|
156
|
+
for (const item of items) {
|
|
157
|
+
const hasWhere = isPlainRecord(item) && "where" in item;
|
|
158
|
+
if (hasWhere) touchEntity(ctx, target, item.where);
|
|
159
|
+
else touchWide(ctx, target);
|
|
160
|
+
const payloads = isPlainRecord(item) ? [item.data, item.create, item.update, hasWhere ? void 0 : item] : [];
|
|
161
|
+
for (const payload of payloads) {
|
|
162
|
+
touchReferencingIfKeyChanges(ctx, target, payload);
|
|
163
|
+
recurse(payload);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
default:
|
|
168
|
+
touchWide(ctx, target);
|
|
169
|
+
for (const item of items) if (isPlainRecord(item)) touchReferencingIfKeyChanges(ctx, target, item.data);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function planWrite(config, model, operation, args) {
|
|
175
|
+
const ctx = { config, plan: { all: false, touched: /* @__PURE__ */ new Map() } };
|
|
176
|
+
const input = isPlainRecord(args) ? args : {};
|
|
177
|
+
touchWrite(ctx, model);
|
|
178
|
+
switch (operation) {
|
|
179
|
+
case "create":
|
|
180
|
+
nestedWrites(ctx, model, input.data, 0);
|
|
181
|
+
break;
|
|
182
|
+
case "createMany":
|
|
183
|
+
case "createManyAndReturn":
|
|
184
|
+
break;
|
|
185
|
+
case "update":
|
|
186
|
+
touchEntity(ctx, model, input.where);
|
|
187
|
+
touchReferencingIfKeyChanges(ctx, model, input.data);
|
|
188
|
+
nestedWrites(ctx, model, input.data, 0);
|
|
189
|
+
break;
|
|
190
|
+
case "upsert":
|
|
191
|
+
touchEntity(ctx, model, input.where);
|
|
192
|
+
touchReferencingIfKeyChanges(ctx, model, input.update);
|
|
193
|
+
nestedWrites(ctx, model, input.create, 0);
|
|
194
|
+
nestedWrites(ctx, model, input.update, 0);
|
|
195
|
+
break;
|
|
196
|
+
case "delete":
|
|
197
|
+
touchEntity(ctx, model, input.where);
|
|
198
|
+
touchReferencing(ctx, model);
|
|
199
|
+
break;
|
|
200
|
+
case "deleteMany":
|
|
201
|
+
touchWide(ctx, model);
|
|
202
|
+
touchReferencing(ctx, model);
|
|
203
|
+
break;
|
|
204
|
+
default:
|
|
205
|
+
touchWide(ctx, model);
|
|
206
|
+
touchReferencingIfKeyChanges(ctx, model, input.data);
|
|
207
|
+
}
|
|
208
|
+
return ctx.plan;
|
|
209
|
+
}
|
|
210
|
+
function planFences(plan) {
|
|
211
|
+
if (plan.all) return [GLOBAL_FENCE];
|
|
212
|
+
const fences = [];
|
|
213
|
+
for (const [model, { pks, wide }] of plan.touched) {
|
|
214
|
+
fences.push(writeFence(model));
|
|
215
|
+
if (wide || pks.size > MAX_ENTITY_FENCES_PER_MODEL) fences.push(modelFence(model));
|
|
216
|
+
else for (const pk of pks) fences.push(entityFence(model, pk));
|
|
217
|
+
}
|
|
218
|
+
return fences;
|
|
219
|
+
}
|
|
220
|
+
function rawWritePlanFences(config, target) {
|
|
221
|
+
if ("all" in target) return [GLOBAL_FENCE];
|
|
222
|
+
const ctx = { config, plan: { all: false, touched: /* @__PURE__ */ new Map() } };
|
|
223
|
+
const known = new Set(config.modelNames);
|
|
224
|
+
const models = "models" in target ? target.models : target.entities.map(({ model }) => model);
|
|
225
|
+
const unknown = models.filter((model) => !known.has(model));
|
|
226
|
+
if (unknown.length > 0) throw new TypeError(`cache invalidation: unknown models ${unknown.join(", ")}`);
|
|
227
|
+
if ("models" in target) target.models.forEach((model) => touchWide(ctx, model));
|
|
228
|
+
else {
|
|
229
|
+
for (const { model, pk } of target.entities) {
|
|
230
|
+
const fields = pkFieldsOf(config, model);
|
|
231
|
+
const encoded = pk.length === fields.length ? pkFromRow(Object.fromEntries(fields.map((field, i) => [field, pk[i]])), fields) : null;
|
|
232
|
+
if (encoded === null) touchWide(ctx, model);
|
|
233
|
+
else touch(ctx.plan, model).pks.add(encoded);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
models.forEach((model) => touchReferencing(ctx, model));
|
|
237
|
+
return planFences(ctx.plan);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/core/shape.ts
|
|
241
|
+
var DEFAULT_SHAPE = { freshTtlSeconds: 3600, negativeTtlSeconds: 600, softTtlRatio: 0.8 };
|
|
242
|
+
function validate(label, shape) {
|
|
243
|
+
if (!shape) return;
|
|
244
|
+
for (const field of ["freshTtlSeconds", "negativeTtlSeconds"]) {
|
|
245
|
+
const value = shape[field];
|
|
246
|
+
if (value !== void 0 && !(Number.isFinite(value) && value > 0 && value <= MAX_SHAPE_TTL_SECONDS)) {
|
|
247
|
+
throw new TypeError(`cache shape ${label}: ${field} must be in (0, ${MAX_SHAPE_TTL_SECONDS}]`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const ratio = shape.softTtlRatio;
|
|
251
|
+
if (ratio !== void 0 && !(Number.isFinite(ratio) && ratio > 0 && ratio <= 1)) {
|
|
252
|
+
throw new TypeError(`cache shape ${label}: softTtlRatio must be in (0, 1]`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function validateShapes(shape) {
|
|
256
|
+
validate("default", shape?.default);
|
|
257
|
+
for (const [model, value] of Object.entries(shape?.byModel ?? {})) validate(`byModel.${model}`, value);
|
|
258
|
+
}
|
|
259
|
+
function resolveShape(shape, model) {
|
|
260
|
+
const pick = (field) => shape?.byModel?.[model]?.[field] ?? shape?.default?.[field] ?? DEFAULT_SHAPE[field];
|
|
261
|
+
return { freshTtlSeconds: pick("freshTtlSeconds"), negativeTtlSeconds: pick("negativeTtlSeconds"), softTtlRatio: pick("softTtlRatio") };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/core/targets.ts
|
|
265
|
+
var MAX_RELATION_DEPTH = 10;
|
|
266
|
+
var RELATION_FILTER_KEYS = ["some", "every", "none", "is", "isNot"];
|
|
267
|
+
var LOGICAL_KEYS = /* @__PURE__ */ new Set(["AND", "OR", "NOT"]);
|
|
268
|
+
function relationsOf(graph, model) {
|
|
269
|
+
return new Map((graph[model] ?? []).map((relation) => [relation.fieldName, relation]));
|
|
270
|
+
}
|
|
271
|
+
function reach(walk, relation) {
|
|
272
|
+
walk.out.models.add(relation.targetModel);
|
|
273
|
+
walk.out.relational = true;
|
|
274
|
+
}
|
|
275
|
+
function walkFilter(walk, model, value, depth) {
|
|
276
|
+
if (depth > MAX_RELATION_DEPTH) return false;
|
|
277
|
+
if (Array.isArray(value)) return value.every((item) => walkFilter(walk, model, item, depth + 1));
|
|
278
|
+
if (!isPlainRecord(value)) return true;
|
|
279
|
+
const relations = relationsOf(walk.graph, model);
|
|
280
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
281
|
+
if (LOGICAL_KEYS.has(key)) {
|
|
282
|
+
if (!walkFilter(walk, model, nested, depth + 1)) return false;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const relation = relations.get(key);
|
|
286
|
+
if (!relation) continue;
|
|
287
|
+
reach(walk, relation);
|
|
288
|
+
if (!isPlainRecord(nested)) continue;
|
|
289
|
+
const wrapped = RELATION_FILTER_KEYS.filter((wrapper) => wrapper in nested);
|
|
290
|
+
const inner = wrapped.length > 0 ? wrapped.map((wrapper) => nested[wrapper]) : [nested];
|
|
291
|
+
if (!inner.every((item) => walkFilter(walk, relation.targetModel, item, depth + 1))) return false;
|
|
292
|
+
}
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
function walkCount(walk, model, count, depth) {
|
|
296
|
+
if (count === void 0) return true;
|
|
297
|
+
const select = isPlainRecord(count) && isPlainRecord(count.select) ? count.select : null;
|
|
298
|
+
for (const relation of walk.graph[model] ?? []) {
|
|
299
|
+
const selected = select ? select[relation.fieldName] : count;
|
|
300
|
+
if (!selected) continue;
|
|
301
|
+
reach(walk, relation);
|
|
302
|
+
if (isPlainRecord(selected) && !walkFilter(walk, relation.targetModel, selected.where, depth + 1)) return false;
|
|
303
|
+
}
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
function walkArgs(walk, model, args, depth) {
|
|
307
|
+
walk.out.models.add(model);
|
|
308
|
+
if (!isPlainRecord(args)) return true;
|
|
309
|
+
for (const filter of [args.where, args.orderBy, args.cursor]) {
|
|
310
|
+
if (!walkFilter(walk, model, filter, depth)) return false;
|
|
311
|
+
}
|
|
312
|
+
for (const projection of [args.include, args.select]) {
|
|
313
|
+
if (!isPlainRecord(projection)) continue;
|
|
314
|
+
if (!walkCount(walk, model, projection._count, depth)) return false;
|
|
315
|
+
for (const relation of walk.graph[model] ?? []) {
|
|
316
|
+
const nested = projection[relation.fieldName];
|
|
317
|
+
if (!nested) continue;
|
|
318
|
+
reach(walk, relation);
|
|
319
|
+
if (!walkArgs(walk, relation.targetModel, nested, depth + 1)) return false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
function readTargets(graph, model, args) {
|
|
325
|
+
const walk = { graph, out: { models: /* @__PURE__ */ new Set(), relational: false } };
|
|
326
|
+
return walkArgs(walk, model, args, 0) ? walk.out : null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/core/extension.ts
|
|
330
|
+
var CacheUnavailableError = class extends Error {
|
|
331
|
+
constructor(cause) {
|
|
332
|
+
super("cache coordinator unavailable; the write was not executed", { cause });
|
|
333
|
+
this.name = "CacheUnavailableError";
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
var DEFAULT_FILL_POLL_DELAYS_MS = [20, 40, 80, 160, 320, 640];
|
|
337
|
+
var DEFAULT_LOCK_MS = 3e4;
|
|
338
|
+
var DEFAULT_LEASE_MS = 6e4;
|
|
339
|
+
var DEFAULT_MAX_VALUE_BYTES = 15e5;
|
|
340
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
341
|
+
var pickEpochs = (epochs, fences) => Object.fromEntries(fences.map((fence) => [fence, epochs[fence] ?? 0]));
|
|
342
|
+
var isNegative = (value) => value === null || Array.isArray(value) && value.length === 0;
|
|
343
|
+
var sum = (values) => values.reduce((total, value) => total + value, 0);
|
|
344
|
+
function internalParams(params) {
|
|
345
|
+
const internal = isPlainRecord(params.__internalParams) ? params.__internalParams : {};
|
|
346
|
+
const transaction = internal.transaction;
|
|
347
|
+
return {
|
|
348
|
+
dataPath: Array.isArray(internal.dataPath) ? internal.dataPath : [],
|
|
349
|
+
inBatch: isPlainRecord(transaction) && transaction.kind === "batch"
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function validateOptions(options) {
|
|
353
|
+
if (options.config.configFormat !== CONFIG_FORMAT) {
|
|
354
|
+
throw new TypeError(
|
|
355
|
+
`cache extension: generated config format ${String(options.config.configFormat)} does not match ${CONFIG_FORMAT}; run prisma generate`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
const inRange = (value, max) => value === void 0 || Number.isFinite(value) && value > 0 && value <= max;
|
|
359
|
+
const problems = [
|
|
360
|
+
!inRange(options.lockMs, MAX_LOCK_MS) && `lockMs must be in (0, ${MAX_LOCK_MS}]`,
|
|
361
|
+
!inRange(options.leaseMs, MAX_LEASE_MS) && `leaseMs must be in (0, ${MAX_LEASE_MS}]`,
|
|
362
|
+
!inRange(options.maxValueBytes, MAX_VALUE_BYTES) && `maxValueBytes must be in (0, ${MAX_VALUE_BYTES}]`,
|
|
363
|
+
options.fillPollDelaysMs?.some((delay) => !(Number.isFinite(delay) && delay >= 0)) && "fillPollDelaysMs must be non-negative",
|
|
364
|
+
options.excludeModels?.some((model) => !options.config.modelNames.includes(model)) && "excludeModels names an unknown model",
|
|
365
|
+
options.config.hasDecimalFields && !options.decimal && "decimal is required because the schema has Decimal fields (pass Prisma.Decimal)",
|
|
366
|
+
options.generation !== void 0 && !(options.generation.length > 0 && options.generation.length <= MAX_GENERATION_LENGTH) && `generation must be 1..${MAX_GENERATION_LENGTH} characters`,
|
|
367
|
+
options.coordinationGeneration !== void 0 && !(options.coordinationGeneration.length > 0 && options.coordinationGeneration.length <= MAX_GENERATION_LENGTH) && `coordinationGeneration must be 1..${MAX_GENERATION_LENGTH} characters`
|
|
368
|
+
].filter((problem) => typeof problem === "string");
|
|
369
|
+
if (problems.length > 0) throw new TypeError(`cache extension: ${problems.join("; ")}`);
|
|
370
|
+
validateShapes(options.shape);
|
|
371
|
+
}
|
|
372
|
+
function createCacheExtension(options) {
|
|
373
|
+
validateOptions(options);
|
|
374
|
+
const { config, store, unsafeTestHooks: hooks } = options;
|
|
375
|
+
const enabled = options.enabled ?? true;
|
|
376
|
+
const excluded = new Set(options.excludeModels ?? []);
|
|
377
|
+
const scope = options.scope ?? "";
|
|
378
|
+
const generation = options.coordinationGeneration ?? `${PLANNER_VERSION}/${config.cacheVersion}/${options.generation ?? ""}`;
|
|
379
|
+
const pollDelays = options.fillPollDelaysMs ?? DEFAULT_FILL_POLL_DELAYS_MS;
|
|
380
|
+
const lockMs = options.lockMs ?? DEFAULT_LOCK_MS;
|
|
381
|
+
const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;
|
|
382
|
+
const maxValueBytes = options.maxValueBytes ?? DEFAULT_MAX_VALUE_BYTES;
|
|
383
|
+
const report = (error, context) => options.onError?.(error, context);
|
|
384
|
+
const isCacheable = (model) => enabled && config.cacheableByModel[model] === true && !excluded.has(model);
|
|
385
|
+
function readContext(model, operation, args, query, key) {
|
|
386
|
+
const targets = readTargets(config.relationGraph, model, args);
|
|
387
|
+
if (!targets || [...targets.models].some((target) => !isCacheable(target))) return null;
|
|
388
|
+
const rootPk = operation.startsWith("findUnique") ? pkFromWhere(
|
|
389
|
+
isPlainRecord(args) ? args.where : void 0,
|
|
390
|
+
config.primaryKeyFieldsByModel[model] ?? ["id"],
|
|
391
|
+
config.primaryKeyNameByModel[model]
|
|
392
|
+
) : null;
|
|
393
|
+
const base = [GLOBAL_FENCE, modelFence(model)];
|
|
394
|
+
const entity = rootPk === null ? null : entityFence(model, rootPk);
|
|
395
|
+
const fences = [...base, ...[...targets.models].map(writeFence), ...entity ? [entity] : []];
|
|
396
|
+
const entityFences = entity && !targets.relational ? [...base, entity] : null;
|
|
397
|
+
return { args, entityFences, fences, key, model, operation, query };
|
|
398
|
+
}
|
|
399
|
+
const release = (key, lockToken) => store.release({ key, lockToken }).catch((error) => report(error, "release"));
|
|
400
|
+
function serialize(value) {
|
|
401
|
+
try {
|
|
402
|
+
const serialized = JSON.stringify(encode(value));
|
|
403
|
+
if (new TextEncoder().encode(serialized).byteLength <= maxValueBytes) return serialized;
|
|
404
|
+
report(new Error(`cache value exceeds ${maxValueBytes} bytes`), "serialize");
|
|
405
|
+
} catch (error) {
|
|
406
|
+
report(error, "serialize");
|
|
407
|
+
}
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
async function fill(ctx, lockToken, epochs) {
|
|
411
|
+
let value;
|
|
412
|
+
try {
|
|
413
|
+
value = await ctx.query(ctx.args);
|
|
414
|
+
await hooks?.afterFillQuery?.();
|
|
415
|
+
} catch (error) {
|
|
416
|
+
await release(ctx.key, lockToken);
|
|
417
|
+
throw error;
|
|
418
|
+
}
|
|
419
|
+
const serialized = serialize(value);
|
|
420
|
+
if (serialized === null) {
|
|
421
|
+
await release(ctx.key, lockToken);
|
|
422
|
+
return value;
|
|
423
|
+
}
|
|
424
|
+
const shape = resolveShape(options.shape, ctx.model);
|
|
425
|
+
const baseTtl = ctx.operation !== "count" && isNegative(value) ? shape.negativeTtlSeconds : shape.freshTtlSeconds;
|
|
426
|
+
const ttlMs = Math.round(baseTtl * 1e3 * (1 + Math.random() * TTL_JITTER_RATIO));
|
|
427
|
+
const snapshotFences = ctx.entityFences && isPlainRecord(value) ? ctx.entityFences : ctx.fences;
|
|
428
|
+
try {
|
|
429
|
+
const result = await store.write({
|
|
430
|
+
key: ctx.key,
|
|
431
|
+
lockToken,
|
|
432
|
+
snapshot: pickEpochs(epochs, snapshotFences),
|
|
433
|
+
softTtlMs: Math.round(ttlMs * shape.softTtlRatio),
|
|
434
|
+
ttlMs,
|
|
435
|
+
value: serialized
|
|
436
|
+
});
|
|
437
|
+
if (!result.ok) report(new Error(`cache write rejected: ${result.reason}`), "write");
|
|
438
|
+
} catch (error) {
|
|
439
|
+
report(error, "write");
|
|
440
|
+
await release(ctx.key, lockToken);
|
|
441
|
+
}
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
async function scheduleRefresh(ctx, response) {
|
|
445
|
+
const token = response.refreshToken;
|
|
446
|
+
if (!token) return;
|
|
447
|
+
if (!options.waitUntil) return release(ctx.key, token);
|
|
448
|
+
try {
|
|
449
|
+
options.waitUntil(fill(ctx, token, response.epochs).catch((error) => report(error, "refresh")));
|
|
450
|
+
} catch (error) {
|
|
451
|
+
report(error, "waitUntil");
|
|
452
|
+
await release(ctx.key, token);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function handleRead(model, operation, args, query, dataPath) {
|
|
456
|
+
let key;
|
|
457
|
+
try {
|
|
458
|
+
const identity = [PLANNER_VERSION, config.cacheVersion, scope, model, operation, dataPath, (options.keyArgs ? options.keyArgs(args) : args) ?? null];
|
|
459
|
+
key = `${model}:${await sha256Hex(stableStringify(identity))}`;
|
|
460
|
+
} catch (error) {
|
|
461
|
+
report(error, "key");
|
|
462
|
+
return query(args);
|
|
463
|
+
}
|
|
464
|
+
const ctx = readContext(model, operation, args, query, key);
|
|
465
|
+
if (!ctx) return query(args);
|
|
466
|
+
for (let attempt = 0; ; attempt++) {
|
|
467
|
+
let response;
|
|
468
|
+
try {
|
|
469
|
+
response = await store.read({ fences: ctx.fences, generation, key, lockMs, refresh: !!options.waitUntil });
|
|
470
|
+
} catch (error) {
|
|
471
|
+
report(error, "read");
|
|
472
|
+
return query(args);
|
|
473
|
+
}
|
|
474
|
+
if (response.kind === "hit") {
|
|
475
|
+
let value;
|
|
476
|
+
try {
|
|
477
|
+
value = decode(JSON.parse(response.value), options.decimal);
|
|
478
|
+
} catch (error) {
|
|
479
|
+
report(error, "decode");
|
|
480
|
+
if (response.refreshToken) await release(key, response.refreshToken);
|
|
481
|
+
return query(args);
|
|
482
|
+
}
|
|
483
|
+
await scheduleRefresh(ctx, response);
|
|
484
|
+
return value;
|
|
485
|
+
}
|
|
486
|
+
if (response.lockToken) return fill(ctx, response.lockToken, response.epochs);
|
|
487
|
+
const delay = pollDelays[attempt];
|
|
488
|
+
const holderTooSlow = response.lockHeldForMs !== null && response.lockHeldForMs > sum(pollDelays);
|
|
489
|
+
if (response.pending || delay === void 0 || holderTooSlow) return query(args);
|
|
490
|
+
await sleep(delay);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
async function withLease(fences, run) {
|
|
494
|
+
const token = crypto.randomUUID();
|
|
495
|
+
try {
|
|
496
|
+
await store.beginWrite({ fences, generation, leaseMs, token });
|
|
497
|
+
} catch (error) {
|
|
498
|
+
report(error, "beginWrite");
|
|
499
|
+
await endWrite(token, fences);
|
|
500
|
+
throw new CacheUnavailableError(error);
|
|
501
|
+
}
|
|
502
|
+
try {
|
|
503
|
+
await hooks?.afterBeginWrite?.();
|
|
504
|
+
return await run();
|
|
505
|
+
} finally {
|
|
506
|
+
if (!hooks?.skipEndWrite?.()) await endWrite(token, fences);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
async function endWrite(token, fences) {
|
|
510
|
+
await store.endWrite({ fences, token }).catch((error) => report(error, "endWrite"));
|
|
511
|
+
}
|
|
512
|
+
const targetFences = (target) => rawWritePlanFences(config, target);
|
|
513
|
+
return {
|
|
514
|
+
client: {
|
|
515
|
+
async $cacheInvalidate(target) {
|
|
516
|
+
await store.invalidate(targetFences(target));
|
|
517
|
+
},
|
|
518
|
+
async $cacheRawWrite(target, run) {
|
|
519
|
+
const fences = targetFences(target);
|
|
520
|
+
return enabled ? withLease(fences, run) : run();
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
name: "dee-wan-cache",
|
|
524
|
+
query: {
|
|
525
|
+
$allModels: {
|
|
526
|
+
$allOperations(params) {
|
|
527
|
+
const { args, model, operation, query } = params;
|
|
528
|
+
if (!model) return query(args);
|
|
529
|
+
const { dataPath, inBatch } = internalParams(params);
|
|
530
|
+
if (READ_OPERATIONS.has(operation) && isCacheable(model) && !inBatch) {
|
|
531
|
+
return handleRead(model, operation, args, query, dataPath);
|
|
532
|
+
}
|
|
533
|
+
if (WRITE_OPERATIONS.has(operation) && enabled) {
|
|
534
|
+
return withLease(planFences(planWrite(config, model, operation, args)), () => query(args));
|
|
535
|
+
}
|
|
536
|
+
return query(args);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export { CacheUnavailableError, createCacheExtension, readTargets };
|
|
544
|
+
//# sourceMappingURL=chunk-ZREX7LLC.js.map
|
|
545
|
+
//# sourceMappingURL=chunk-ZREX7LLC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/pk.ts","../src/core/plan.ts","../src/core/shape.ts","../src/core/targets.ts","../src/core/extension.ts"],"names":[],"mappings":"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","file":"chunk-ZREX7LLC.js","sourcesContent":["export type PkValue = number | string;\n\nexport function isPlainRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function encodePk(parts: ReadonlyArray<PkValue>): string {\n return parts.map((part) => encodeURIComponent(String(part))).join(\":\");\n}\n\nfunction unwrapEquals(value: unknown): unknown {\n return isPlainRecord(value) && \"equals\" in value ? value.equals : value;\n}\n\nfunction isScalarPk(value: unknown): value is PkValue {\n return typeof value === \"string\" || (typeof value === \"number\" && Number.isFinite(value));\n}\n\nexport function pkFromWhere(where: unknown, pkFields: string[], compoundName?: string): null | string {\n if (!isPlainRecord(where)) return null;\n const compound = where[compoundName ?? pkFields.join(\"_\")];\n const source = pkFields.length > 1 && isPlainRecord(compound) ? compound : where;\n const parts: PkValue[] = [];\n for (const field of pkFields) {\n const value = source === where ? unwrapEquals(where[field]) : source[field];\n if (!isScalarPk(value)) return null;\n parts.push(value);\n }\n return encodePk(parts);\n}\n\nexport function pkFromRow(row: unknown, pkFields: string[]): null | string {\n if (!isPlainRecord(row)) return null;\n const parts: PkValue[] = [];\n for (const field of pkFields) {\n const value = row[field];\n if (!isScalarPk(value)) return null;\n parts.push(value);\n }\n return encodePk(parts);\n}\n","import type { GeneratedCacheConfig, InvalidationTarget, RelationInfo } from \"./types\";\n\nimport { entityFence, GLOBAL_FENCE, modelFence, writeFence } from \"./fences\";\nimport { isPlainRecord, pkFromRow, pkFromWhere } from \"./pk\";\n\nexport const MAX_NESTED_WRITE_DEPTH = 5;\nexport const MAX_ENTITY_FENCES_PER_MODEL = 100;\n\nexport const READ_OPERATIONS = new Set([\"aggregate\", \"count\", \"findFirst\", \"findFirstOrThrow\", \"findMany\", \"findUnique\", \"findUniqueOrThrow\", \"groupBy\"]);\n\nexport const WRITE_OPERATIONS = new Set([\n \"create\",\n \"createMany\",\n \"createManyAndReturn\",\n \"delete\",\n \"deleteMany\",\n \"update\",\n \"updateMany\",\n \"updateManyAndReturn\",\n \"upsert\",\n]);\n\ninterface ModelTouch {\n pks: Set<string>;\n wide: boolean;\n}\n\nexport interface WritePlan {\n all: boolean;\n touched: Map<string, ModelTouch>;\n}\n\ninterface PlanContext {\n config: GeneratedCacheConfig;\n plan: WritePlan;\n}\n\nconst pkFieldsOf = (config: GeneratedCacheConfig, model: string): string[] => config.primaryKeyFieldsByModel[model] ?? [\"id\"];\n\nfunction touch(plan: WritePlan, model: string): ModelTouch {\n const existing = plan.touched.get(model);\n if (existing) return existing;\n const created: ModelTouch = { pks: new Set(), wide: false };\n plan.touched.set(model, created);\n return created;\n}\n\nconst touchWrite = (ctx: PlanContext, model: string): void => void touch(ctx.plan, model);\n\nconst touchWide = (ctx: PlanContext, model: string): void => void (touch(ctx.plan, model).wide = true);\n\nfunction touchEntity(ctx: PlanContext, model: string, where: unknown): void {\n const pk = pkFromWhere(where, pkFieldsOf(ctx.config, model), ctx.config.primaryKeyNameByModel[model]);\n if (pk === null) touchWide(ctx, model);\n else touch(ctx.plan, model).pks.add(pk);\n}\n\nfunction referencedFields(config: GeneratedCacheConfig, model: string): Set<string> {\n const fields = new Set<string>();\n for (const relations of Object.values(config.relationGraph)) {\n for (const relation of relations) {\n if (relation.targetModel === model && relation.localFields.length > 0) {\n for (const field of relation.foreignFields) fields.add(field);\n }\n }\n }\n return fields;\n}\n\nfunction touchReferencing(ctx: PlanContext, model: string, seen = new Set<string>()): void {\n if (seen.has(model)) return;\n seen.add(model);\n for (const [owner, relations] of Object.entries(ctx.config.relationGraph)) {\n const references = relations.some((relation) => relation.targetModel === model && relation.localFields.length > 0);\n if (!references) continue;\n touchWide(ctx, owner);\n touchReferencing(ctx, owner, seen);\n }\n}\n\nfunction touchReferencingIfKeyChanges(ctx: PlanContext, model: string, data: unknown): void {\n if (!isPlainRecord(data)) return;\n const referenced = referencedFields(ctx.config, model);\n if (Object.keys(data).some((field) => referenced.has(field))) touchReferencing(ctx, model);\n}\n\nconst asItems = (value: unknown): unknown[] => (Array.isArray(value) ? value : [value]);\n\nconst ONE_TO_ONE_REPARENTING_OPS = new Set([\"connect\", \"connectOrCreate\", \"create\", \"upsert\"]);\n\nconst FOREIGN_KEY_CHANGING_OPS = new Set([\"connect\", \"connectOrCreate\", \"create\", \"delete\", \"disconnect\", \"set\", \"upsert\"]);\n\nconst overlaps = (fields: string[], referenced: Set<string>): boolean => fields.some((field) => referenced.has(field));\n\nfunction widenIfForeignKeyReferenced(ctx: PlanContext, model: string, relation: RelationInfo): void {\n if (overlaps(relation.localFields, referencedFields(ctx.config, model))) touchReferencing(ctx, model);\n const opposite = (ctx.config.relationGraph[relation.targetModel] ?? []).find(\n (candidate) => candidate !== relation && candidate.relationName !== undefined && candidate.relationName === relation.relationName,\n );\n if (opposite && overlaps(opposite.localFields, referencedFields(ctx.config, relation.targetModel))) {\n touchReferencing(ctx, relation.targetModel);\n }\n}\n\nfunction nestedWrites(ctx: PlanContext, model: string, data: unknown, depth: number): void {\n if (!isPlainRecord(data)) return;\n for (const relation of ctx.config.relationGraph[model] ?? []) {\n const ops = data[relation.fieldName];\n if (!isPlainRecord(ops)) continue;\n const target = relation.targetModel;\n if (depth >= MAX_NESTED_WRITE_DEPTH) {\n ctx.plan.all = true;\n return;\n }\n touchWrite(ctx, target);\n const recurse = (value: unknown) => nestedWrites(ctx, target, value, depth + 1);\n for (const [op, value] of Object.entries(ops)) {\n const items = asItems(value);\n if (relation.oneToOne === true && ONE_TO_ONE_REPARENTING_OPS.has(op)) {\n touchWide(ctx, target);\n touchWide(ctx, model);\n }\n if (FOREIGN_KEY_CHANGING_OPS.has(op)) widenIfForeignKeyReferenced(ctx, model, relation);\n switch (op) {\n case \"create\":\n items.forEach(recurse);\n break;\n case \"createMany\":\n break;\n case \"connect\":\n items.forEach((item) => touchEntity(ctx, target, item));\n break;\n case \"connectOrCreate\":\n for (const item of items) {\n touchEntity(ctx, target, isPlainRecord(item) ? item.where : undefined);\n if (isPlainRecord(item)) recurse(item.create);\n }\n break;\n case \"disconnect\":\n items.forEach((item) => (isPlainRecord(item) ? touchEntity(ctx, target, item) : touchWide(ctx, target)));\n break;\n case \"delete\":\n items.forEach((item) => (isPlainRecord(item) ? touchEntity(ctx, target, item) : touchWide(ctx, target)));\n touchReferencing(ctx, target);\n break;\n case \"deleteMany\":\n touchWide(ctx, target);\n touchReferencing(ctx, target);\n break;\n case \"update\":\n case \"upsert\":\n for (const item of items) {\n const hasWhere = isPlainRecord(item) && \"where\" in item;\n if (hasWhere) touchEntity(ctx, target, item.where);\n else touchWide(ctx, target);\n const payloads = isPlainRecord(item) ? [item.data, item.create, item.update, hasWhere ? undefined : item] : [];\n for (const payload of payloads) {\n touchReferencingIfKeyChanges(ctx, target, payload);\n recurse(payload);\n }\n }\n break;\n default:\n touchWide(ctx, target);\n for (const item of items) if (isPlainRecord(item)) touchReferencingIfKeyChanges(ctx, target, item.data);\n }\n }\n }\n}\n\nexport function planWrite(config: GeneratedCacheConfig, model: string, operation: string, args: unknown): WritePlan {\n const ctx: PlanContext = { config, plan: { all: false, touched: new Map() } };\n const input = isPlainRecord(args) ? args : {};\n touchWrite(ctx, model);\n switch (operation) {\n case \"create\":\n nestedWrites(ctx, model, input.data, 0);\n break;\n case \"createMany\":\n case \"createManyAndReturn\":\n break;\n case \"update\":\n touchEntity(ctx, model, input.where);\n touchReferencingIfKeyChanges(ctx, model, input.data);\n nestedWrites(ctx, model, input.data, 0);\n break;\n case \"upsert\":\n touchEntity(ctx, model, input.where);\n touchReferencingIfKeyChanges(ctx, model, input.update);\n nestedWrites(ctx, model, input.create, 0);\n nestedWrites(ctx, model, input.update, 0);\n break;\n case \"delete\":\n touchEntity(ctx, model, input.where);\n touchReferencing(ctx, model);\n break;\n case \"deleteMany\":\n touchWide(ctx, model);\n touchReferencing(ctx, model);\n break;\n default:\n touchWide(ctx, model);\n touchReferencingIfKeyChanges(ctx, model, input.data);\n }\n return ctx.plan;\n}\n\nexport function planFences(plan: WritePlan): string[] {\n if (plan.all) return [GLOBAL_FENCE];\n const fences: string[] = [];\n for (const [model, { pks, wide }] of plan.touched) {\n fences.push(writeFence(model));\n if (wide || pks.size > MAX_ENTITY_FENCES_PER_MODEL) fences.push(modelFence(model));\n else for (const pk of pks) fences.push(entityFence(model, pk));\n }\n return fences;\n}\n\nexport function rawWritePlanFences(config: GeneratedCacheConfig, target: InvalidationTarget): string[] {\n if (\"all\" in target) return [GLOBAL_FENCE];\n const ctx: PlanContext = { config, plan: { all: false, touched: new Map() } };\n const known = new Set(config.modelNames);\n const models = \"models\" in target ? target.models : target.entities.map(({ model }) => model);\n const unknown = models.filter((model) => !known.has(model));\n if (unknown.length > 0) throw new TypeError(`cache invalidation: unknown models ${unknown.join(\", \")}`);\n if (\"models\" in target) target.models.forEach((model) => touchWide(ctx, model));\n else {\n for (const { model, pk } of target.entities) {\n const fields = pkFieldsOf(config, model);\n const encoded = pk.length === fields.length ? pkFromRow(Object.fromEntries(fields.map((field, i) => [field, pk[i]])), fields) : null;\n if (encoded === null) touchWide(ctx, model);\n else touch(ctx.plan, model).pks.add(encoded);\n }\n }\n models.forEach((model) => touchReferencing(ctx, model));\n return planFences(ctx.plan);\n}\n","import type { CacheExtensionOptions, CacheShape, ResolvedShape } from \"./types\";\n\nimport { MAX_SHAPE_TTL_SECONDS } from \"./limits\";\n\nexport const DEFAULT_SHAPE: ResolvedShape = { freshTtlSeconds: 3600, negativeTtlSeconds: 600, softTtlRatio: 0.8 };\n\nfunction validate(label: string, shape: CacheShape | undefined): void {\n if (!shape) return;\n for (const field of [\"freshTtlSeconds\", \"negativeTtlSeconds\"] as const) {\n const value = shape[field];\n if (value !== undefined && !(Number.isFinite(value) && value > 0 && value <= MAX_SHAPE_TTL_SECONDS)) {\n throw new TypeError(`cache shape ${label}: ${field} must be in (0, ${MAX_SHAPE_TTL_SECONDS}]`);\n }\n }\n const ratio = shape.softTtlRatio;\n if (ratio !== undefined && !(Number.isFinite(ratio) && ratio > 0 && ratio <= 1)) {\n throw new TypeError(`cache shape ${label}: softTtlRatio must be in (0, 1]`);\n }\n}\n\nexport function validateShapes(shape: CacheExtensionOptions[\"shape\"]): void {\n validate(\"default\", shape?.default);\n for (const [model, value] of Object.entries(shape?.byModel ?? {})) validate(`byModel.${model}`, value);\n}\n\nexport function resolveShape(shape: CacheExtensionOptions[\"shape\"], model: string): ResolvedShape {\n const pick = <K extends keyof ResolvedShape>(field: K): ResolvedShape[K] =>\n shape?.byModel?.[model]?.[field] ?? shape?.default?.[field] ?? DEFAULT_SHAPE[field];\n return { freshTtlSeconds: pick(\"freshTtlSeconds\"), negativeTtlSeconds: pick(\"negativeTtlSeconds\"), softTtlRatio: pick(\"softTtlRatio\") };\n}\n","import type { RelationInfo } from \"./types\";\n\nimport { isPlainRecord } from \"./pk\";\n\nexport const MAX_RELATION_DEPTH = 10;\n\nconst RELATION_FILTER_KEYS = [\"some\", \"every\", \"none\", \"is\", \"isNot\"];\nconst LOGICAL_KEYS = new Set([\"AND\", \"OR\", \"NOT\"]);\n\ntype Graph = Record<string, RelationInfo[]>;\n\nexport interface ReadTargets {\n models: Set<string>;\n relational: boolean;\n}\n\ninterface Walk {\n graph: Graph;\n out: ReadTargets;\n}\n\nfunction relationsOf(graph: Graph, model: string): Map<string, RelationInfo> {\n return new Map((graph[model] ?? []).map((relation) => [relation.fieldName, relation]));\n}\n\nfunction reach(walk: Walk, relation: RelationInfo): void {\n walk.out.models.add(relation.targetModel);\n walk.out.relational = true;\n}\n\nfunction walkFilter(walk: Walk, model: string, value: unknown, depth: number): boolean {\n if (depth > MAX_RELATION_DEPTH) return false;\n if (Array.isArray(value)) return value.every((item) => walkFilter(walk, model, item, depth + 1));\n if (!isPlainRecord(value)) return true;\n const relations = relationsOf(walk.graph, model);\n for (const [key, nested] of Object.entries(value)) {\n if (LOGICAL_KEYS.has(key)) {\n if (!walkFilter(walk, model, nested, depth + 1)) return false;\n continue;\n }\n const relation = relations.get(key);\n if (!relation) continue;\n reach(walk, relation);\n if (!isPlainRecord(nested)) continue;\n const wrapped = RELATION_FILTER_KEYS.filter((wrapper) => wrapper in nested);\n const inner = wrapped.length > 0 ? wrapped.map((wrapper) => nested[wrapper]) : [nested];\n if (!inner.every((item) => walkFilter(walk, relation.targetModel, item, depth + 1))) return false;\n }\n return true;\n}\n\nfunction walkCount(walk: Walk, model: string, count: unknown, depth: number): boolean {\n if (count === undefined) return true;\n const select = isPlainRecord(count) && isPlainRecord(count.select) ? count.select : null;\n for (const relation of walk.graph[model] ?? []) {\n const selected = select ? select[relation.fieldName] : count;\n if (!selected) continue;\n reach(walk, relation);\n if (isPlainRecord(selected) && !walkFilter(walk, relation.targetModel, selected.where, depth + 1)) return false;\n }\n return true;\n}\n\nfunction walkArgs(walk: Walk, model: string, args: unknown, depth: number): boolean {\n walk.out.models.add(model);\n if (!isPlainRecord(args)) return true;\n for (const filter of [args.where, args.orderBy, args.cursor]) {\n if (!walkFilter(walk, model, filter, depth)) return false;\n }\n for (const projection of [args.include, args.select]) {\n if (!isPlainRecord(projection)) continue;\n if (!walkCount(walk, model, projection._count, depth)) return false;\n for (const relation of walk.graph[model] ?? []) {\n const nested = projection[relation.fieldName];\n if (!nested) continue;\n reach(walk, relation);\n if (!walkArgs(walk, relation.targetModel, nested, depth + 1)) return false;\n }\n }\n return true;\n}\n\nexport function readTargets(graph: Graph, model: string, args: unknown): null | ReadTargets {\n const walk: Walk = { graph, out: { models: new Set(), relational: false } };\n return walkArgs(walk, model, args, 0) ? walk.out : null;\n}\n","import type { CacheExtensionOptions, InvalidationTarget, ReadResponse } from \"./types\";\n\nimport { decode, encode, sha256Hex, stableStringify } from \"./codec\";\nimport { entityFence, GLOBAL_FENCE, modelFence, writeFence } from \"./fences\";\nimport {\n CONFIG_FORMAT,\n MAX_GENERATION_LENGTH,\n MAX_LEASE_MS,\n MAX_LOCK_MS,\n MAX_VALUE_BYTES,\n PLANNER_VERSION,\n TTL_JITTER_RATIO,\n} from \"./limits\";\nimport { planFences, planWrite, rawWritePlanFences, READ_OPERATIONS, WRITE_OPERATIONS } from \"./plan\";\nimport { isPlainRecord, pkFromWhere } from \"./pk\";\nimport { resolveShape, validateShapes } from \"./shape\";\nimport { readTargets } from \"./targets\";\n\nexport class CacheUnavailableError extends Error {\n constructor(cause: unknown) {\n super(\"cache coordinator unavailable; the write was not executed\", { cause });\n this.name = \"CacheUnavailableError\";\n }\n}\n\nexport const DEFAULT_FILL_POLL_DELAYS_MS = [20, 40, 80, 160, 320, 640];\nexport const DEFAULT_LOCK_MS = 30_000;\nexport const DEFAULT_LEASE_MS = 60_000;\nexport const DEFAULT_MAX_VALUE_BYTES = 1_500_000;\n\ntype Query = (args: unknown) => Promise<unknown>;\n\ninterface OperationParams {\n __internalParams?: unknown;\n args: unknown;\n model?: string;\n operation: string;\n query: Query;\n}\n\ninterface ReadContext {\n args: unknown;\n entityFences: string[] | null;\n fences: string[];\n key: string;\n model: string;\n operation: string;\n query: Query;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst pickEpochs = (epochs: Record<string, number>, fences: string[]): Record<string, number> =>\n Object.fromEntries(fences.map((fence) => [fence, epochs[fence] ?? 0]));\n\nconst isNegative = (value: unknown): boolean => value === null || (Array.isArray(value) && value.length === 0);\n\nconst sum = (values: number[]): number => values.reduce((total, value) => total + value, 0);\n\nfunction internalParams(params: OperationParams): { dataPath: unknown[]; inBatch: boolean } {\n const internal = isPlainRecord(params.__internalParams) ? params.__internalParams : {};\n const transaction = internal.transaction;\n return {\n dataPath: Array.isArray(internal.dataPath) ? internal.dataPath : [],\n inBatch: isPlainRecord(transaction) && transaction.kind === \"batch\",\n };\n}\n\nfunction validateOptions(options: CacheExtensionOptions): void {\n if (options.config.configFormat !== CONFIG_FORMAT) {\n throw new TypeError(\n `cache extension: generated config format ${String(options.config.configFormat)} does not match ${CONFIG_FORMAT}; run prisma generate`,\n );\n }\n const inRange = (value: number | undefined, max: number) => value === undefined || (Number.isFinite(value) && value > 0 && value <= max);\n const problems = [\n !inRange(options.lockMs, MAX_LOCK_MS) && `lockMs must be in (0, ${MAX_LOCK_MS}]`,\n !inRange(options.leaseMs, MAX_LEASE_MS) && `leaseMs must be in (0, ${MAX_LEASE_MS}]`,\n !inRange(options.maxValueBytes, MAX_VALUE_BYTES) && `maxValueBytes must be in (0, ${MAX_VALUE_BYTES}]`,\n options.fillPollDelaysMs?.some((delay) => !(Number.isFinite(delay) && delay >= 0)) && \"fillPollDelaysMs must be non-negative\",\n options.excludeModels?.some((model) => !options.config.modelNames.includes(model)) && \"excludeModels names an unknown model\",\n options.config.hasDecimalFields &&\n !options.decimal &&\n \"decimal is required because the schema has Decimal fields (pass Prisma.Decimal)\",\n options.generation !== undefined &&\n !(options.generation.length > 0 && options.generation.length <= MAX_GENERATION_LENGTH) &&\n `generation must be 1..${MAX_GENERATION_LENGTH} characters`,\n options.coordinationGeneration !== undefined &&\n !(options.coordinationGeneration.length > 0 && options.coordinationGeneration.length <= MAX_GENERATION_LENGTH) &&\n `coordinationGeneration must be 1..${MAX_GENERATION_LENGTH} characters`,\n ].filter((problem): problem is string => typeof problem === \"string\");\n if (problems.length > 0) throw new TypeError(`cache extension: ${problems.join(\"; \")}`);\n validateShapes(options.shape);\n}\n\nexport function createCacheExtension(options: CacheExtensionOptions) {\n validateOptions(options);\n const { config, store, unsafeTestHooks: hooks } = options;\n const enabled = options.enabled ?? true;\n const excluded = new Set(options.excludeModels ?? []);\n const scope = options.scope ?? \"\";\n const generation = options.coordinationGeneration ?? `${PLANNER_VERSION}/${config.cacheVersion}/${options.generation ?? \"\"}`;\n const pollDelays = options.fillPollDelaysMs ?? DEFAULT_FILL_POLL_DELAYS_MS;\n const lockMs = options.lockMs ?? DEFAULT_LOCK_MS;\n const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;\n const maxValueBytes = options.maxValueBytes ?? DEFAULT_MAX_VALUE_BYTES;\n const report = (error: unknown, context: string): void => options.onError?.(error, context);\n\n const isCacheable = (model: string): boolean =>\n enabled && config.cacheableByModel[model] === true && !excluded.has(model);\n\n function readContext(model: string, operation: string, args: unknown, query: Query, key: string): ReadContext | null {\n const targets = readTargets(config.relationGraph, model, args);\n if (!targets || [...targets.models].some((target) => !isCacheable(target))) return null;\n const rootPk = operation.startsWith(\"findUnique\")\n ? pkFromWhere(\n isPlainRecord(args) ? args.where : undefined,\n config.primaryKeyFieldsByModel[model] ?? [\"id\"],\n config.primaryKeyNameByModel[model],\n )\n : null;\n const base = [GLOBAL_FENCE, modelFence(model)];\n const entity = rootPk === null ? null : entityFence(model, rootPk);\n const fences = [...base, ...[...targets.models].map(writeFence), ...(entity ? [entity] : [])];\n const entityFences = entity && !targets.relational ? [...base, entity] : null;\n return { args, entityFences, fences, key, model, operation, query };\n }\n\n const release = (key: string, lockToken: string): Promise<void> =>\n store.release({ key, lockToken }).catch((error) => report(error, \"release\"));\n\n function serialize(value: unknown): null | string {\n try {\n const serialized = JSON.stringify(encode(value));\n if (new TextEncoder().encode(serialized).byteLength <= maxValueBytes) return serialized;\n report(new Error(`cache value exceeds ${maxValueBytes} bytes`), \"serialize\");\n } catch (error) {\n report(error, \"serialize\");\n }\n return null;\n }\n\n async function fill(ctx: ReadContext, lockToken: string, epochs: Record<string, number>): Promise<unknown> {\n let value: unknown;\n try {\n value = await ctx.query(ctx.args);\n await hooks?.afterFillQuery?.();\n } catch (error) {\n await release(ctx.key, lockToken);\n throw error;\n }\n const serialized = serialize(value);\n if (serialized === null) {\n await release(ctx.key, lockToken);\n return value;\n }\n const shape = resolveShape(options.shape, ctx.model);\n const baseTtl = ctx.operation !== \"count\" && isNegative(value) ? shape.negativeTtlSeconds : shape.freshTtlSeconds;\n const ttlMs = Math.round(baseTtl * 1000 * (1 + Math.random() * TTL_JITTER_RATIO));\n const snapshotFences = ctx.entityFences && isPlainRecord(value) ? ctx.entityFences : ctx.fences;\n try {\n const result = await store.write({\n key: ctx.key,\n lockToken,\n snapshot: pickEpochs(epochs, snapshotFences),\n softTtlMs: Math.round(ttlMs * shape.softTtlRatio),\n ttlMs,\n value: serialized,\n });\n if (!result.ok) report(new Error(`cache write rejected: ${result.reason}`), \"write\");\n } catch (error) {\n report(error, \"write\");\n await release(ctx.key, lockToken);\n }\n return value;\n }\n\n async function scheduleRefresh(ctx: ReadContext, response: Extract<ReadResponse, { kind: \"hit\" }>): Promise<void> {\n const token = response.refreshToken;\n if (!token) return;\n if (!options.waitUntil) return release(ctx.key, token);\n try {\n options.waitUntil(fill(ctx, token, response.epochs).catch((error) => report(error, \"refresh\")));\n } catch (error) {\n report(error, \"waitUntil\");\n await release(ctx.key, token);\n }\n }\n\n async function handleRead(model: string, operation: string, args: unknown, query: Query, dataPath: unknown[]): Promise<unknown> {\n let key: string;\n try {\n const identity = [PLANNER_VERSION, config.cacheVersion, scope, model, operation, dataPath, (options.keyArgs ? options.keyArgs(args) : args) ?? null];\n key = `${model}:${await sha256Hex(stableStringify(identity))}`;\n } catch (error) {\n report(error, \"key\");\n return query(args);\n }\n const ctx = readContext(model, operation, args, query, key);\n if (!ctx) return query(args);\n for (let attempt = 0; ; attempt++) {\n let response: ReadResponse;\n try {\n response = await store.read({ fences: ctx.fences, generation, key, lockMs, refresh: !!options.waitUntil });\n } catch (error) {\n report(error, \"read\");\n return query(args);\n }\n if (response.kind === \"hit\") {\n let value: unknown;\n try {\n value = decode(JSON.parse(response.value), options.decimal);\n } catch (error) {\n report(error, \"decode\");\n if (response.refreshToken) await release(key, response.refreshToken);\n return query(args);\n }\n await scheduleRefresh(ctx, response);\n return value;\n }\n if (response.lockToken) return fill(ctx, response.lockToken, response.epochs);\n const delay = pollDelays[attempt];\n const holderTooSlow = response.lockHeldForMs !== null && response.lockHeldForMs > sum(pollDelays);\n if (response.pending || delay === undefined || holderTooSlow) return query(args);\n await sleep(delay);\n }\n }\n\n async function withLease<T>(fences: string[], run: () => Promise<T>): Promise<T> {\n const token = crypto.randomUUID();\n try {\n await store.beginWrite({ fences, generation, leaseMs, token });\n } catch (error) {\n report(error, \"beginWrite\");\n await endWrite(token, fences);\n throw new CacheUnavailableError(error);\n }\n try {\n await hooks?.afterBeginWrite?.();\n return await run();\n } finally {\n if (!hooks?.skipEndWrite?.()) await endWrite(token, fences);\n }\n }\n\n async function endWrite(token: string, fences: string[]): Promise<void> {\n await store.endWrite({ fences, token }).catch((error) => report(error, \"endWrite\"));\n }\n\n const targetFences = (target: InvalidationTarget): string[] => rawWritePlanFences(config, target);\n\n return {\n client: {\n async $cacheInvalidate(target: InvalidationTarget): Promise<void> {\n await store.invalidate(targetFences(target));\n },\n async $cacheRawWrite<T>(target: InvalidationTarget, run: () => Promise<T>): Promise<T> {\n const fences = targetFences(target);\n return enabled ? withLease(fences, run) : run();\n },\n },\n name: \"dee-wan-cache\",\n query: {\n $allModels: {\n $allOperations(params: OperationParams): Promise<unknown> {\n const { args, model, operation, query } = params;\n if (!model) return query(args);\n const { dataPath, inBatch } = internalParams(params);\n if (READ_OPERATIONS.has(operation) && isCacheable(model) && !inBatch) {\n return handleRead(model, operation, args, query, dataPath);\n }\n if (WRITE_OPERATIONS.has(operation) && enabled) {\n return withLease(planFences(planWrite(config, model, operation, args)), () => query(args));\n }\n return query(args);\n },\n },\n },\n };\n}\n"]}
|