@terreno/api 0.7.1 → 0.8.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.
Files changed (50) hide show
  1. package/dist/__tests__/{versionCheck.test.js → versionCheckPlugin.test.js} +2 -2
  2. package/dist/api.d.ts +4 -2
  3. package/dist/api.js +7 -2
  4. package/dist/consentApp.d.ts +33 -0
  5. package/dist/consentApp.js +484 -0
  6. package/dist/consentApp.test.d.ts +1 -0
  7. package/dist/consentApp.test.js +1132 -0
  8. package/dist/index.d.ts +6 -0
  9. package/dist/index.js +6 -0
  10. package/dist/models/consentForm.d.ts +2 -0
  11. package/dist/models/consentForm.js +115 -0
  12. package/dist/models/consentResponse.d.ts +2 -0
  13. package/dist/models/consentResponse.js +73 -0
  14. package/dist/models/versionConfig.d.ts +1 -1
  15. package/dist/openApiValidator.js +2 -0
  16. package/dist/populate.d.ts +1 -0
  17. package/dist/populate.js +53 -13
  18. package/dist/syncConsents.d.ts +67 -0
  19. package/dist/syncConsents.js +334 -0
  20. package/dist/syncConsents.test.d.ts +1 -0
  21. package/dist/syncConsents.test.js +249 -0
  22. package/dist/terrenoApp.js +6 -5
  23. package/dist/terrenoPlugin.d.ts +1 -1
  24. package/dist/types/consentForm.d.ts +32 -0
  25. package/dist/types/consentForm.js +2 -0
  26. package/dist/types/consentResponse.d.ts +23 -0
  27. package/dist/types/consentResponse.js +2 -0
  28. package/dist/vendor/wesleytodd-openapi/lib/generate-doc.js +1 -1
  29. package/dist/versionCheckPlugin.d.ts +2 -0
  30. package/dist/versionCheckPlugin.js +3 -6
  31. package/package.json +1 -1
  32. package/src/__tests__/{versionCheck.test.ts → versionCheckPlugin.test.ts} +2 -2
  33. package/src/api.ts +11 -4
  34. package/src/consentApp.test.ts +749 -0
  35. package/src/consentApp.ts +463 -0
  36. package/src/index.ts +6 -0
  37. package/src/models/consentForm.ts +123 -0
  38. package/src/models/consentResponse.ts +78 -0
  39. package/src/models/versionConfig.ts +1 -1
  40. package/src/openApiValidator.ts +2 -0
  41. package/src/populate.ts +33 -0
  42. package/src/syncConsents.test.ts +124 -0
  43. package/src/syncConsents.ts +263 -0
  44. package/src/terrenoApp.ts +6 -6
  45. package/src/terrenoPlugin.ts +1 -1
  46. package/src/types/consentForm.ts +41 -0
  47. package/src/types/consentResponse.ts +34 -0
  48. package/src/vendor/wesleytodd-openapi/lib/generate-doc.js +1 -1
  49. package/src/versionCheckPlugin.ts +5 -6
  50. /package/dist/__tests__/{versionCheck.test.d.ts → versionCheckPlugin.test.d.ts} +0 -0
package/dist/index.d.ts CHANGED
@@ -5,11 +5,14 @@ export * from "./betterAuthApp";
5
5
  export * from "./betterAuthSetup";
6
6
  export * from "./configurationApp";
7
7
  export * from "./configurationPlugin";
8
+ export * from "./consentApp";
8
9
  export * from "./errors";
9
10
  export * from "./expressServer";
10
11
  export * from "./githubAuth";
11
12
  export * from "./logger";
12
13
  export * from "./middleware";
14
+ export * from "./models/consentForm";
15
+ export * from "./models/consentResponse";
13
16
  export * from "./models/versionConfig";
14
17
  export * from "./notifiers";
15
18
  export * from "./openApiBuilder";
@@ -21,8 +24,11 @@ export * from "./plugins";
21
24
  export * from "./populate";
22
25
  export * from "./scriptRunner";
23
26
  export * from "./secretProviders";
