@palbase/backend 14.1.0 → 14.3.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/dist/index.js CHANGED
@@ -595,6 +595,82 @@ var PROVIDER_CATALOG = {
595
595
  secrets: ["authToken"]
596
596
  }
597
597
  };
598
+ var DEFAULT_TEMPLATE_LOCALE = "en";
599
+ function extractVariables(...sources) {
600
+ const found = /* @__PURE__ */ new Set();
601
+ for (const src of sources) {
602
+ if (!src) continue;
603
+ for (const match of src.matchAll(/\{\{\{?\s*([^{}]+?)\s*\}?\}\}/g)) {
604
+ const token = (match[1] ?? "").trim();
605
+ if (token === "" || "#/^!>&".includes(token.charAt(0)) || token === "else") continue;
606
+ if (/\s/.test(token)) continue;
607
+ const root = token.split(".")[0] ?? "";
608
+ if (root === "" || root === "this" || root.startsWith("@")) continue;
609
+ found.add(root);
610
+ }
611
+ }
612
+ return [...found].sort();
613
+ }
614
+ function buildEmailTemplate(slug, opts) {
615
+ const row = (locale, c) => {
616
+ if (!c.subject) throw new Error(`notifications: email template "${slug}" (${locale}) needs a subject`);
617
+ if (!c.html) throw new Error(`notifications: email template "${slug}" (${locale}) needs an html body`);
618
+ const def = {
619
+ slug,
620
+ locale,
621
+ subject: c.subject,
622
+ html_body: c.html,
623
+ variables: c.variables ? [...c.variables] : extractVariables(c.subject, c.html, c.text)
624
+ };
625
+ if (c.text !== void 0) def.text_body = c.text;
626
+ return def;
627
+ };
628
+ const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];
629
+ for (const [locale, content] of Object.entries(opts.locales ?? {})) {
630
+ rows.push(row(locale, content));
631
+ }
632
+ return rows;
633
+ }
634
+ function buildSmsTemplate(slug, opts) {
635
+ const row = (locale, c) => {
636
+ if (!c.body) throw new Error(`notifications: sms template "${slug}" (${locale}) needs a body`);
637
+ return {
638
+ slug,
639
+ locale,
640
+ body: c.body,
641
+ variables: c.variables ? [...c.variables] : extractVariables(c.body)
642
+ };
643
+ };
644
+ const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];
645
+ for (const [locale, content] of Object.entries(opts.locales ?? {})) {
646
+ rows.push(row(locale, content));
647
+ }
648
+ return rows;
649
+ }
650
+ function buildTemplates(input) {
651
+ const out = { email: [], sms: [] };
652
+ const seen = /* @__PURE__ */ new Set();
653
+ const claim = (channel, slug, locale) => {
654
+ const key = `${channel}/${slug}/${locale}`;
655
+ if (seen.has(key)) {
656
+ throw new Error(`notifications: ${channel} template "${slug}" declares locale "${locale}" twice`);
657
+ }
658
+ seen.add(key);
659
+ };
660
+ for (const [slug, opts] of Object.entries(input.email ?? {})) {
661
+ for (const row of buildEmailTemplate(slug, opts)) {
662
+ claim("email", row.slug, row.locale);
663
+ out.email.push(row);
664
+ }
665
+ }
666
+ for (const [slug, opts] of Object.entries(input.sms ?? {})) {
667
+ for (const row of buildSmsTemplate(slug, opts)) {
668
+ claim("sms", row.slug, row.locale);
669
+ out.sms.push(row);
670
+ }
671
+ }
672
+ return out;
673
+ }
598
674
  function buildProvider(name, opts) {
599
675
  const entry = PROVIDER_CATALOG[name];
600
676
  const src = { ...opts };
@@ -636,7 +712,8 @@ function defineNotifications(input) {
636
712
  __config: NOTIFICATIONS_CONFIG_KIND,
637
713
  push: {},
638
714
  email: {},
639
- sms: {}
715
+ sms: {},
716
+ templates: buildTemplates(input.templates ?? {})
640
717
  };
641
718
  const push = input.push ?? {};
642
719
  if (push.apns !== void 0) config.push.apns = buildProvider("apns", push.apns);
@@ -826,6 +903,33 @@ function flag(opts) {
826
903
  );
827
904
  }
828
905
  }
906
+ let conditions = null;
907
+ if (opts.conditions !== void 0) {
908
+ if (!Array.isArray(opts.conditions)) {
909
+ throw new Error("flag conditions must be an array of { when, value }");
910
+ }
911
+ const compiled = [];
912
+ for (const [i, branch] of opts.conditions.entries()) {
913
+ if (branch === null || typeof branch !== "object") {
914
+ throw new Error(`flag condition ${i} must be an object { when, value }`);
915
+ }
916
+ if (typeof branch.when !== "string" || branch.when.trim().length === 0) {
917
+ throw new Error(`flag condition ${i} needs a non-empty "when" expression`);
918
+ }
919
+ if (!valueMatchesType(type, branch.value)) {
920
+ throw new Error(
921
+ `flag condition ${i} value ${JSON.stringify(branch.value)} does not match type "${type}"`
922
+ );
923
+ }
924
+ if (variants !== null && !variants.includes(branch.value)) {
925
+ throw new Error(
926
+ `flag condition ${i} value ${JSON.stringify(branch.value)} is not one of its variants [${variants.map((v) => JSON.stringify(v)).join(", ")}]`
927
+ );
928
+ }
929
+ compiled.push({ when: branch.when.trim(), value: branch.value });
930
+ }
931
+ conditions = compiled.length > 0 ? compiled : null;
932
+ }
829
933
  let description = null;
830
934
  if (opts.description !== void 0) {
831
935
  if (typeof opts.description !== "string") {
@@ -838,6 +942,7 @@ function flag(opts) {
838
942
  type,
839
943
  default: opts.default,
840
944
  variants,
945
+ conditions,
841
946
  description
842
947
  };
843
948
  }
@@ -1541,6 +1646,7 @@ export {
1541
1646
  Client,
1542
1647
  Conflict,
1543
1648
  Controller,
1649
+ DEFAULT_TEMPLATE_LOCALE,
1544
1650
  Database,
1545
1651
  Delete,
1546
1652
  Documents,
@@ -1616,6 +1722,7 @@ export {
1616
1722
  documents,
1617
1723
  entitlementFor,
1618
1724
  enumType,
1725
+ extractVariables,
1619
1726
  flag,
1620
1727
  getErrorRegistry,
1621
1728
  getJobConfig,