@convex-dev/crons 0.0.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/LICENSE +202 -0
- package/README.md +56 -0
- package/dist/commonjs/client/index.d.ts +50 -0
- package/dist/commonjs/client/index.d.ts.map +1 -0
- package/dist/commonjs/client/index.js +99 -0
- package/dist/commonjs/client/index.js.map +1 -0
- package/dist/commonjs/client/utils.d.ts +15 -0
- package/dist/commonjs/client/utils.d.ts.map +1 -0
- package/dist/commonjs/client/utils.js +3 -0
- package/dist/commonjs/client/utils.js.map +1 -0
- package/dist/commonjs/component/_generated/api.d.ts +14 -0
- package/dist/commonjs/component/_generated/api.d.ts.map +1 -0
- package/dist/commonjs/component/_generated/api.js +24 -0
- package/dist/commonjs/component/_generated/api.js.map +1 -0
- package/dist/commonjs/component/_generated/server.d.ts +64 -0
- package/dist/commonjs/component/_generated/server.d.ts.map +1 -0
- package/dist/commonjs/component/_generated/server.js +76 -0
- package/dist/commonjs/component/_generated/server.js.map +1 -0
- package/dist/commonjs/component/convex.config.d.ts +3 -0
- package/dist/commonjs/component/convex.config.d.ts.map +1 -0
- package/dist/commonjs/component/convex.config.js +3 -0
- package/dist/commonjs/component/convex.config.js.map +1 -0
- package/dist/commonjs/component/index.d.ts +135 -0
- package/dist/commonjs/component/index.d.ts.map +1 -0
- package/dist/commonjs/component/index.js +289 -0
- package/dist/commonjs/component/index.js.map +1 -0
- package/dist/commonjs/component/parseArgs.d.ts +11 -0
- package/dist/commonjs/component/parseArgs.d.ts.map +1 -0
- package/dist/commonjs/component/parseArgs.js +28 -0
- package/dist/commonjs/component/parseArgs.js.map +1 -0
- package/dist/commonjs/component/public.d.ts +98 -0
- package/dist/commonjs/component/public.d.ts.map +1 -0
- package/dist/commonjs/component/public.js +225 -0
- package/dist/commonjs/component/public.js.map +1 -0
- package/dist/commonjs/component/schema.d.ts +45 -0
- package/dist/commonjs/component/schema.d.ts.map +1 -0
- package/dist/commonjs/component/schema.js +20 -0
- package/dist/commonjs/component/schema.js.map +1 -0
- package/dist/commonjs/frontend/index.d.ts +2 -0
- package/dist/commonjs/frontend/index.d.ts.map +1 -0
- package/dist/commonjs/frontend/index.js +8 -0
- package/dist/commonjs/frontend/index.js.map +1 -0
- package/dist/esm/client/index.d.ts +50 -0
- package/dist/esm/client/index.d.ts.map +1 -0
- package/dist/esm/client/index.js +99 -0
- package/dist/esm/client/index.js.map +1 -0
- package/dist/esm/client/utils.d.ts +15 -0
- package/dist/esm/client/utils.d.ts.map +1 -0
- package/dist/esm/client/utils.js +3 -0
- package/dist/esm/client/utils.js.map +1 -0
- package/dist/esm/component/_generated/api.d.ts +14 -0
- package/dist/esm/component/_generated/api.d.ts.map +1 -0
- package/dist/esm/component/_generated/api.js +24 -0
- package/dist/esm/component/_generated/api.js.map +1 -0
- package/dist/esm/component/_generated/server.d.ts +64 -0
- package/dist/esm/component/_generated/server.d.ts.map +1 -0
- package/dist/esm/component/_generated/server.js +76 -0
- package/dist/esm/component/_generated/server.js.map +1 -0
- package/dist/esm/component/convex.config.d.ts +3 -0
- package/dist/esm/component/convex.config.d.ts.map +1 -0
- package/dist/esm/component/convex.config.js +3 -0
- package/dist/esm/component/convex.config.js.map +1 -0
- package/dist/esm/component/index.d.ts +135 -0
- package/dist/esm/component/index.d.ts.map +1 -0
- package/dist/esm/component/index.js +289 -0
- package/dist/esm/component/index.js.map +1 -0
- package/dist/esm/component/parseArgs.d.ts +11 -0
- package/dist/esm/component/parseArgs.d.ts.map +1 -0
- package/dist/esm/component/parseArgs.js +28 -0
- package/dist/esm/component/parseArgs.js.map +1 -0
- package/dist/esm/component/public.d.ts +98 -0
- package/dist/esm/component/public.d.ts.map +1 -0
- package/dist/esm/component/public.js +225 -0
- package/dist/esm/component/public.js.map +1 -0
- package/dist/esm/component/schema.d.ts +45 -0
- package/dist/esm/component/schema.d.ts.map +1 -0
- package/dist/esm/component/schema.js +20 -0
- package/dist/esm/component/schema.js.map +1 -0
- package/dist/esm/frontend/index.d.ts +2 -0
- package/dist/esm/frontend/index.d.ts.map +1 -0
- package/dist/esm/frontend/index.js +8 -0
- package/dist/esm/frontend/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/package.json +56 -0
- package/src/client/index.ts +128 -0
- package/src/client/utils.ts +44 -0
- package/src/component/_generated/api.d.ts +98 -0
- package/src/component/_generated/api.js +27 -0
- package/src/component/_generated/dataModel.d.ts +64 -0
- package/src/component/_generated/server.d.ts +153 -0
- package/src/component/_generated/server.js +94 -0
- package/src/component/convex.config.ts +3 -0
- package/src/component/public.ts +287 -0
- package/src/component/schema.ts +23 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// Implementation of crons in user space.
|
|
2
|
+
//
|
|
3
|
+
// See ../client/index.ts for the public API.
|
|
4
|
+
import { v } from "convex/values";
|
|
5
|
+
import { mutation, query, internalMutation, } from "./_generated/server.js";
|
|
6
|
+
import { internal } from "./_generated/api.js";
|
|
7
|
+
import parser from "cron-parser";
|
|
8
|
+
import schema from "./schema.js";
|
|
9
|
+
const scheduleValidator = schema.tables.crons.validator.fields.schedule;
|
|
10
|
+
const cronInfoValidator = v.object({
|
|
11
|
+
id: v.id("crons"),
|
|
12
|
+
name: v.optional(v.string()),
|
|
13
|
+
functionHandle: v.string(),
|
|
14
|
+
args: v.record(v.string(), v.any()),
|
|
15
|
+
schedule: scheduleValidator,
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Schedule a mutation or action to run on a cron schedule or interval.
|
|
19
|
+
*
|
|
20
|
+
* @param name - Optional unique name for the job. Will throw if a name is
|
|
21
|
+
* provided and a job with the same name already exists.
|
|
22
|
+
* @param schedule - Either a cron specification string or an interval in
|
|
23
|
+
* milliseconds. For intervals, ms must be >= 1000.
|
|
24
|
+
* @param functionHandle - A {@link FunctionHandle} string for the function to
|
|
25
|
+
* schedule.
|
|
26
|
+
* @param args - The arguments to the function.
|
|
27
|
+
* @returns The ID of the scheduled job.
|
|
28
|
+
*/
|
|
29
|
+
export const register = mutation({
|
|
30
|
+
args: {
|
|
31
|
+
name: v.optional(v.string()),
|
|
32
|
+
schedule: scheduleValidator,
|
|
33
|
+
functionHandle: v.string(),
|
|
34
|
+
args: v.record(v.string(), v.any()),
|
|
35
|
+
},
|
|
36
|
+
returns: v.id("crons"),
|
|
37
|
+
handler: async (ctx, { name, schedule, functionHandle, args }) => {
|
|
38
|
+
if (name &&
|
|
39
|
+
(await ctx.db
|
|
40
|
+
.query("crons")
|
|
41
|
+
.withIndex("name", (q) => q.eq("name", name))
|
|
42
|
+
.unique())) {
|
|
43
|
+
throw new Error(`Cron with name "${name}" already exists`);
|
|
44
|
+
}
|
|
45
|
+
validateSchedule(schedule);
|
|
46
|
+
const id = await ctx.db.insert("crons", {
|
|
47
|
+
functionHandle,
|
|
48
|
+
args,
|
|
49
|
+
name,
|
|
50
|
+
schedule,
|
|
51
|
+
});
|
|
52
|
+
console.log(`Scheduling cron "${name}" (${id}) on schedule ${JSON.stringify(schedule)}`);
|
|
53
|
+
await scheduleNextRun(ctx, id, new Date(), schedule);
|
|
54
|
+
return id;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
function validateSchedule(schedule) {
|
|
58
|
+
if (schedule.kind === "interval" && schedule.ms < 1000) {
|
|
59
|
+
throw new Error("Interval must be >= 1000ms");
|
|
60
|
+
}
|
|
61
|
+
if (schedule.kind === "cron") {
|
|
62
|
+
try {
|
|
63
|
+
parser.parseExpression(schedule.cronspec);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
throw new Error(`Invalid cronspec: "${schedule.cronspec}"`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function scheduleNextRun(ctx, id, lastScheduled, schedule) {
|
|
71
|
+
const nextRun = calculateNextRun(lastScheduled, schedule);
|
|
72
|
+
const schedulerJobId = await ctx.scheduler.runAt(nextRun, internal.public.rescheduler, { id });
|
|
73
|
+
await ctx.db.patch(id, { schedulerJobId });
|
|
74
|
+
}
|
|
75
|
+
function calculateNextRun(lastScheduled, schedule) {
|
|
76
|
+
if (schedule.kind === "interval") {
|
|
77
|
+
return new Date(lastScheduled.getTime() + schedule.ms);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const cron = parser.parseExpression(schedule.cronspec, {
|
|
81
|
+
currentDate: lastScheduled,
|
|
82
|
+
});
|
|
83
|
+
return cron.next().toDate();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* List all user space cron jobs.
|
|
88
|
+
*
|
|
89
|
+
* @returns List of `cron` table rows.
|
|
90
|
+
*/
|
|
91
|
+
export const list = query({
|
|
92
|
+
args: {},
|
|
93
|
+
returns: v.array(cronInfoValidator),
|
|
94
|
+
handler: async (ctx) => {
|
|
95
|
+
const crons = await ctx.db.query("crons").collect();
|
|
96
|
+
return crons.map((cron) => ({
|
|
97
|
+
id: cron._id,
|
|
98
|
+
...(cron.name && { name: cron.name }),
|
|
99
|
+
functionHandle: cron.functionHandle,
|
|
100
|
+
args: cron.args,
|
|
101
|
+
schedule: cron.schedule,
|
|
102
|
+
}));
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
/**
|
|
106
|
+
* Get an existing cron job by id or name.
|
|
107
|
+
*
|
|
108
|
+
* @param identifier - Either the ID or name of the cron job.
|
|
109
|
+
* @returns Cron job document or null if not found.
|
|
110
|
+
*/
|
|
111
|
+
export const get = query({
|
|
112
|
+
args: {
|
|
113
|
+
identifier: v.union(v.object({ id: v.id("crons") }), v.object({ name: v.string() })),
|
|
114
|
+
},
|
|
115
|
+
returns: v.union(cronInfoValidator, v.null()),
|
|
116
|
+
handler: async (ctx, { identifier }) => {
|
|
117
|
+
const cron = "id" in identifier
|
|
118
|
+
? await ctx.db.get(identifier.id)
|
|
119
|
+
: await ctx.db
|
|
120
|
+
.query("crons")
|
|
121
|
+
.withIndex("name", (q) => q.eq("name", identifier.name))
|
|
122
|
+
.unique();
|
|
123
|
+
if (!cron)
|
|
124
|
+
return null;
|
|
125
|
+
return {
|
|
126
|
+
id: cron._id,
|
|
127
|
+
...(cron.name && { name: cron.name }),
|
|
128
|
+
functionHandle: cron.functionHandle,
|
|
129
|
+
args: cron.args,
|
|
130
|
+
schedule: cron.schedule,
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* Delete and deschedule a cron job by id or name.
|
|
136
|
+
*
|
|
137
|
+
* @param identifier - Either the ID or name of the cron job.
|
|
138
|
+
*/
|
|
139
|
+
export const del = mutation({
|
|
140
|
+
args: {
|
|
141
|
+
identifier: v.union(v.object({ id: v.id("crons") }), v.object({ name: v.string() })),
|
|
142
|
+
},
|
|
143
|
+
returns: v.null(),
|
|
144
|
+
handler: async (ctx, { identifier }) => {
|
|
145
|
+
let cron;
|
|
146
|
+
if ("id" in identifier) {
|
|
147
|
+
cron = await ctx.db.get(identifier.id);
|
|
148
|
+
if (!cron) {
|
|
149
|
+
throw new Error(`Cron ${identifier.id} not found`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
cron = await ctx.db
|
|
154
|
+
.query("crons")
|
|
155
|
+
.withIndex("name", (q) => q.eq("name", identifier.name))
|
|
156
|
+
.unique();
|
|
157
|
+
if (!cron) {
|
|
158
|
+
throw new Error(`Cron "${identifier.name}" not found`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (!cron.schedulerJobId) {
|
|
162
|
+
throw new Error(`Cron ${cron._id} not scheduled`);
|
|
163
|
+
}
|
|
164
|
+
console.log(`Canceling scheduler job ${cron.schedulerJobId}`);
|
|
165
|
+
await ctx.scheduler.cancel(cron.schedulerJobId);
|
|
166
|
+
if (cron.executionJobId) {
|
|
167
|
+
console.log(`Canceling execution job ${cron.executionJobId}`);
|
|
168
|
+
await ctx.scheduler.cancel(cron.executionJobId);
|
|
169
|
+
}
|
|
170
|
+
console.log(`Deleting cron ${cron._id}`);
|
|
171
|
+
await ctx.db.delete(cron._id);
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
// Continue rescheduling a cron job.
|
|
175
|
+
//
|
|
176
|
+
// This is the main worker function that does the scheduling but also schedules
|
|
177
|
+
// the target function so that it runs in a different context. As a result this
|
|
178
|
+
// function probably *shouldn't* fail since it isn't doing much, but under heavy
|
|
179
|
+
// OCC contention it's possible it may eventually fail. In this case the cron
|
|
180
|
+
// will be lost and we'll need a janitor job to recover it.
|
|
181
|
+
export const rescheduler = internalMutation({
|
|
182
|
+
args: {
|
|
183
|
+
id: v.id("crons"),
|
|
184
|
+
},
|
|
185
|
+
returns: v.null(),
|
|
186
|
+
handler: async (ctx, { id }) => {
|
|
187
|
+
// Cron job is the logical concept we're rescheduling repeatedly.
|
|
188
|
+
const cronJob = await ctx.db.get(id);
|
|
189
|
+
if (!cronJob) {
|
|
190
|
+
throw Error(`Cron ${id} not found`);
|
|
191
|
+
}
|
|
192
|
+
if (!cronJob.schedulerJobId) {
|
|
193
|
+
throw Error(`Cron ${id} not scheduled`);
|
|
194
|
+
}
|
|
195
|
+
// Scheduler job is the job that's running right now, that we use to trigger
|
|
196
|
+
// repeated executions.
|
|
197
|
+
const schedulerJob = await ctx.db.system.get(cronJob.schedulerJobId);
|
|
198
|
+
if (!schedulerJob) {
|
|
199
|
+
throw Error(`Scheduler job ${cronJob.schedulerJobId} not found`);
|
|
200
|
+
}
|
|
201
|
+
if (schedulerJob.state.kind !== "pending" &&
|
|
202
|
+
schedulerJob.state.kind !== "inProgress") {
|
|
203
|
+
throw Error(`We are running in job ${schedulerJob._id} but state is ${schedulerJob.state.kind}`);
|
|
204
|
+
}
|
|
205
|
+
// Execution job is the previous job used to actually do the work of the cron.
|
|
206
|
+
let stillRunning = false;
|
|
207
|
+
if (cronJob.executionJobId) {
|
|
208
|
+
const executionJob = await ctx.db.system.get(cronJob.executionJobId);
|
|
209
|
+
if (executionJob &&
|
|
210
|
+
(executionJob.state.kind === "pending" ||
|
|
211
|
+
executionJob.state.kind === "inProgress")) {
|
|
212
|
+
stillRunning = true;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (stillRunning) {
|
|
216
|
+
console.log(`Cron ${cronJob._id} still running, skipping this run.`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
console.log(`Running cron ${cronJob._id}.`);
|
|
220
|
+
await ctx.scheduler.runAfter(0, cronJob.functionHandle, cronJob.args);
|
|
221
|
+
}
|
|
222
|
+
await scheduleNextRun(ctx, id, new Date(schedulerJob.scheduledTime), cronJob.schedule);
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
//# sourceMappingURL=public.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/component/public.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
declare const _default: import("convex/server").SchemaDefinition<{
|
|
2
|
+
crons: import("convex/server").TableDefinition<import("convex/values").VObject<{
|
|
3
|
+
name?: string | undefined;
|
|
4
|
+
schedulerJobId?: import("convex/values").GenericId<"_scheduled_functions"> | undefined;
|
|
5
|
+
executionJobId?: import("convex/values").GenericId<"_scheduled_functions"> | undefined;
|
|
6
|
+
functionHandle: string;
|
|
7
|
+
args: Record<string, any>;
|
|
8
|
+
schedule: {
|
|
9
|
+
kind: "interval";
|
|
10
|
+
ms: number;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "cron";
|
|
13
|
+
cronspec: string;
|
|
14
|
+
};
|
|
15
|
+
}, {
|
|
16
|
+
name: import("convex/values").VString<string | undefined, "optional">;
|
|
17
|
+
functionHandle: import("convex/values").VString<string, "required">;
|
|
18
|
+
args: import("convex/values").VRecord<Record<string, any>, import("convex/values").VString<string, "required">, import("convex/values").VAny<any, "required", string>, "required", string>;
|
|
19
|
+
schedule: import("convex/values").VUnion<{
|
|
20
|
+
kind: "interval";
|
|
21
|
+
ms: number;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "cron";
|
|
24
|
+
cronspec: string;
|
|
25
|
+
}, [import("convex/values").VObject<{
|
|
26
|
+
kind: "interval";
|
|
27
|
+
ms: number;
|
|
28
|
+
}, {
|
|
29
|
+
kind: import("convex/values").VLiteral<"interval", "required">;
|
|
30
|
+
ms: import("convex/values").VFloat64<number, "required">;
|
|
31
|
+
}, "required", "kind" | "ms">, import("convex/values").VObject<{
|
|
32
|
+
kind: "cron";
|
|
33
|
+
cronspec: string;
|
|
34
|
+
}, {
|
|
35
|
+
kind: import("convex/values").VLiteral<"cron", "required">;
|
|
36
|
+
cronspec: import("convex/values").VString<string, "required">;
|
|
37
|
+
}, "required", "kind" | "cronspec">], "required", "kind" | "ms" | "cronspec">;
|
|
38
|
+
schedulerJobId: import("convex/values").VId<import("convex/values").GenericId<"_scheduled_functions"> | undefined, "optional">;
|
|
39
|
+
executionJobId: import("convex/values").VId<import("convex/values").GenericId<"_scheduled_functions"> | undefined, "optional">;
|
|
40
|
+
}, "required", "name" | "functionHandle" | "args" | "schedule" | "schedulerJobId" | "executionJobId" | `args.${string}` | "schedule.kind" | "schedule.ms" | "schedule.cronspec">, {
|
|
41
|
+
name: ["name", "_creationTime"];
|
|
42
|
+
}, {}, {}>;
|
|
43
|
+
}, true>;
|
|
44
|
+
export default _default;
|
|
45
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/component/schema.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,wBAmBG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineSchema, defineTable } from "convex/server";
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
export default defineSchema({
|
|
4
|
+
// User space crons.
|
|
5
|
+
crons: defineTable({
|
|
6
|
+
name: v.optional(v.string()),
|
|
7
|
+
functionHandle: v.string(),
|
|
8
|
+
args: v.record(v.string(), v.any()),
|
|
9
|
+
schedule: v.union(v.object({
|
|
10
|
+
kind: v.literal("interval"),
|
|
11
|
+
ms: v.float64(), // milliseconds
|
|
12
|
+
}), v.object({
|
|
13
|
+
kind: v.literal("cron"),
|
|
14
|
+
cronspec: v.string(), // "* * * * *"
|
|
15
|
+
})),
|
|
16
|
+
schedulerJobId: v.optional(v.id("_scheduled_functions")),
|
|
17
|
+
executionJobId: v.optional(v.id("_scheduled_functions")), // async job to run the function
|
|
18
|
+
}).index("name", ["name"]),
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/component/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAElC,eAAe,YAAY,CAAC;IAC1B,oBAAoB;IACpB,KAAK,EAAE,WAAW,CAAC;QACjB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC5B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;QAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QACnC,QAAQ,EAAE,CAAC,CAAC,KAAK,CACf,CAAC,CAAC,MAAM,CAAC;YACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;YAC3B,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,eAAe;SACjC,CAAC,EACF,CAAC,CAAC,MAAM,CAAC;YACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;YACvB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,cAAc;SACrC,CAAC,CACH;QACD,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC;QACxD,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,EAAE,gCAAgC;KAC3F,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;CAC3B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/frontend/index.ts"],"names":[],"mappings":"AAKA,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/frontend/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;IACjC,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;CAC5E;AAED,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,CAAS;IAC3C,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { FunctionArgs, SchedulableFunctionReference } from "convex/server";
|
|
2
|
+
import { api } from "../component/_generated/api.js";
|
|
3
|
+
import { CronInfo, Schedule } from "../component/public.js";
|
|
4
|
+
import { RunMutationCtx, RunQueryCtx, UseApi } from "./utils.js";
|
|
5
|
+
export type { CronInfo };
|
|
6
|
+
export declare class Crons {
|
|
7
|
+
private component;
|
|
8
|
+
constructor(component: UseApi<typeof api>);
|
|
9
|
+
/**
|
|
10
|
+
* Schedule a mutation or action to run on a cron schedule or interval.
|
|
11
|
+
*
|
|
12
|
+
* @param ctx - The mutation context from the calling Convex mutation.
|
|
13
|
+
* @param schedule - Either a cron specification string or an interval in
|
|
14
|
+
* milliseconds. For intervals, ms must be >= 1000.
|
|
15
|
+
* @param func - A function reference to the mutation or action to schedule.
|
|
16
|
+
* @param args - The arguments to the function.
|
|
17
|
+
* @param name - Optional unique name for the cron. Will throw if a name is
|
|
18
|
+
* provided and a cron with the same name already exists.
|
|
19
|
+
* @returns A string identifier for the cron job.
|
|
20
|
+
*/
|
|
21
|
+
register<F extends SchedulableFunctionReference>(ctx: RunMutationCtx, schedule: Schedule, func: F, args: FunctionArgs<F>, name?: string): Promise<string>;
|
|
22
|
+
/**
|
|
23
|
+
* List all user space cron jobs.
|
|
24
|
+
*
|
|
25
|
+
* @returns List of `cron` table rows.
|
|
26
|
+
*/
|
|
27
|
+
list(ctx: RunQueryCtx): Promise<CronInfo[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Get an existing cron job by id or name.
|
|
30
|
+
*
|
|
31
|
+
* @param identifier - Either the ID or name of the cron job.
|
|
32
|
+
* @returns Cron job document.
|
|
33
|
+
*/
|
|
34
|
+
get(ctx: RunQueryCtx, identifier: {
|
|
35
|
+
id: string;
|
|
36
|
+
} | {
|
|
37
|
+
name: string;
|
|
38
|
+
}): Promise<CronInfo | null>;
|
|
39
|
+
/**
|
|
40
|
+
* Delete and deschedule a cron job by id or name.
|
|
41
|
+
*
|
|
42
|
+
* @param identifier - Either the ID or name of the cron job.
|
|
43
|
+
*/
|
|
44
|
+
del(ctx: RunMutationCtx, identifier: {
|
|
45
|
+
id: string;
|
|
46
|
+
} | {
|
|
47
|
+
name: string;
|
|
48
|
+
}): Promise<null>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,YAAY,EAEZ,4BAA4B,EAC7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,GAAG,EAAE,MAAM,gCAAgC,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEjE,YAAY,EAAE,QAAQ,EAAE,CAAC;AAqCzB,qBAAa,KAAK;IACJ,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,CAAC,OAAO,GAAG,CAAC;IAEjD;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,CAAC,SAAS,4BAA4B,EACnD,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EACrB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC;IASlB;;;;OAIG;IACG,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAUjD;;;;;OAKG;IACG,GAAG,CACP,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAC5C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAa3B;;;;OAIG;IACG,GAAG,CACP,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAC5C,OAAO,CAAC,IAAI,CAAC;CAGjB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Client side implementation of the Crons component.
|
|
2
|
+
import { createFunctionHandle, } from "convex/server";
|
|
3
|
+
// TODO (james): should we add helpers for minutely, hourly, etc schedules?
|
|
4
|
+
// Implementation of crons in user space.
|
|
5
|
+
//
|
|
6
|
+
// Supports intervals in ms as well as cron schedules with the same format as
|
|
7
|
+
// the unix `cron` command:
|
|
8
|
+
//
|
|
9
|
+
// * * * * * *
|
|
10
|
+
// ┬ ┬ ┬ ┬ ┬ ┬
|
|
11
|
+
// │ │ │ │ │ |
|
|
12
|
+
// │ │ │ │ │ └── day of week (0 - 7, 1L - 7L) (0 or 7 is Sun)
|
|
13
|
+
// │ │ │ │ └───── month (1 - 12)
|
|
14
|
+
// │ │ │ └──────── day of month (1 - 31, L)
|
|
15
|
+
// │ │ └─────────── hour (0 - 23)
|
|
16
|
+
// │ └────────────── minute (0 - 59)
|
|
17
|
+
// └───────────────── second (0 - 59, optional)
|
|
18
|
+
//
|
|
19
|
+
// Crons can be registered at runtime via the `register` function.
|
|
20
|
+
//
|
|
21
|
+
// If you'd like to statically define cronjobs like in the built-in `crons.ts`
|
|
22
|
+
// Convex feature you can do so via an init script that idempotently registers a
|
|
23
|
+
// cron with a given name. e.g., in an `init.ts` file that gets run on every
|
|
24
|
+
// deploy via `convex dev --run init`:
|
|
25
|
+
//
|
|
26
|
+
// const crons = new Crons(components.crons);
|
|
27
|
+
// ...
|
|
28
|
+
// if ((await crons.get(ctx, { name: "daily" })) === null) {
|
|
29
|
+
// await crons.register(
|
|
30
|
+
// ctx,
|
|
31
|
+
// { kind: "cron", cronspec: "0 0 * * *" },
|
|
32
|
+
// internal.example.logStuff,
|
|
33
|
+
// { message: "daily cron" },
|
|
34
|
+
// "daily"
|
|
35
|
+
// );
|
|
36
|
+
// }
|
|
37
|
+
export class Crons {
|
|
38
|
+
component;
|
|
39
|
+
constructor(component) {
|
|
40
|
+
this.component = component;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Schedule a mutation or action to run on a cron schedule or interval.
|
|
44
|
+
*
|
|
45
|
+
* @param ctx - The mutation context from the calling Convex mutation.
|
|
46
|
+
* @param schedule - Either a cron specification string or an interval in
|
|
47
|
+
* milliseconds. For intervals, ms must be >= 1000.
|
|
48
|
+
* @param func - A function reference to the mutation or action to schedule.
|
|
49
|
+
* @param args - The arguments to the function.
|
|
50
|
+
* @param name - Optional unique name for the cron. Will throw if a name is
|
|
51
|
+
* provided and a cron with the same name already exists.
|
|
52
|
+
* @returns A string identifier for the cron job.
|
|
53
|
+
*/
|
|
54
|
+
async register(ctx, schedule, func, args, name) {
|
|
55
|
+
return ctx.runMutation(this.component.public.register, {
|
|
56
|
+
name,
|
|
57
|
+
schedule,
|
|
58
|
+
functionHandle: await createFunctionHandle(func),
|
|
59
|
+
args,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* List all user space cron jobs.
|
|
64
|
+
*
|
|
65
|
+
* @returns List of `cron` table rows.
|
|
66
|
+
*/
|
|
67
|
+
async list(ctx) {
|
|
68
|
+
const crons = await ctx.runQuery(this.component.public.list, {});
|
|
69
|
+
return crons.map((cron) => ({
|
|
70
|
+
...cron,
|
|
71
|
+
functionHandle: cron.functionHandle,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get an existing cron job by id or name.
|
|
76
|
+
*
|
|
77
|
+
* @param identifier - Either the ID or name of the cron job.
|
|
78
|
+
* @returns Cron job document.
|
|
79
|
+
*/
|
|
80
|
+
async get(ctx, identifier) {
|
|
81
|
+
const cron = await ctx.runQuery(this.component.public.get, { identifier });
|
|
82
|
+
if (cron === null) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
...cron,
|
|
87
|
+
functionHandle: cron.functionHandle,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Delete and deschedule a cron job by id or name.
|
|
92
|
+
*
|
|
93
|
+
* @param identifier - Either the ID or name of the cron job.
|
|
94
|
+
*/
|
|
95
|
+
async del(ctx, identifier) {
|
|
96
|
+
return ctx.runMutation(this.component.public.del, { identifier });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAErD,OAAO,EACL,oBAAoB,GAIrB,MAAM,eAAe,CAAC;AAOvB,2EAA2E;AAE3E,yCAAyC;AACzC,EAAE;AACF,6EAA6E;AAC7E,2BAA2B;AAC3B,EAAE;AACF,oBAAoB;AACpB,oBAAoB;AACpB,oBAAoB;AACpB,mEAAmE;AACnE,qCAAqC;AACrC,+CAA+C;AAC/C,oCAAoC;AACpC,sCAAsC;AACtC,gDAAgD;AAChD,EAAE;AACF,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,4EAA4E;AAC5E,sCAAsC;AACtC,EAAE;AACF,6CAA6C;AAC7C,MAAM;AACN,4DAA4D;AAC5D,0BAA0B;AAC1B,WAAW;AACX,+CAA+C;AAC/C,iCAAiC;AACjC,iCAAiC;AACjC,cAAc;AACd,OAAO;AACP,IAAI;AACJ,MAAM,OAAO,KAAK;IACI;IAApB,YAAoB,SAA6B;QAA7B,cAAS,GAAT,SAAS,CAAoB;IAAG,CAAC;IAErD;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,QAAQ,CACZ,GAAmB,EACnB,QAAkB,EAClB,IAAO,EACP,IAAqB,EACrB,IAAa;QAEb,OAAO,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE;YACrD,IAAI;YACJ,QAAQ;YACR,cAAc,EAAE,MAAM,oBAAoB,CAAC,IAAI,CAAC;YAChD,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,CAAC,GAAgB;QACzB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1B,GAAG,IAAI;YACP,cAAc,EAAE,IAAI,CAAC,cAEpB;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,GAAG,CACP,GAAgB,EAChB,UAA6C;QAE7C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3E,IAAI,IAAI,KAAK,IAAI,EAAE;YACjB,OAAO,IAAI,CAAC;SACb;QACD,OAAO;YACL,GAAG,IAAI;YACP,cAAc,EAAE,IAAI,CAAC,cAEpB;SACF,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAG,CACP,GAAmB,EACnB,UAA6C;QAE7C,OAAO,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IACpE,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Expand, FunctionReference, GenericDataModel, GenericMutationCtx, GenericQueryCtx } from "convex/server";
|
|
2
|
+
import { GenericId } from "convex/values";
|
|
3
|
+
export type RunQueryCtx = {
|
|
4
|
+
runQuery: GenericQueryCtx<GenericDataModel>["runQuery"];
|
|
5
|
+
};
|
|
6
|
+
export type RunMutationCtx = {
|
|
7
|
+
runMutation: GenericMutationCtx<GenericDataModel>["runMutation"];
|
|
8
|
+
};
|
|
9
|
+
export type OpaqueIds<T> = T extends GenericId<infer _T> ? string : T extends (infer U)[] ? OpaqueIds<U>[] : T extends object ? {
|
|
10
|
+
[K in keyof T]: OpaqueIds<T[K]>;
|
|
11
|
+
} : T;
|
|
12
|
+
export type UseApi<API> = Expand<{
|
|
13
|
+
[mod in keyof API]: API[mod] extends FunctionReference<infer FType, "public", infer FArgs, infer FReturnType, infer FComponentPath> ? FunctionReference<FType, "internal", OpaqueIds<FArgs>, OpaqueIds<FReturnType>, FComponentPath> : UseApi<API[mod]>;
|
|
14
|
+
}>;
|
|
15
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/client/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,eAAe,CAAC,gBAAgB,CAAC,CAAC,UAAU,CAAC,CAAC;CACzD,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,CAAC,aAAa,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IACrB,CAAC,SAAS,SAAS,CAAC,MAAM,EAAE,CAAC,GACzB,MAAM,GACN,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACnB,SAAS,CAAC,CAAC,CAAC,EAAE,GACd,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GACnC,CAAC,CAAC;AAEZ,MAAM,MAAM,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC;KAC9B,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,iBAAiB,CACpD,MAAM,KAAK,EACX,QAAQ,EACR,MAAM,KAAK,EACX,MAAM,WAAW,EACjB,MAAM,cAAc,CACrB,GACG,iBAAiB,CACf,KAAK,EACL,UAAU,EACV,SAAS,CAAC,KAAK,CAAC,EAChB,SAAS,CAAC,WAAW,CAAC,EACtB,cAAc,CACf,GACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACrB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/client/utils.ts"],"names":[],"mappings":"AAAA,wCAAwC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A utility for referencing Convex functions in your app's API.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* ```js
|
|
6
|
+
* const myFunctionReference = api.myModule.myFunction;
|
|
7
|
+
* ```
|
|
8
|
+
*/
|
|
9
|
+
export const api: import("convex/server").AnyApi;
|
|
10
|
+
export const internal: import("convex/server").AnyApi;
|
|
11
|
+
export const components: {
|
|
12
|
+
[x: string]: import("../../../node_modules/convex/dist/esm-types/server/components/index.js").AnyComponentReference;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/component/_generated/api.js"],"names":[],"mappings":"AAcA;;;;;;;GAOG;AACH,iDAA0B;AAC1B,sDAA+B;AAC/B;;EAA8C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* prettier-ignore-start */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
* Generated `api` utility.
|
|
5
|
+
*
|
|
6
|
+
* THIS CODE IS AUTOMATICALLY GENERATED.
|
|
7
|
+
*
|
|
8
|
+
* To regenerate, run `npx convex dev`.
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { anyApi, componentsGeneric } from "convex/server";
|
|
12
|
+
/**
|
|
13
|
+
* A utility for referencing Convex functions in your app's API.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* ```js
|
|
17
|
+
* const myFunctionReference = api.myModule.myFunction;
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const api = anyApi;
|
|
21
|
+
export const internal = anyApi;
|
|
22
|
+
export const components = componentsGeneric();
|
|
23
|
+
/* prettier-ignore-end */
|
|
24
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../../src/component/_generated/api.js"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,oBAAoB;AACpB;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC;AAC1B,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC;AAC/B,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;AAE9C,yBAAyB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define a query in this Convex app's public API.
|
|
3
|
+
*
|
|
4
|
+
* This function will be allowed to read your Convex database and will be accessible from the client.
|
|
5
|
+
*
|
|
6
|
+
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
|
7
|
+
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
|
8
|
+
*/
|
|
9
|
+
export const query: import("convex/server").QueryBuilder<any, "public">;
|
|
10
|
+
/**
|
|
11
|
+
* Define a query that is only accessible from other Convex functions (but not from the client).
|
|
12
|
+
*
|
|
13
|
+
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
|
|
14
|
+
*
|
|
15
|
+
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
|
16
|
+
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
|
17
|
+
*/
|
|
18
|
+
export const internalQuery: import("convex/server").QueryBuilder<any, "internal">;
|
|
19
|
+
/**
|
|
20
|
+
* Define a mutation in this Convex app's public API.
|
|
21
|
+
*
|
|
22
|
+
* This function will be allowed to modify your Convex database and will be accessible from the client.
|
|
23
|
+
*
|
|
24
|
+
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
|
25
|
+
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
|
26
|
+
*/
|
|
27
|
+
export const mutation: import("convex/server").MutationBuilder<any, "public">;
|
|
28
|
+
/**
|
|
29
|
+
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
|
30
|
+
*
|
|
31
|
+
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
|
|
32
|
+
*
|
|
33
|
+
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
|
34
|
+
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
|
35
|
+
*/
|
|
36
|
+
export const internalMutation: import("convex/server").MutationBuilder<any, "internal">;
|
|
37
|
+
/**
|
|
38
|
+
* Define an action in this Convex app's public API.
|
|
39
|
+
*
|
|
40
|
+
* An action is a function which can execute any JavaScript code, including non-deterministic
|
|
41
|
+
* code and code with side-effects, like calling third-party services.
|
|
42
|
+
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
|
|
43
|
+
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
|
|
44
|
+
*
|
|
45
|
+
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
|
46
|
+
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
|
47
|
+
*/
|
|
48
|
+
export const action: import("convex/server").ActionBuilder<any, "public">;
|
|
49
|
+
/**
|
|
50
|
+
* Define an action that is only accessible from other Convex functions (but not from the client).
|
|
51
|
+
*
|
|
52
|
+
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
|
53
|
+
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
|
54
|
+
*/
|
|
55
|
+
export const internalAction: import("convex/server").ActionBuilder<any, "internal">;
|
|
56
|
+
/**
|
|
57
|
+
* Define a Convex HTTP action.
|
|
58
|
+
*
|
|
59
|
+
* @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
|
|
60
|
+
* as its second.
|
|
61
|
+
* @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
|
|
62
|
+
*/
|
|
63
|
+
export const httpAction: (func: (ctx: import("convex/server").GenericActionCtx<import("convex/server").GenericDataModel>, request: Request) => Promise<Response>) => import("convex/server").PublicHttpAction;
|
|
64
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/component/_generated/server.js"],"names":[],"mappings":"AAuBA;;;;;;;GAOG;AACH,wEAAkC;AAElC;;;;;;;GAOG;AACH,kFAAkD;AAElD;;;;;;;GAOG;AACH,8EAAwC;AAExC;;;;;;;GAOG;AACH,wFAAwD;AAExD;;;;;;;;;;GAUG;AACH,0EAAoC;AAEpC;;;;;GAKG;AACH,oFAAoD;AAEpD;;;;;;GAMG;AACH,8MAA4C"}
|