27
+ export * from "./syncConsents";
24
28
  export * from "./terrenoApp";
25
29
  export * from "./terrenoPlugin";
26
30
  export * from "./transformers";
31
+ export * from "./types/consentForm";
32
+ export * from "./types/consentResponse";
27
33
  export * from "./utils";
28
34
  export * from "./versionCheckPlugin";
package/dist/index.js CHANGED
@@ -21,11 +21,14 @@ __exportStar(require("./betterAuthApp"), exports);
21
21
  __exportStar(require("./betterAuthSetup"), exports);
22
22
  __exportStar(require("./configurationApp"), exports);
23
23
  __exportStar(require("./configurationPlugin"), exports);
24
+ __exportStar(require("./consentApp"), exports);
24
25
  __exportStar(require("./errors"), exports);
25
26
  __exportStar(require("./expressServer"), exports);
26
27
  __exportStar(require("./githubAuth"), exports);
27
28
  __exportStar(require("./logger"), exports);
28
29
  __exportStar(require("./middleware"), exports);
30
+ __exportStar(require("./models/consentForm"), exports);
31
+ __exportStar(require("./models/consentResponse"), exports);
29
32
  __exportStar(require("./models/versionConfig"), exports);
30
33
  __exportStar(require("./notifiers"), exports);
31
34
  __exportStar(require("./openApiBuilder"), exports);
@@ -37,8 +40,11 @@ __exportStar(require("./plugins"), exports);
37
40
  __exportStar(require("./populate"), exports);
38
41
  __exportStar(require("./scriptRunner"), exports);
39
42
  __exportStar(require("./secretProviders"), exports);
43
+ __exportStar(require("./syncConsents"), exports);
40
44
  __exportStar(require("./terrenoApp"), exports);
41
45
  __exportStar(require("./terrenoPlugin"), exports);
42
46
  __exportStar(require("./transformers"), exports);
47
+ __exportStar(require("./types/consentForm"), exports);
48
+ __exportStar(require("./types/consentResponse"), exports);
43
49
  __exportStar(require("./utils"), exports);
44
50
  __exportStar(require("./versionCheckPlugin"), exports);
