@odla-ai/chapter 0.8.0 → 0.10.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 +55 -17
- package/dist/chunk-YO6DY5DL.js +281 -0
- package/dist/chunk-YO6DY5DL.js.map +1 -0
- package/dist/chunk-ZCZK6QLC.js +537 -0
- package/dist/chunk-ZCZK6QLC.js.map +1 -0
- package/dist/index.cjs +61 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -14
- package/dist/index.d.ts +60 -14
- package/dist/index.js +61 -16
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +71 -0
- package/dist/ui/admin/index.js +9 -0
- package/dist/ui/admin/index.js.map +1 -0
- package/dist/ui/index.d.ts +4 -219
- package/dist/ui/index.js +20 -795
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/member/index.d.ts +152 -0
- package/dist/ui/member/index.js +33 -0
- package/dist/ui/member/index.js.map +1 -0
- package/dist/worker/index.cjs +105 -30
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +17 -0
- package/dist/worker/index.d.ts +17 -0
- package/dist/worker/index.js +105 -30
- package/dist/worker/index.js.map +1 -1
- package/package.json +9 -5
package/dist/index.cjs
CHANGED
|
@@ -77,6 +77,7 @@ __export(index_exports, {
|
|
|
77
77
|
stripeForm: () => stripeForm,
|
|
78
78
|
submitApplication: () => submitApplication,
|
|
79
79
|
subscriptionIdempotencyKey: () => subscriptionIdempotencyKey,
|
|
80
|
+
validateScheduling: () => validateScheduling,
|
|
80
81
|
verifyStripeSignature: () => verifyStripeSignature,
|
|
81
82
|
webhookMutationId: () => webhookMutationId
|
|
82
83
|
});
|
|
@@ -558,6 +559,13 @@ function defineChapter(config) {
|
|
|
558
559
|
if (account !== "invite" && account !== "create" && account !== "none") {
|
|
559
560
|
throw new Error(`defineChapter.account: must be "invite", "create", or "none" \u2014 got "${String(account)}"`);
|
|
560
561
|
}
|
|
562
|
+
const adminNotification = config.sends?.adminNotification ?? "submit";
|
|
563
|
+
if (adminNotification !== "submit" && adminNotification !== "payment" && adminNotification !== "never") {
|
|
564
|
+
throw new Error(
|
|
565
|
+
`defineChapter.sends.adminNotification: must be "submit", "payment", or "never" \u2014 got "${String(adminNotification)}"`
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
const sends = { adminNotification };
|
|
561
569
|
const chapter = {
|
|
562
570
|
config,
|
|
563
571
|
id: id2,
|
|
@@ -571,6 +579,7 @@ function defineChapter(config) {
|
|
|
571
579
|
rules,
|
|
572
580
|
services,
|
|
573
581
|
account,
|
|
582
|
+
sends,
|
|
574
583
|
groupSeed: () => mode === "chapter" ? buildGroupSeed(config) : null
|
|
575
584
|
};
|
|
576
585
|
if (config.url !== void 0) chapter.url = config.url;
|
|
@@ -848,13 +857,15 @@ async function projectApplicant(deps, applicant) {
|
|
|
848
857
|
}
|
|
849
858
|
|
|
850
859
|
// src/clerk.ts
|
|
860
|
+
var heal = (status) => status === 422 ? { ok: true, status, existed: true } : { ok: false, status };
|
|
851
861
|
function clerkInviteRequest(input) {
|
|
852
862
|
return {
|
|
853
863
|
path: "/v1/invitations",
|
|
854
864
|
body: {
|
|
855
865
|
email_address: input.email,
|
|
856
866
|
notify: true,
|
|
857
|
-
...input.redirectUrl ? { redirect_url: input.redirectUrl } : {}
|
|
867
|
+
...input.redirectUrl ? { redirect_url: input.redirectUrl } : {},
|
|
868
|
+
...input.publicMetadata ? { public_metadata: input.publicMetadata } : {}
|
|
858
869
|
}
|
|
859
870
|
};
|
|
860
871
|
}
|
|
@@ -865,7 +876,7 @@ async function createClerkInvitation(secretKey, input, fetchImpl = fetch) {
|
|
|
865
876
|
headers: { authorization: `Bearer ${secretKey}`, "content-type": "application/json" },
|
|
866
877
|
body: JSON.stringify(body)
|
|
867
878
|
});
|
|
868
|
-
return { ok:
|
|
879
|
+
return res.ok ? { ok: true, status: res.status } : heal(res.status);
|
|
869
880
|
}
|
|
870
881
|
function clerkUserRequest(input) {
|
|
871
882
|
return {
|
|
@@ -874,10 +885,25 @@ function clerkUserRequest(input) {
|
|
|
874
885
|
email_address: [input.email],
|
|
875
886
|
skip_password_requirement: true,
|
|
876
887
|
...input.firstName ? { first_name: input.firstName } : {},
|
|
877
|
-
...input.lastName ? { last_name: input.lastName } : {}
|
|
888
|
+
...input.lastName ? { last_name: input.lastName } : {},
|
|
889
|
+
...input.publicMetadata ? { public_metadata: input.publicMetadata } : {}
|
|
878
890
|
}
|
|
879
891
|
};
|
|
880
892
|
}
|
|
893
|
+
async function refreshUserMetadata(secretKey, email, publicMetadata, fetchImpl) {
|
|
894
|
+
const auth = { authorization: `Bearer ${secretKey}` };
|
|
895
|
+
const found = await fetchImpl(`https://api.clerk.com/v1/users?email_address=${encodeURIComponent(email)}&limit=1`, { headers: auth });
|
|
896
|
+
if (!found.ok) return false;
|
|
897
|
+
const users = await found.json().catch(() => null);
|
|
898
|
+
const id2 = Array.isArray(users) && typeof users[0]?.id === "string" ? users[0].id : void 0;
|
|
899
|
+
if (!id2) return false;
|
|
900
|
+
const patched = await fetchImpl(`https://api.clerk.com/v1/users/${id2}/metadata`, {
|
|
901
|
+
method: "PATCH",
|
|
902
|
+
headers: { ...auth, "content-type": "application/json" },
|
|
903
|
+
body: JSON.stringify({ public_metadata: publicMetadata })
|
|
904
|
+
});
|
|
905
|
+
return patched.ok;
|
|
906
|
+
}
|
|
881
907
|
async function createClerkUser(secretKey, input, fetchImpl = fetch) {
|
|
882
908
|
const { path, body } = clerkUserRequest(input);
|
|
883
909
|
const res = await fetchImpl(`https://api.clerk.com${path}`, {
|
|
@@ -885,7 +911,11 @@ async function createClerkUser(secretKey, input, fetchImpl = fetch) {
|
|
|
885
911
|
headers: { authorization: `Bearer ${secretKey}`, "content-type": "application/json" },
|
|
886
912
|
body: JSON.stringify(body)
|
|
887
913
|
});
|
|
888
|
-
return { ok:
|
|
914
|
+
if (res.ok) return { ok: true, status: res.status };
|
|
915
|
+
const healed = heal(res.status);
|
|
916
|
+
if (!healed.existed || !input.publicMetadata) return healed;
|
|
917
|
+
const refreshed = await refreshUserMetadata(secretKey, input.email, input.publicMetadata, fetchImpl).catch(() => false);
|
|
918
|
+
return { ...healed, refreshed };
|
|
889
919
|
}
|
|
890
920
|
|
|
891
921
|
// src/session.ts
|
|
@@ -1004,6 +1034,12 @@ function isValidTimeZone(tz) {
|
|
|
1004
1034
|
}
|
|
1005
1035
|
}
|
|
1006
1036
|
function resolveScheduling(config) {
|
|
1037
|
+
const result = validateScheduling(config);
|
|
1038
|
+
if (result.ok) return result.value;
|
|
1039
|
+
const detail = Object.entries(result.errors).map(([field, message]) => `${field}: ${message}`).join(" ");
|
|
1040
|
+
throw new Error(`scheduling: ${detail}`);
|
|
1041
|
+
}
|
|
1042
|
+
function validateScheduling(config) {
|
|
1007
1043
|
const d = config ?? {};
|
|
1008
1044
|
const c = {
|
|
1009
1045
|
slotMinutes: d.slotMinutes ?? SCHEDULING_DEFAULTS.slotMinutes,
|
|
@@ -1015,20 +1051,29 @@ function resolveScheduling(config) {
|
|
|
1015
1051
|
windowDays: d.windowDays ?? SCHEDULING_DEFAULTS.windowDays,
|
|
1016
1052
|
summaryTemplate: d.summaryTemplate ?? SCHEDULING_DEFAULTS.summaryTemplate
|
|
1017
1053
|
};
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
if (!(c.windowDays >= 1 && c.windowDays <= 62))
|
|
1023
|
-
|
|
1024
|
-
|
|
1054
|
+
const errors = {};
|
|
1055
|
+
if (!(c.slotMinutes >= 15 && c.slotMinutes <= 240)) {
|
|
1056
|
+
errors.slotMinutes = "Slot length must be between 15 and 240 minutes.";
|
|
1057
|
+
}
|
|
1058
|
+
if (!(c.windowDays >= 1 && c.windowDays <= 62)) {
|
|
1059
|
+
errors.windowDays = "Booking window must be between 1 and 62 days (the calendar caps look-ahead at 62).";
|
|
1060
|
+
}
|
|
1061
|
+
if (!(c.minNoticeHours >= 0 && c.minNoticeHours <= 336)) {
|
|
1062
|
+
errors.minNoticeHours = "Minimum notice must be between 0 and 336 hours.";
|
|
1063
|
+
}
|
|
1064
|
+
if (!(c.startHour >= 0 && c.startHour < c.endHour && c.endHour <= 24)) {
|
|
1065
|
+
errors.hours = "Hours must satisfy 0 \u2264 start < end \u2264 24.";
|
|
1066
|
+
}
|
|
1025
1067
|
const days = [...c.days];
|
|
1026
|
-
if (!days.length
|
|
1027
|
-
|
|
1068
|
+
if (!days.length) errors.days = "Pick at least one day.";
|
|
1069
|
+
else if (!days.every((n) => Number.isInteger(n) && n >= 0 && n <= 6)) {
|
|
1070
|
+
errors.days = "Days must be weekday numbers, 0 (Sunday) through 6 (Saturday).";
|
|
1071
|
+
}
|
|
1072
|
+
if (typeof c.timezone !== "string" || !isValidTimeZone(c.timezone)) {
|
|
1073
|
+
errors.timezone = `"${String(c.timezone)}" is not a valid IANA timezone (for example "America/Los_Angeles").`;
|
|
1028
1074
|
}
|
|
1029
|
-
if (typeof c.
|
|
1030
|
-
|
|
1031
|
-
return { ...c, days };
|
|
1075
|
+
if (typeof c.summaryTemplate !== "string") errors.summaryTemplate = "Calendar summary template must be text.";
|
|
1076
|
+
return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value: { ...c, days } };
|
|
1032
1077
|
}
|
|
1033
1078
|
function slotWindow(now, windowDays) {
|
|
1034
1079
|
return { from: now, to: now + windowDays * 864e5 };
|