@odla-ai/chapter 0.11.0 → 0.13.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 +36 -5
- package/dist/index.cjs +90 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -7
- package/dist/index.d.ts +73 -7
- package/dist/index.js +90 -7
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +31 -7
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +25 -0
- package/dist/worker/index.d.ts +25 -0
- package/dist/worker/index.js +31 -7
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/dist/worker/index.cjs
CHANGED
|
@@ -184,18 +184,28 @@ async function createClerkUser(secretKey, input, fetchImpl = fetch) {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
// src/member.ts
|
|
187
|
+
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
188
|
+
function isValidEmail(value) {
|
|
189
|
+
return typeof value === "string" && EMAIL_RE.test(value);
|
|
190
|
+
}
|
|
191
|
+
function clampArray(value, max) {
|
|
192
|
+
if (!Array.isArray(value)) return value;
|
|
193
|
+
return value.filter((x) => typeof x === "string" || typeof x === "number" || typeof x === "boolean").slice(0, max);
|
|
194
|
+
}
|
|
187
195
|
function hasDisclaimerAck(fields) {
|
|
188
196
|
return fields.disclaimerAck === true || fields.disclaimerAck === "true";
|
|
189
197
|
}
|
|
190
198
|
var IDENTITY_FIELDS = /* @__PURE__ */ new Set(["email", "firstName", "lastName"]);
|
|
191
199
|
function applicantProfile(chapter, fields) {
|
|
200
|
+
const app = chapter.application;
|
|
201
|
+
const allowed = (f) => app.profileFields === null || app.profileFields.includes(f);
|
|
192
202
|
const profile = {};
|
|
193
|
-
for (const f of [...
|
|
194
|
-
if (IDENTITY_FIELDS.has(f)) continue;
|
|
203
|
+
for (const f of [...app.required, ...app.optional]) {
|
|
204
|
+
if (IDENTITY_FIELDS.has(f) || !allowed(f)) continue;
|
|
195
205
|
const v = fields[f];
|
|
196
206
|
if (typeof v === "string" && v.trim() !== "") profile[f] = v.trim();
|
|
197
207
|
}
|
|
198
|
-
if (fields.focus !== void 0) profile.focus = fields.focus;
|
|
208
|
+
if (fields.focus !== void 0 && allowed("focus")) profile.focus = clampArray(fields.focus, app.maxArrayLen);
|
|
199
209
|
return Object.keys(profile).length > 0 ? profile : void 0;
|
|
200
210
|
}
|
|
201
211
|
async function submitApplication(db, chapter, fields, opts) {
|
|
@@ -209,6 +219,9 @@ async function submitApplication(db, chapter, fields, opts) {
|
|
|
209
219
|
const cap = app.maxLen[f] ?? app.defaultMaxLen;
|
|
210
220
|
if (typeof v === "string" && v.length > cap) return { ok: false, error: `${f} exceeds ${cap} characters` };
|
|
211
221
|
}
|
|
222
|
+
if (app.validateEmail && typeof fields.email === "string" && !isValidEmail(fields.email)) {
|
|
223
|
+
return { ok: false, error: "email must be a valid email address" };
|
|
224
|
+
}
|
|
212
225
|
const acked = hasDisclaimerAck(fields);
|
|
213
226
|
if (app.requireDisclaimerAck && !acked) {
|
|
214
227
|
return { ok: false, error: "disclaimerAck is required" };
|
|
@@ -218,7 +231,7 @@ async function submitApplication(db, chapter, fields, opts) {
|
|
|
218
231
|
for (const f of [...app.required, ...app.optional]) {
|
|
219
232
|
if (typeof fields[f] === "string") row[f] = fields[f].trim();
|
|
220
233
|
}
|
|
221
|
-
if (fields.focus !== void 0) row.focus = fields.focus;
|
|
234
|
+
if (fields.focus !== void 0) row.focus = clampArray(fields.focus, app.maxArrayLen);
|
|
222
235
|
if (opts.groupId) row.groupId = opts.groupId;
|
|
223
236
|
if (acked) row.disclaimerAckAt = opts.now;
|
|
224
237
|
const { duplicate } = await db.transact(
|
|
@@ -271,7 +284,7 @@ async function projectSharedRecord(deps, person) {
|
|
|
271
284
|
return upsertPerson(deps, { email: person.email, input: sharedPersonInput(person), mutationId: `share:${person.hubRecordId}` });
|
|
272
285
|
}
|
|
273
286
|
async function projectApplicant(deps, applicant) {
|
|
274
|
-
const
|
|
287
|
+
const base = sharedPersonInput({
|
|
275
288
|
email: applicant.email,
|
|
276
289
|
firstName: applicant.firstName,
|
|
277
290
|
lastName: applicant.lastName,
|
|
@@ -279,7 +292,14 @@ async function projectApplicant(deps, applicant) {
|
|
|
279
292
|
linkedin: applicant.linkedin,
|
|
280
293
|
hubRecordId: applicant.applicationId
|
|
281
294
|
});
|
|
282
|
-
|
|
295
|
+
const mutationId = `apply:${applicant.applicationId}`;
|
|
296
|
+
const extra = applicant.extra ?? {};
|
|
297
|
+
if (Object.keys(extra).length === 0) return upsertPerson(deps, { email: applicant.email, input: base, mutationId });
|
|
298
|
+
try {
|
|
299
|
+
return await upsertPerson(deps, { email: applicant.email, input: { ...base, ...extra }, mutationId });
|
|
300
|
+
} catch {
|
|
301
|
+
return upsertPerson(deps, { email: applicant.email, input: base, mutationId });
|
|
302
|
+
}
|
|
283
303
|
}
|
|
284
304
|
|
|
285
305
|
// src/scheduling.ts
|
|
@@ -523,10 +543,14 @@ async function provisionApplicant(db, chapter, applicationId, fields) {
|
|
|
523
543
|
const email = typeof fields.email === "string" ? fields.email : "";
|
|
524
544
|
if (!email) return;
|
|
525
545
|
const s = (v) => typeof v === "string" ? v : void 0;
|
|
546
|
+
const extra = {};
|
|
547
|
+
for (const f of chapter.application.crmFields) {
|
|
548
|
+
if (fields[f] !== void 0) extra[f] = fields[f];
|
|
549
|
+
}
|
|
526
550
|
try {
|
|
527
551
|
await projectApplicant(
|
|
528
552
|
{ crm: chapter.crm, db, now: () => Date.now(), newId: () => crypto.randomUUID() },
|
|
529
|
-
{ applicationId, email, firstName: s(fields.firstName), lastName: s(fields.lastName), phone: s(fields.phone), linkedin: s(fields.linkedin) }
|
|
553
|
+
{ applicationId, email, firstName: s(fields.firstName), lastName: s(fields.lastName), phone: s(fields.phone), linkedin: s(fields.linkedin), extra }
|
|
530
554
|
);
|
|
531
555
|
} catch {
|
|
532
556
|
}
|