@@ -0,0 +1,2 @@
1
+ import type { ConsentFormModel } from "../types/consentForm";
2
+ export declare const ConsentForm: ConsentFormModel;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ConsentForm = void 0;
7
+ var mongoose_1 = __importDefault(require("mongoose"));
8
+ var plugins_1 = require("../plugins");
9
+ var consentFormSchema = new mongoose_1.default.Schema({
10
+ active: {
11
+ default: false,
12
+ description: "Whether this consent form is currently active and available to users",
13
+ type: Boolean,
14
+ },
15
+ agreeButtonText: {
16
+ default: "I Agree",
17
+ description: "Label text for the agreement button",
18
+ type: String,
19
+ },
20
+ allowDecline: {
21
+ default: false,
22
+ description: "Whether users are allowed to decline the consent form",
23
+ type: Boolean,
24
+ },
25
+ captureSignature: {
26
+ default: false,
27
+ description: "Whether to require a drawn or typed signature when the user agrees",
28
+ type: Boolean,
29
+ },
30
+ checkboxes: {
31
+ default: [],
32
+ description: "List of checkboxes the user must interact with before agreeing",
33
+ type: [
34
+ {
35
+ confirmationPrompt: {
36
+ description: "Optional prompt shown when the user checks this checkbox",
37
+ type: String,
38
+ },
39
+ label: {
40
+ description: "Display label for the checkbox",
41
+ required: true,
42
+ type: String,
43
+ },
44
+ required: {
45
+ default: false,
46
+ description: "Whether this checkbox must be checked before the user can agree",
47
+ type: Boolean,
48
+ },
49
+ },
50
+ ],
51
+ },
52
+ content: {
53
+ description: 'Locale-keyed map of Markdown content for this form (e.g. {"en": "# Terms\\n..."})',
54
+ of: String,
55
+ required: true,
56
+ type: Map,
57
+ },
58
+ declineButtonText: {
59
+ default: "Decline",
60
+ description: "Label text for the decline button (only shown when allowDecline is true)",
61
+ type: String,
62
+ },
63
+ defaultLocale: {
64
+ default: "en",
65
+ description: "Default locale to use when the requested locale is not available",
66
+ type: String,
67
+ },
68
+ order: {
69
+ default: 0,
70
+ description: "Display order relative to other consent forms (lower numbers appear first)",
71
+ required: true,
72
+ type: Number,
73
+ },
74
+ required: {
75
+ default: true,
76
+ description: "Whether users must complete this form before accessing the application",
77
+ type: Boolean,
78
+ },
79
+ requireScrollToBottom: {
80
+ default: false,
81
+ description: "Whether users must scroll to the bottom of the form content before agreeing",
82
+ type: Boolean,
83
+ },
84
+ slug: {
85
+ description: "URL-safe identifier for this form, combined with version to uniquely identify a form",
86
+ index: true,
87
+ required: true,
88
+ trim: true,
89
+ type: String,
90
+ },
91
+ title: {
92
+ description: "Human-readable title of the consent form",
93
+ required: true,
94
+ trim: true,
95
+ type: String,
96
+ },
97
+ type: {
98
+ description: "Category of consent form",
99
+ enum: ["agreement", "privacy", "hipaa", "research", "terms", "custom"],
100
+ required: true,
101
+ type: String,
102
+ },
103
+ version: {
104
+ default: 1,
105
+ description: "Version number of this form. Incrementing the version requires users to re-consent",
106
+ required: true,
107
+ type: Number,
108
+ },
109
+ }, { strict: "throw", toJSON: { virtuals: true }, toObject: { virtuals: true } });
110
+ consentFormSchema.index({ slug: 1, version: 1 }, { unique: true });
111
+ consentFormSchema.plugin(plugins_1.createdUpdatedPlugin);
112
+ consentFormSchema.plugin(plugins_1.isDeletedPlugin);
113
+ consentFormSchema.plugin(plugins_1.findOneOrNone);
114
+ consentFormSchema.plugin(plugins_1.findExactlyOne);
115
+ exports.ConsentForm = mongoose_1.default.model("ConsentForm", consentFormSchema);
@@ -0,0 +1,2 @@
1
+ import type { ConsentResponseModel } from "../types/consentResponse";
2
+ export declare const ConsentResponse: ConsentResponseModel;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ConsentResponse = void 0;
7
+ var mongoose_1 = __importDefault(require("mongoose"));
8
+ var plugins_1 = require("../plugins");
9
+ var consentResponseSchema = new mongoose_1.default.Schema({
10
+ agreed: {
11
+ description: "Whether the user agreed (true) or declined (false) the consent form",
12
+ required: true,
13
+ type: Boolean,
14
+ },
15
+ agreedAt: {
16
+ description: "Timestamp when the user submitted their agreement or declination",
17
+ required: true,
18
+ type: Date,
19
+ },
20
+ checkboxValues: {
21
+ description: "Map of checkbox index to boolean indicating whether each checkbox was checked",
22
+ of: Boolean,
23
+ type: Map,
24
+ },
25
+ consentFormId: {
26
+ description: "Reference to the ConsentForm that was responded to",
27
+ ref: "ConsentForm",
28
+ required: true,
29
+ type: mongoose_1.default.Schema.Types.ObjectId,
30
+ },
31
+ contentSnapshot: {
32
+ description: "Snapshot of the form content in the user's locale at the time of response",
33
+ type: String,
34
+ },
35
+ formVersionSnapshot: {
36
+ description: "Version number of the form at the time the user responded",
37
+ type: Number,
38
+ },
39
+ ipAddress: {
40
+ description: "IP address of the user at the time of response, captured for audit purposes",
41
+ type: String,
42
+ },
43
+ locale: {
44
+ description: "Locale code of the content version the user viewed when responding",
45
+ required: true,
46
+ type: String,
47
+ },
48
+ signature: {
49
+ description: "Base64-encoded signature image or typed signature text, if captured",
50
+ type: String,
51
+ },
52
+ signedAt: {
53
+ description: "Timestamp when the user provided their signature",
54
+ type: Date,
55
+ },
56
+ userAgent: {
57
+ description: "User-agent string of the browser or app used to submit the response",
58
+ type: String,
59
+ },
60
+ userId: {
61
+ description: "Reference to the User who submitted this response",
62
+ index: true,
63
+ ref: "User",
64
+ required: true,
65
+ type: mongoose_1.default.Schema.Types.ObjectId,
66
+ },
67
+ }, { strict: "throw", toJSON: { virtuals: true }, toObject: { virtuals: true } });
68
+ consentResponseSchema.index({ consentFormId: 1, userId: 1 });
69
+ consentResponseSchema.plugin(plugins_1.createdUpdatedPlugin);
70
+ consentResponseSchema.plugin(plugins_1.isDeletedPlugin);
71
+ consentResponseSchema.plugin(plugins_1.findOneOrNone);
72
+ consentResponseSchema.plugin(plugins_1.findExactlyOne);
73
+ exports.ConsentResponse = mongoose_1.default.model("ConsentResponse", consentResponseSchema);
@@ -1,5 +1,5 @@
1
1
  import mongoose, { type Document } from "mongoose";
