kitcn 0.0.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/intent.js +3 -0
- package/dist/aggregate/index.d.ts +388 -0
- package/dist/aggregate/index.js +37 -0
- package/dist/api-entry-BckXqaLb.js +66 -0
- package/dist/auth/client/index.d.ts +37 -0
- package/dist/auth/client/index.js +217 -0
- package/dist/auth/config/index.d.ts +45 -0
- package/dist/auth/config/index.js +24 -0
- package/dist/auth/generated/index.d.ts +2 -0
- package/dist/auth/generated/index.js +3 -0
- package/dist/auth/http/index.d.ts +64 -0
- package/dist/auth/http/index.js +461 -0
- package/dist/auth/index.d.ts +221 -0
- package/dist/auth/index.js +1398 -0
- package/dist/auth/nextjs/index.d.ts +50 -0
- package/dist/auth/nextjs/index.js +81 -0
- package/dist/auth-store-Cljlmdmi.js +197 -0
- package/dist/builder-CBdG5W6A.js +1974 -0
- package/dist/caller-factory-cTXNvYdz.js +216 -0
- package/dist/cli.mjs +13264 -0
- package/dist/codegen-lF80HSWu.mjs +3416 -0
- package/dist/context-utils-HPC5nXzx.d.ts +17 -0
- package/dist/create-schema-odyF4kCy.js +156 -0
- package/dist/create-schema-orm-DOyiNDCx.js +246 -0
- package/dist/crpc/index.d.ts +105 -0
- package/dist/crpc/index.js +169 -0
- package/dist/customFunctions-C0voKmtx.js +144 -0
- package/dist/error-BZEnI7Sq.js +41 -0
- package/dist/generated-contract-disabled-Cih4eITO.js +50 -0
- package/dist/generated-contract-disabled-D-sOFy92.d.ts +354 -0
- package/dist/http-types-DqJubRPJ.d.ts +292 -0
- package/dist/meta-utils-0Pu0Nrap.js +117 -0
- package/dist/middleware-BUybuv9n.d.ts +34 -0
- package/dist/middleware-C2qTZ3V7.js +84 -0
- package/dist/orm/index.d.ts +17 -0
- package/dist/orm/index.js +10713 -0
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/index.js +3 -0
- package/dist/procedure-caller-DtxLmGwA.d.ts +1467 -0
- package/dist/procedure-caller-MWcxhQDv.js +349 -0
- package/dist/query-context-B8o6-8kC.js +1518 -0
- package/dist/query-context-CFZqIvD7.d.ts +42 -0
- package/dist/query-options-Dw7cOyXl.js +121 -0
- package/dist/ratelimit/index.d.ts +269 -0
- package/dist/ratelimit/index.js +856 -0
- package/dist/ratelimit/react/index.d.ts +76 -0
- package/dist/ratelimit/react/index.js +183 -0
- package/dist/react/index.d.ts +1284 -0
- package/dist/react/index.js +2526 -0
- package/dist/rsc/index.d.ts +276 -0
- package/dist/rsc/index.js +233 -0
- package/dist/runtime-CtvJPkur.js +2453 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +6 -0
- package/dist/solid/index.d.ts +1221 -0
- package/dist/solid/index.js +2940 -0
- package/dist/transformer-DtDhR3Lc.js +194 -0
- package/dist/types-BTb_4BaU.d.ts +42 -0
- package/dist/types-BiJE7qxR.d.ts +4 -0
- package/dist/types-DEJpkIhw.d.ts +88 -0
- package/dist/types-HhO_R6pd.d.ts +213 -0
- package/dist/validators-B7oIJCAp.js +279 -0
- package/dist/validators-vzRKjBJC.d.ts +88 -0
- package/dist/watcher.mjs +96 -0
- package/dist/where-clause-compiler-DdjN63Io.d.ts +4756 -0
- package/package.json +107 -34
- package/skills/convex/SKILL.md +486 -0
- package/skills/convex/references/features/aggregates.md +353 -0
- package/skills/convex/references/features/auth-admin.md +446 -0
- package/skills/convex/references/features/auth-organizations.md +1141 -0
- package/skills/convex/references/features/auth-polar.md +579 -0
- package/skills/convex/references/features/auth.md +470 -0
- package/skills/convex/references/features/create-plugins.md +153 -0
- package/skills/convex/references/features/http.md +676 -0
- package/skills/convex/references/features/migrations.md +162 -0
- package/skills/convex/references/features/orm.md +1166 -0
- package/skills/convex/references/features/react.md +657 -0
- package/skills/convex/references/features/scheduling.md +267 -0
- package/skills/convex/references/features/testing.md +209 -0
- package/skills/convex/references/setup/auth.md +501 -0
- package/skills/convex/references/setup/biome.md +190 -0
- package/skills/convex/references/setup/doc-guidelines.md +145 -0
- package/skills/convex/references/setup/index.md +761 -0
- package/skills/convex/references/setup/next.md +116 -0
- package/skills/convex/references/setup/react.md +175 -0
- package/skills/convex/references/setup/server.md +473 -0
- package/skills/convex/references/setup/start.md +67 -0
- package/LICENSE +0 -21
- package/README.md +0 -0
- package/dist/index.d.mts +0 -5
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -6
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { FunctionReference } from "convex/server";
|
|
3
|
+
|
|
4
|
+
//#region src/ratelimit/types.d.ts
|
|
5
|
+
type RatelimitSnapshot = {
|
|
6
|
+
value: number;
|
|
7
|
+
ts: number;
|
|
8
|
+
shard: number;
|
|
9
|
+
config: ResolvedAlgorithm;
|
|
10
|
+
};
|
|
11
|
+
type FixedWindowAlgorithm = {
|
|
12
|
+
kind: 'fixedWindow';
|
|
13
|
+
limit: number;
|
|
14
|
+
window: number;
|
|
15
|
+
capacity: number;
|
|
16
|
+
start?: number;
|
|
17
|
+
maxReserved?: number;
|
|
18
|
+
shards: number;
|
|
19
|
+
};
|
|
20
|
+
type SlidingWindowAlgorithm = {
|
|
21
|
+
kind: 'slidingWindow';
|
|
22
|
+
limit: number;
|
|
23
|
+
window: number;
|
|
24
|
+
maxReserved?: number;
|
|
25
|
+
shards: number;
|
|
26
|
+
};
|
|
27
|
+
type TokenBucketAlgorithm = {
|
|
28
|
+
kind: 'tokenBucket';
|
|
29
|
+
refillRate: number;
|
|
30
|
+
interval: number;
|
|
31
|
+
maxTokens: number;
|
|
32
|
+
maxReserved?: number;
|
|
33
|
+
shards: number;
|
|
34
|
+
};
|
|
35
|
+
type ResolvedAlgorithm = FixedWindowAlgorithm | SlidingWindowAlgorithm | TokenBucketAlgorithm;
|
|
36
|
+
type HookCheckValue = {
|
|
37
|
+
value: number;
|
|
38
|
+
ts: number;
|
|
39
|
+
config: ResolvedAlgorithm;
|
|
40
|
+
shard: number;
|
|
41
|
+
ok: boolean;
|
|
42
|
+
retryAt?: number;
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/ratelimit/react/use-rate-limit.d.ts
|
|
46
|
+
type GetRatelimitValueQueryRef = FunctionReference<'query', 'public', {
|
|
47
|
+
identifier?: string;
|
|
48
|
+
sampleShards?: number;
|
|
49
|
+
}, RatelimitSnapshot>;
|
|
50
|
+
type GetServerTimeMutationRef = FunctionReference<'mutation', 'public', Record<string, never>, number>;
|
|
51
|
+
type GetRatelimitValueQuery = GetRatelimitValueQueryRef | string;
|
|
52
|
+
type GetServerTimeMutation = GetServerTimeMutationRef | string;
|
|
53
|
+
type UseRatelimitOptions = {
|
|
54
|
+
identifier?: string;
|
|
55
|
+
count?: number;
|
|
56
|
+
sampleShards?: number;
|
|
57
|
+
getServerTimeMutation?: GetServerTimeMutation;
|
|
58
|
+
};
|
|
59
|
+
declare function useRatelimit(getRatelimitValueQuery: GetRatelimitValueQuery, options?: UseRatelimitOptions): {
|
|
60
|
+
status: undefined;
|
|
61
|
+
check: (ts?: number, requestedCount?: number) => HookCheckValue | undefined;
|
|
62
|
+
} | {
|
|
63
|
+
status: {
|
|
64
|
+
ok: false;
|
|
65
|
+
retryAt: number;
|
|
66
|
+
};
|
|
67
|
+
check: (ts?: number, requestedCount?: number) => HookCheckValue | undefined;
|
|
68
|
+
} | {
|
|
69
|
+
status: {
|
|
70
|
+
ok: true;
|
|
71
|
+
retryAt: undefined;
|
|
72
|
+
};
|
|
73
|
+
check: (ts?: number, requestedCount?: number) => HookCheckValue | undefined;
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { GetRatelimitValueQuery, GetRatelimitValueQueryRef, GetServerTimeMutation, GetServerTimeMutationRef, UseRatelimitOptions, useRatelimit };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useConvex, useQuery } from "convex/react";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { makeFunctionReference } from "convex/server";
|
|
5
|
+
|
|
6
|
+
//#region src/ratelimit/core/calculate-rate-limit.ts
|
|
7
|
+
function calculateRatelimit(state, algorithm, now, count) {
|
|
8
|
+
if (algorithm.kind === "fixedWindow") return calculateFixedWindow(state, algorithm, now, count);
|
|
9
|
+
if (algorithm.kind === "tokenBucket") return calculateTokenBucket(state, algorithm, now, count);
|
|
10
|
+
return calculateSlidingWindow(state, algorithm, now, count);
|
|
11
|
+
}
|
|
12
|
+
function calculateTokenBucket(state, config, now, count) {
|
|
13
|
+
const ratePerMs = config.refillRate / config.interval;
|
|
14
|
+
const initial = state ?? {
|
|
15
|
+
value: config.maxTokens,
|
|
16
|
+
ts: now
|
|
17
|
+
};
|
|
18
|
+
const elapsed = Math.max(0, now - initial.ts);
|
|
19
|
+
const nextValue = Math.min(initial.value + elapsed * ratePerMs, config.maxTokens) - count;
|
|
20
|
+
const retryAfter = nextValue < 0 ? Math.ceil(-nextValue / ratePerMs) : void 0;
|
|
21
|
+
return {
|
|
22
|
+
state: {
|
|
23
|
+
value: nextValue,
|
|
24
|
+
ts: now
|
|
25
|
+
},
|
|
26
|
+
retryAfter,
|
|
27
|
+
remaining: Math.max(0, Math.floor(nextValue)),
|
|
28
|
+
reset: retryAfter ? now + retryAfter : now,
|
|
29
|
+
limit: config.maxTokens
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function calculateFixedWindow(state, config, now, count) {
|
|
33
|
+
const windowStart = alignWindowStart(now, config.window, config.start);
|
|
34
|
+
const initial = state ?? {
|
|
35
|
+
value: config.capacity,
|
|
36
|
+
ts: windowStart
|
|
37
|
+
};
|
|
38
|
+
const elapsedWindows = Math.max(0, Math.floor((now - initial.ts) / config.window));
|
|
39
|
+
const replenished = Math.min(initial.value + config.limit * elapsedWindows, config.capacity);
|
|
40
|
+
const ts = initial.ts + elapsedWindows * config.window;
|
|
41
|
+
const nextValue = replenished - count;
|
|
42
|
+
const retryAfter = nextValue < 0 ? ts + config.window * Math.ceil(-nextValue / config.limit) - now : void 0;
|
|
43
|
+
return {
|
|
44
|
+
state: {
|
|
45
|
+
value: nextValue,
|
|
46
|
+
ts
|
|
47
|
+
},
|
|
48
|
+
retryAfter,
|
|
49
|
+
remaining: Math.max(0, Math.floor(nextValue)),
|
|
50
|
+
reset: ts + config.window,
|
|
51
|
+
limit: config.limit
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function calculateSlidingWindow(state, config, now, count) {
|
|
55
|
+
const windowStart = alignWindowStart(now, config.window);
|
|
56
|
+
const previousWindowStart = windowStart - config.window;
|
|
57
|
+
const elapsedInWindow = now - windowStart;
|
|
58
|
+
const previousWeight = Math.max(0, (config.window - elapsedInWindow) / config.window);
|
|
59
|
+
let currentCount = 0;
|
|
60
|
+
let previousCount = 0;
|
|
61
|
+
if (state) {
|
|
62
|
+
if (state.ts === windowStart) {
|
|
63
|
+
currentCount = Math.max(0, state.value);
|
|
64
|
+
if (state.auxTs === previousWindowStart) previousCount = Math.max(0, state.auxValue ?? 0);
|
|
65
|
+
} else if (state.ts === previousWindowStart) previousCount = Math.max(0, state.value);
|
|
66
|
+
}
|
|
67
|
+
const projectedCurrent = currentCount + count;
|
|
68
|
+
const projectedUsed = projectedCurrent + previousCount * previousWeight;
|
|
69
|
+
const remaining = config.limit - projectedUsed;
|
|
70
|
+
const retryAfter = remaining < 0 ? Math.max(1, config.window - elapsedInWindow) : void 0;
|
|
71
|
+
return {
|
|
72
|
+
state: {
|
|
73
|
+
value: projectedCurrent,
|
|
74
|
+
ts: windowStart,
|
|
75
|
+
auxValue: previousCount,
|
|
76
|
+
auxTs: previousWindowStart
|
|
77
|
+
},
|
|
78
|
+
retryAfter,
|
|
79
|
+
remaining: Math.max(0, Math.floor(remaining)),
|
|
80
|
+
reset: windowStart + config.window,
|
|
81
|
+
limit: config.limit
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function alignWindowStart(now, window, start = 0) {
|
|
85
|
+
const offsetNow = now - start;
|
|
86
|
+
return start + Math.floor(offsetNow / window) * window;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/ratelimit/react/use-rate-limit.ts
|
|
91
|
+
function useRatelimit(getRatelimitValueQuery, options) {
|
|
92
|
+
const [timeOffset, setTimeOffset] = useState(0);
|
|
93
|
+
const [now, setNow] = useState(() => Date.now());
|
|
94
|
+
const convex = useConvex();
|
|
95
|
+
const getRatelimitValueQueryRef = useMemo(() => resolveGetRatelimitValueQuery(getRatelimitValueQuery), [getRatelimitValueQuery]);
|
|
96
|
+
const { getServerTimeMutation, count, identifier, sampleShards } = options ?? {};
|
|
97
|
+
const getServerTimeMutationRef = useMemo(() => getServerTimeMutation ? resolveGetServerTimeMutation(getServerTimeMutation) : void 0, [getServerTimeMutation]);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (!getServerTimeMutationRef) return;
|
|
100
|
+
const clientTime = Date.now();
|
|
101
|
+
convex.mutation(getServerTimeMutationRef, {}).then((serverTime) => {
|
|
102
|
+
const latency = Date.now() - clientTime;
|
|
103
|
+
setTimeOffset(serverTime - clientTime - latency / 2);
|
|
104
|
+
});
|
|
105
|
+
}, [convex, getServerTimeMutationRef]);
|
|
106
|
+
const ratelimitData = useQuery(getRatelimitValueQueryRef, {
|
|
107
|
+
identifier,
|
|
108
|
+
sampleShards
|
|
109
|
+
});
|
|
110
|
+
const check = useCallback((ts, requestedCount) => {
|
|
111
|
+
if (!ratelimitData) return;
|
|
112
|
+
const serverTs = (ts ?? Date.now()) + timeOffset;
|
|
113
|
+
const evaluation = evaluateSnapshot(ratelimitData, serverTs, requestedCount ?? count ?? 1);
|
|
114
|
+
return {
|
|
115
|
+
value: evaluation.value,
|
|
116
|
+
ts: evaluation.ts - timeOffset,
|
|
117
|
+
config: ratelimitData.config,
|
|
118
|
+
shard: ratelimitData.shard,
|
|
119
|
+
ok: evaluation.value >= 0,
|
|
120
|
+
retryAt: evaluation.retryAfter ? serverTs + evaluation.retryAfter - timeOffset : void 0
|
|
121
|
+
};
|
|
122
|
+
}, [
|
|
123
|
+
count,
|
|
124
|
+
ratelimitData,
|
|
125
|
+
timeOffset
|
|
126
|
+
]);
|
|
127
|
+
const current = check(now, count ?? 1);
|
|
128
|
+
const response = useMemo(() => {
|
|
129
|
+
if (!current) return {
|
|
130
|
+
status: void 0,
|
|
131
|
+
check
|
|
132
|
+
};
|
|
133
|
+
if (current.value < 0) return {
|
|
134
|
+
status: {
|
|
135
|
+
ok: false,
|
|
136
|
+
retryAt: current.retryAt
|
|
137
|
+
},
|
|
138
|
+
check
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
status: {
|
|
142
|
+
ok: true,
|
|
143
|
+
retryAt: void 0
|
|
144
|
+
},
|
|
145
|
+
check
|
|
146
|
+
};
|
|
147
|
+
}, [check, current]);
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
if (response.status?.ok !== false || !response.status.retryAt) return;
|
|
150
|
+
const timeout = setTimeout(() => setNow(Date.now()), Math.max(0, response.status.retryAt - now));
|
|
151
|
+
return () => clearTimeout(timeout);
|
|
152
|
+
}, [
|
|
153
|
+
now,
|
|
154
|
+
response.status?.ok,
|
|
155
|
+
response.status?.retryAt
|
|
156
|
+
]);
|
|
157
|
+
return response;
|
|
158
|
+
}
|
|
159
|
+
function resolveGetRatelimitValueQuery(ref) {
|
|
160
|
+
if (typeof ref === "string") return makeFunctionReference(ref);
|
|
161
|
+
return ref;
|
|
162
|
+
}
|
|
163
|
+
function resolveGetServerTimeMutation(ref) {
|
|
164
|
+
if (typeof ref === "string") return makeFunctionReference(ref);
|
|
165
|
+
return ref;
|
|
166
|
+
}
|
|
167
|
+
function evaluateSnapshot(snapshot, now, count) {
|
|
168
|
+
const evaluated = calculateRatelimit(snapshot.config.kind === "slidingWindow" ? {
|
|
169
|
+
value: Math.max(0, snapshot.config.limit - snapshot.value),
|
|
170
|
+
ts: snapshot.ts
|
|
171
|
+
} : {
|
|
172
|
+
value: snapshot.value,
|
|
173
|
+
ts: snapshot.ts
|
|
174
|
+
}, snapshot.config, now, count);
|
|
175
|
+
return {
|
|
176
|
+
value: snapshot.config.kind === "slidingWindow" ? evaluated.retryAfter !== void 0 ? -1 : evaluated.remaining : evaluated.state.value,
|
|
177
|
+
ts: evaluated.state.ts,
|
|
178
|
+
retryAfter: evaluated.retryAfter
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
//#endregion
|
|
183
|
+
export { useRatelimit };
|