@formancy/server 0.9.0 → 0.11.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.
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
|
-
import { AUDIT_ACTIONS, auditedBy, authenticateApiKey, authenticateLocal, can, collectAbandonedFiles, completeBuilderRequest, createApiKey, createLocalUser, createSubmission, decodeSolution, exportCsv, formToFill, formVersion, healthOf, keepExamples, listForms, listSubmissions, listVersions, mintChallenge, offerUpload, publishForm, readExamples, replayDelivery, resolveForm, resumeDraft, saveDraft, screenUpload, setFormAccess, startDraft, verifySolution } from "@formancy/server-core";
|
|
2
|
+
import { AUDIT_ACTIONS, auditedBy, authenticateApiKey, authenticateLocal, can, collectAbandonedFiles, completeBuilderRequest, createApiKey, createLocalUser, createSubmission, decodeSolution, exportCsv, formToFill, formVersion, healthOf, keepExamples, listForms, listSubmissionPage, listSubmissions, listVersions, mintChallenge, offerUpload, publishForm, readExamples, replayDelivery, resolveForm, resumeDraft, saveDraft, screenUpload, setFormAccess, startDraft, summariseResponses, verifySolution } from "@formancy/server-core";
|
|
3
3
|
import { MODEL_REQUEST_KINDS } from "@formancy/builder-core";
|
|
4
4
|
import Fastify, { LogController } from "fastify";
|
|
5
5
|
import rateLimit from "@fastify/rate-limit";
|
|
6
6
|
import { hash, verify } from "@node-rs/argon2";
|
|
7
7
|
import { SignJWT, jwtVerify } from "jose";
|
|
8
8
|
import { METHODS, STATUS_CODES, validateHeaderName, validateHeaderValue } from "node:http";
|
|
9
|
-
import { and, desc, eq, inArray, isNull, lt, lte, max, ne, or } from "drizzle-orm";
|
|
9
|
+
import { and, desc, eq, inArray, isNull, lt, lte, max, ne, or, sql } from "drizzle-orm";
|
|
10
10
|
import { drizzle } from "drizzle-orm/postgres-js";
|
|
11
11
|
import { integer, jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
12
12
|
import postgres from "postgres";
|
|
@@ -1193,6 +1193,26 @@ async function createApp(storage, options) {
|
|
|
1193
1193
|
});
|
|
1194
1194
|
app.get("/f/:path/submissions", { preHandler: requires("submission.read") }, async (request, reply) => {
|
|
1195
1195
|
const { path } = request.params;
|
|
1196
|
+
const query = request.query ?? {};
|
|
1197
|
+
if (query.limit !== void 0 || query.after !== void 0) {
|
|
1198
|
+
const asked = typeof query.limit === "string" ? Number.parseInt(query.limit, 10) : 100;
|
|
1199
|
+
const after = query.after === void 0 ? void 0 : typeof query.after === "string" ? query.after : "";
|
|
1200
|
+
const page = await listSubmissionPage(deps, path, {
|
|
1201
|
+
limit: Number.isFinite(asked) ? asked : 100,
|
|
1202
|
+
after
|
|
1203
|
+
});
|
|
1204
|
+
if (page === void 0) return reply.code(404).send({ error: "unknown_form" });
|
|
1205
|
+
if (page.kind === "bad_cursor") return reply.code(400).send({ error: "bad_cursor" });
|
|
1206
|
+
await audit(request, {
|
|
1207
|
+
action: "submission.read",
|
|
1208
|
+
subject: path,
|
|
1209
|
+
detail: { count: page.submissions.length }
|
|
1210
|
+
});
|
|
1211
|
+
return reply.send({
|
|
1212
|
+
submissions: page.submissions,
|
|
1213
|
+
next: page.next
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1196
1216
|
const listed = await listSubmissions(deps, path);
|
|
1197
1217
|
if (listed === void 0) return reply.code(404).send({ error: "unknown_form" });
|
|
1198
1218
|
await audit(request, {
|
|
@@ -1202,6 +1222,21 @@ async function createApp(storage, options) {
|
|
|
1202
1222
|
});
|
|
1203
1223
|
return reply.send({ submissions: listed });
|
|
1204
1224
|
});
|
|
1225
|
+
app.get("/f/:path/summary", { preHandler: requires("submission.read") }, async (request, reply) => {
|
|
1226
|
+
const { path } = request.params;
|
|
1227
|
+
const versions = await summariseResponses(deps, path);
|
|
1228
|
+
if (versions === void 0) return reply.code(404).send({ error: "unknown_form" });
|
|
1229
|
+
const count = versions.reduce((total, version) => total + version.responses, 0);
|
|
1230
|
+
await audit(request, {
|
|
1231
|
+
action: "submission.read",
|
|
1232
|
+
subject: path,
|
|
1233
|
+
detail: {
|
|
1234
|
+
count,
|
|
1235
|
+
summary: true
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
return reply.send({ versions });
|
|
1239
|
+
});
|
|
1205
1240
|
app.get("/f/:path/submissions/export.csv", { preHandler: requires("submission.export") }, async (request, reply) => {
|
|
1206
1241
|
const { path } = request.params;
|
|
1207
1242
|
const csv = await exportCsv(deps, path);
|
|
@@ -1387,6 +1422,7 @@ async function bootstrapSchema(sql) {
|
|
|
1387
1422
|
data jsonb NOT NULL,
|
|
1388
1423
|
submitted_at timestamptz NOT NULL
|
|
1389
1424
|
)`;
|
|
1425
|
+
await sql`CREATE INDEX IF NOT EXISTS submissions_by_form ON submissions (form_id, submitted_at DESC, id DESC)`;
|
|
1390
1426
|
await sql`
|
|
1391
1427
|
CREATE TABLE IF NOT EXISTS webhooks (
|
|
1392
1428
|
id uuid PRIMARY KEY,
|
|
@@ -1638,8 +1674,8 @@ function toApiKeyRecord(row) {
|
|
|
1638
1674
|
}
|
|
1639
1675
|
//#endregion
|
|
1640
1676
|
//#region src/postgres-storage.ts
|
|
1641
|
-
function createPostgresStorage(sql) {
|
|
1642
|
-
const db = drizzle(sql);
|
|
1677
|
+
function createPostgresStorage(sql$1) {
|
|
1678
|
+
const db = drizzle(sql$1);
|
|
1643
1679
|
return {
|
|
1644
1680
|
...examplesStorage(db),
|
|
1645
1681
|
...identitiesStorage(db),
|
|
@@ -1873,6 +1909,9 @@ function createPostgresStorage(sql) {
|
|
|
1873
1909
|
async listSubmissionsByForm(formId) {
|
|
1874
1910
|
return (await db.select().from(submissions).where(eq(submissions.formId, formId)).orderBy(desc(submissions.submittedAt), desc(submissions.id))).map(toSubmissionRecord);
|
|
1875
1911
|
},
|
|
1912
|
+
async pageSubmissionsByForm(formId, limit, before) {
|
|
1913
|
+
return (await db.select().from(submissions).where(and(eq(submissions.formId, formId), before === void 0 ? void 0 : sql`(${submissions.submittedAt}, ${submissions.id}) < (${before.submittedAt}::timestamptz, ${before.id}::uuid)`)).orderBy(desc(submissions.submittedAt), desc(submissions.id)).limit(limit)).map(toSubmissionRecord);
|
|
1914
|
+
},
|
|
1876
1915
|
async listVersionsByForm(formId) {
|
|
1877
1916
|
return (await db.select().from(formVersions).where(eq(formVersions.formId, formId)).orderBy(desc(formVersions.version))).map((row) => ({
|
|
1878
1917
|
id: row.id,
|
|
@@ -2380,4 +2419,4 @@ function createCompleter(settings, fetch) {
|
|
|
2380
2419
|
//#endregion
|
|
2381
2420
|
export { SUBMISSION_TOKEN_HEADER as _, createLocalFileStore as a, createPostgresStorage as c, LOG_LEVELS as d, createServerLog as f, SCHEMA_HASH_HEADER as g, maxFileBytesFrom as h, startFileCollector as i, bootstrapSchema as l, workerLog as m, MODEL_PROVIDERS as n, sha256 as o, databaseNotices as p, modelSettings as r, createPostgresRateLimitStore as s, createCompleter as t, createApp as u };
|
|
2382
2421
|
|
|
2383
|
-
//# sourceMappingURL=completers-
|
|
2422
|
+
//# sourceMappingURL=completers-Cjn4y1ZH.mjs.map
|