2
- import { type APIErrorConstructor } from "../errors";
2
+ import type { APIErrorConstructor } from "../errors";
3
3
  export interface VersionConfigDocument extends mongoose.Document {
4
4
  webWarningVersion: number;
5
5
  webRequiredVersion: number;
@@ -113,6 +113,7 @@ var ajv_formats_1 = __importDefault(require("ajv-formats"));
113
113
  var mongoose_to_swagger_1 = __importDefault(require("mongoose-to-swagger"));
114
114
  var errors_1 = require("./errors");
115
115
  var logger_1 = require("./logger");
116
+ var populate_1 = require("./populate");
116
117
  // Whether configureOpenApiValidator() has been called
117
118
  var isConfigured = false;
118
119
  // Global validator configuration - can be modified at runtime
@@ -601,6 +602,7 @@ var m2sOptions = {
601
602
  */
602
603
  function getSchemaFromModel(model) {
603
604
  var modelSwagger = (0, mongoose_to_swagger_1.default)(model, m2sOptions);
605
+ (0, populate_1.fixMixedFields)(model.schema, modelSwagger.properties);
604
606
  return modelSwagger.properties;
605
607
  }
606
608
  /**
@@ -4,6 +4,7 @@ export type PopulatePath = {
4
4
  openApiComponent?: any;
5
5
  fields?: string[];
6
6
  };
7
+ export declare const fixMixedFields: (schema: any, properties: Record<string, any>) => void;
7
8
  export declare function getOpenApiSpecForModel(model: any, { populatePaths, extraModelProperties, }?: {
8
9
  populatePaths?: PopulatePath[];
9
10
  extraModelProperties?: any;
package/dist/populate.js CHANGED
@@ -50,6 +50,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
50
50
  return (mod && mod.__esModule) ? mod : { "default": mod };
51
51
  };
52
52
  Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.fixMixedFields = void 0;
53
54
  exports.getOpenApiSpecForModel = getOpenApiSpecForModel;
54
55
  exports.unpopulate = unpopulate;
55
56
  var isArray_1 = __importDefault(require("lodash/isArray"));
@@ -124,13 +125,52 @@ function getPathInSchema(schema, path) {
124
125
  return fullPath;
125
126
  }
126
127
  // Replaces populated properties with the populated schema.
128
+ // Recursively walks a Mongoose schema and fixes any Mixed fields in the
129
+ // OpenAPI properties so they use an empty schema (accepts any type) instead
130
+ // of the `{type: "object", properties: {}}` that mongoose-to-swagger emits.
131
+ var fixMixedFields = function (schema, properties) {
132
+ var e_1, _a;
133
+ var _b, _c, _d;
134
+ if (!properties || !schema) {
135
+ return;
136
+ }
137
+ try {
138
+ for (var _e = __values(Object.keys(properties)), _f = _e.next(); !_f.done; _f = _e.next()) {
139
+ var key = _f.value;
140
+ var schemaPath = schema.path(key);
141
+ if (!schemaPath) {
142
+ continue;
143
+ }
144
+ // Direct Mixed field
145
+ if (schemaPath.instance === "Mixed") {
146
+ properties[key] = { description: (_b = properties[key]) === null || _b === void 0 ? void 0 : _b.description };
147
+ continue;
148
+ }
149
+ // Array of sub-documents — check each sub-field for Mixed
150
+ if (schemaPath.instance === "Array" &&
151
+ schemaPath.schema &&
152
+ ((_d = (_c = properties[key]) === null || _c === void 0 ? void 0 : _c.items) === null || _d === void 0 ? void 0 : _d.properties)) {
153
+ (0, exports.fixMixedFields)(schemaPath.schema, properties[key].items.properties);
154
+ }
155
+ }
156
+ }
157
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
158
+ finally {
159
+ try {
160
+ if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
161
+ }
162
+ finally { if (e_1) throw e_1.error; }
163
+ }
164
+ };
165
+ exports.fixMixedFields = fixMixedFields;
127
166
  function getOpenApiSpecForModel(model, _a) {
128
- var e_1, _b, _c, e_2, _d, e_3, _e, e_4, _f;
167
+ var e_2, _b, _c, e_3, _d, e_4, _e, e_5, _f;
129
168
  var _g, _h, _j, _k;
130
169
  var _l = _a === void 0 ? {} : _a, populatePaths = _l.populatePaths, extraModelProperties = _l.extraModelProperties;
131
170
  var modelSwagger = (0, mongoose_to_swagger_1.default)(model, {
132
171
  props: ["required", "enum"],
133
172
  });
173
+ (0, exports.fixMixedFields)(model.schema, modelSwagger.properties);
134
174
  if (populatePaths && (0, isArray_1.default)(populatePaths)) {
135
175
  try {
136
176
  for (var populatePaths_1 = __values(populatePaths), populatePaths_1_1 = populatePaths_1.next(); !populatePaths_1_1.done; populatePaths_1_1 = populatePaths_1.next()) {
@@ -191,12 +231,12 @@ function getOpenApiSpecForModel(model, _a) {
191
231
  }
192
232
  }
193
233
  }
194
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
234
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
195
235
  finally {
196
236
  try {
197
237
  if (populatePaths_1_1 && !populatePaths_1_1.done && (_b = populatePaths_1.return)) _b.call(populatePaths_1);
198
238
  }
199
- finally { if (e_1) throw e_1.error; }
239
+ finally { if (e_2) throw e_2.error; }
200
240
  }
201
241
  }
202
242
  try {
@@ -212,12 +252,12 @@ function getOpenApiSpecForModel(model, _a) {
212
252
  };
213
253
  }
214
254
  }
215
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
255
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
216
256
  finally {
217
257
  try {
218
258
  if (_o && !_o.done && (_d = _m.return)) _d.call(_m);
219
259
  }
220
- finally { if (e_2) throw e_2.error; }
260
+ finally { if (e_3) throw e_3.error; }
221
261
  }
222
262
  // Check subschemas for virtuals (one level deep)
223
263
  if (model.schema.childSchemas.length > 0) {
@@ -225,7 +265,7 @@ function getOpenApiSpecForModel(model, _a) {
225
265
  for (var _p = __values(model.schema.childSchemas), _q = _p.next(); !_q.done; _q = _p.next()) {
226
266
  var childSchema = _q.value;
227
267
  try {
228
- for (var _r = (e_4 = void 0, __values(Object.keys(childSchema.schema.virtuals))), _s = _r.next(); !_s.done; _s = _r.next()) {
268
+ for (var _r = (e_5 = void 0, __values(Object.keys(childSchema.schema.virtuals))), _s = _r.next(); !_s.done; _s = _r.next()) {
229
269
  var virtual = _s.value;
230
270
  if (virtual === "id" || virtual === "__v") {
231
271
  continue;
@@ -235,21 +275,21 @@ function getOpenApiSpecForModel(model, _a) {
235
275
  };
236
276
  }
237
277
  }
238
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
278
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
239
279
  finally {
240
280
  try {
241
281
  if (_s && !_s.done && (_f = _r.return)) _f.call(_r);
242
282
  }
243
- finally { if (e_4) throw e_4.error; }
283
+ finally { if (e_5) throw e_5.error; }
244
284
  }
245
285
  }
246
286
  }
247
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
287
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
248
288
  finally {
249
289
  try {
250
290
  if (_q && !_q.done && (_e = _p.return)) _e.call(_p);
251
291
  }
252
- finally { if (e_3) throw e_3.error; }
292
+ finally { if (e_4) throw e_4.error; }
253
293
  }
254
294
  }
255
295
  return {
@@ -268,7 +308,7 @@ function unpopulate(doc, path) {
268
308
  var pathParts = path.split(".");
269
309
  // Recursive because we need to support nested paths.
270
310
  var recursiveUnpopulate = function (current, parts) {
271
- var e_5, _a;
311
+ var e_6, _a;
272
312
  var _b;
273
313
  var part = parts[0];
274
314
  // If the path doesn't exist, return the original doc
@@ -297,12 +337,12 @@ function unpopulate(doc, path) {
297
337
  recursiveUnpopulate(item, parts.slice(1)); // Recursively handle each item in the array
298
338
  }
299
339
  }
300
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
340
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
301
341
  finally {
302
342
  try {
303
343
  if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
304
344
  }
305
- finally { if (e_5) throw e_5.error; }
345
+ finally { if (e_6) throw e_6.error; }
306
346
  }
307
347
  }
308
348
  else {
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Sync consent form definitions from code to the database.
3
+ *
4
+ * Compares the provided definitions (keyed by slug) against what's in the database
5
+ * and creates, updates, or deactivates forms to match. When content changes, a new
6
+ * version is published so users are prompted to re-consent.
7
+ */
8
+ import type { ConsentFormType } from "./types/consentForm";
9
+ export interface ConsentFormDefinition {
10
+ title: string;
11
+ type: ConsentFormType;
12
+ content: Record<string, string>;
13
+ order?: number;
14
+ required?: boolean;
15
+ requireScrollToBottom?: boolean;
16
+ captureSignature?: boolean;
17
+ agreeButtonText?: string;
18
+ allowDecline?: boolean;
19
+ declineButtonText?: string;
20
+ defaultLocale?: string;
21
+ checkboxes?: Array<{
22
+ label: string;
23
+ required?: boolean;
24
+ confirmationPrompt?: string;
25
+ }>;
26
+ }
27
+ export interface SyncConsentsOptions {
28
+ /** Deactivate database forms whose slugs are not in the definitions. Default: false */
29
+ deactivateRemoved?: boolean;
30
+ /** If true, log what would change without writing to the database. Default: false */
31
+ dryRun?: boolean;
32
+ }
33
+ export interface SyncConsentsResult {
34
+ created: string[];
35
+ updated: string[];
36
+ deactivated: string[];
37
+ unchanged: string[];
38
+ }
39
+ /**
40
+ * Sync consent form definitions to the database.
41
+ *
42
+ * @param definitions - Map of slug to consent form definition
43
+ * @param options - Sync options
44
+ * @returns Summary of what was created, updated, deactivated, or unchanged
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * import {syncConsents} from "@terreno/api";
49
+ *
50
+ * await syncConsents({
51
+ * "terms-of-service": {
52
+ * title: "Terms of Service",
53
+ * type: "terms",
54
+ * content: {"en": "# Terms\n...", "es": "# Términos\n..."},
55
+ * required: true,
56
+ * order: 1,
57
+ * },
58
+ * "privacy-policy": {
59
+ * title: "Privacy Policy",
60
+ * type: "privacy",
61
+ * content: {"en": "# Privacy\n..."},
62
+ * order: 2,
63
+ * },
64
+ * });
65
+ * ```
66
+ */
67
+ export declare const syncConsents: (definitions: Record<string, ConsentFormDefinition>, options?: SyncConsentsOptions) => Promise<SyncConsentsResult>;