@contentrain/types 1.33.0 → 1.36.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.mjs CHANGED
@@ -625,6 +625,13 @@ function evaluateApproval(input) {
625
625
  //#region src/migrate-claim.ts
626
626
  /** Contract version carried in the payload as `v`. */
627
627
  const MIGRATE_STUDIO_CLAIM_VERSION = 1;
628
+ /**
629
+ * v2: "Migrate with Studio". No trial: the Studio year is part of the order's
630
+ * first invoice (Studio creates that checkout itself, server to server), and
631
+ * the claim names the customer's GitHub account so Studio can find or create
632
+ * the user without a sign-in. v1 stays valid for the claim-link flow.
633
+ */
634
+ const MIGRATE_STUDIO_CLAIM_VERSION_2 = 2;
628
635
  /** JWS `alg` header value. */
629
636
  const MIGRATE_STUDIO_CLAIM_ALG = "EdDSA";
630
637
  /** `iss` — who signs. */
@@ -643,6 +650,7 @@ const isObject = (x) => typeof x === "object" && x !== null && !Array.isArray(x)
643
650
  const isText = (x) => typeof x === "string" && x.trim().length > 0;
644
651
  const isSeconds = (x) => typeof x === "number" && Number.isInteger(x) && x > 0;
645
652
  const isFiniteNonNegative = (x) => typeof x === "number" && Number.isFinite(x) && x >= 0;
653
+ const isCents = (x) => typeof x === "number" && Number.isInteger(x) && x >= 0 && x <= 1e8;
646
654
  const LOCAL_HOSTS = new Set([
647
655
  "localhost",
648
656
  "127.0.0.1",
@@ -664,6 +672,18 @@ function isClaimOrigin(x) {
664
672
  function isCompactJws(x) {
665
673
  return typeof x === "string" && x.length <= 2048 && /^[\w-]+\.[\w-]+\.[\w-]+$/.test(x);
666
674
  }
675
+ /** A post-payment return address: https (http for localhost), no credentials or fragment; a query is fine. */
676
+ function isReturnUrl(x) {
677
+ if (typeof x !== "string" || x.length > 2048) return false;
678
+ let url;
679
+ try {
680
+ url = new URL(x);
681
+ } catch {
682
+ return false;
683
+ }
684
+ if (url.username || url.password || url.hash || url.hostname.endsWith(".")) return false;
685
+ return url.protocol === "https:" || url.protocol === "http:" && LOCAL_HOSTS.has(url.hostname);
686
+ }
667
687
  /** A fetchable export address: https (http for localhost), no credentials, query or fragment — nowhere for a secret. */
668
688
  function isExportUrl(x) {
669
689
  if (typeof x !== "string" || x.length > 2048) return false;
@@ -688,6 +708,21 @@ function isExportUrl(x) {
688
708
  * file upload instead.
689
709
  */
690
710
  function validateMigrateStudioClaim(input, options = {}) {
711
+ return validateClaim(input, options, 1);
712
+ }
713
+ /**
714
+ * The v2 counterpart of `validateMigrateStudioClaim`: same envelope, plan, repo
715
+ * and add-on checks, no `trial_days` (a v2 claim that carries one is refused),
716
+ * plus `github_user_id`, `email_verified`, `return_url` and `billing`.
717
+ */
718
+ function validateMigrateStudioClaimV2(input, options = {}) {
719
+ return validateClaim(input, options, 2);
720
+ }
721
+ /** Validate a claim of either version; read `result.claim.v` to tell them apart. */
722
+ function validateMigrateStudioClaimAny(input, options = {}) {
723
+ return (isObject(input) ? input.v : void 0) === 2 ? validateMigrateStudioClaimV2(input, options) : validateMigrateStudioClaim(input, options);
724
+ }
725
+ function validateClaim(input, options, version) {
691
726
  const errors = [];
692
727
  if (!isObject(input)) return {
693
728
  ok: false,
@@ -696,7 +731,7 @@ function validateMigrateStudioClaim(input, options = {}) {
696
731
  const x = input;
697
732
  if (x.iss !== "contentrain-migrate") errors.push("iss: unexpected issuer");
698
733
  if (x.aud !== "contentrain-studio") errors.push("aud: unexpected audience");
699
- if (x.v !== 1) errors.push("v: unsupported version");
734
+ if (x.v !== version) errors.push("v: unsupported version");
700
735
  for (const key of [
701
736
  "sub",
702
737
  "jti",
@@ -720,7 +755,16 @@ function validateMigrateStudioClaim(input, options = {}) {
720
755
  if (!isObject(e) || !isText(e.limit_key) || !isFiniteNonNegative(e.measured) || !isFiniteNonNegative(e.limit)) errors.push(`plan_evidence[${i}]: invalid`);
721
756
  else if (e.capability !== void 0 && !CAPABILITY_SET.has(e.capability)) errors.push(`plan_evidence[${i}].capability: unknown`);
722
757
  });
723
- if (typeof x.trial_days !== "number" || !Number.isInteger(x.trial_days) || x.trial_days < 1 || x.trial_days > 90) errors.push("trial_days: out of range");
758
+ if (version === 1) {
759
+ if (typeof x.trial_days !== "number" || !Number.isInteger(x.trial_days) || x.trial_days < 1 || x.trial_days > 90) errors.push("trial_days: out of range");
760
+ } else {
761
+ if (x.trial_days !== void 0) errors.push("trial_days: not part of v2");
762
+ if (typeof x.github_user_id !== "string" || !/^[1-9]\d{0,18}$/.test(x.github_user_id)) errors.push("github_user_id: invalid");
763
+ if (typeof x.email_verified !== "boolean") errors.push("email_verified: required");
764
+ if (!isReturnUrl(x.return_url)) errors.push("return_url: invalid");
765
+ const b = x.billing;
766
+ if (!isObject(b) || !isCents(b.migrate_fee_cents) || !isCents(b.quoted_total_cents) || b.quoted_total_cents <= 0 || b.currency !== "usd" || b.quoted_total_cents < b.migrate_fee_cents) errors.push("billing: invalid");
767
+ }
724
768
  const repo = x.repo;
725
769
  if (!isObject(repo) || repo.provider !== "github" || !isText(repo.owner) || !isText(repo.name) || repo.owner.includes("/") || repo.name.includes("/")) errors.push("repo: invalid");
726
770
  if (x.capabilities !== void 0) if (!Array.isArray(x.capabilities)) errors.push("capabilities: not an array");
@@ -766,6 +810,99 @@ function isMigrateStudioClaim(input) {
766
810
  const result = validateMigrateStudioClaim(input);
767
811
  return result.ok && !result.warnings;
768
812
  }
813
+ const MIGRATE_ACCOUNT_STATES = [
814
+ "none",
815
+ "covers",
816
+ "too_small"
817
+ ];
818
+ /** Plans in ascending order; a higher index carries more. */
819
+ const PLAN_RANK = {
820
+ starter: 0,
821
+ pro: 1
822
+ };
823
+ /**
824
+ * Check the signed request Studio receives. Pass `now` (seconds since the
825
+ * epoch) to also check the validity window. It does no cryptography, and it
826
+ * does not remember `jti`: Studio keeps a replay record for account-state
827
+ * requests, as it does for claims (a repeated `jti` is refused).
828
+ */
829
+ function validateMigrateAccountStateRequest(input, options = {}) {
830
+ if (!isObject(input)) return {
831
+ ok: false,
832
+ errors: ["payload: not an object"]
833
+ };
834
+ const x = input;
835
+ const errors = [];
836
+ if (x.iss !== "contentrain-migrate") errors.push("iss: unexpected issuer");
837
+ if (x.aud !== "contentrain-studio") errors.push("aud: unexpected audience");
838
+ if (!isText(x.jti)) errors.push("jti: required");
839
+ if (!isSeconds(x.iat)) errors.push("iat: invalid");
840
+ if (!isSeconds(x.exp)) errors.push("exp: invalid");
841
+ if (isSeconds(x.iat) && isSeconds(x.exp)) {
842
+ const ttl = x.exp - x.iat;
843
+ if (ttl <= 0) errors.push("exp: not after iat");
844
+ else if (ttl > 1800) errors.push("exp: lifetime too long");
845
+ if (options.now !== void 0) {
846
+ if (options.now >= x.exp + 60) errors.push("exp: expired");
847
+ if (x.iat > options.now + 60) errors.push("iat: in the future");
848
+ }
849
+ }
850
+ if (typeof x.github_user_id !== "string" || !/^[1-9]\d{0,18}$/.test(x.github_user_id)) errors.push("github_user_id: invalid");
851
+ if (!MIGRATE_STUDIO_PLANS.includes(x.plan)) errors.push("plan: unknown plan");
852
+ return errors.length === 0 ? {
853
+ ok: true,
854
+ request: x
855
+ } : {
856
+ ok: false,
857
+ errors
858
+ };
859
+ }
860
+ /**
861
+ * Check Studio's answer against the plan that was asked about (`requested`,
862
+ * required: an answer is only meaningful against its question), which is what
863
+ * Migrate does before it prices an Offer from it:
864
+ * - `none`: no `current_plan`; `plan` is the requested plan.
865
+ * - `too_small`: `plan` is the requested plan and `current_plan` is below it.
866
+ * - `covers`: `current_plan` is at least the requested plan, `plan` is that
867
+ * current plan, and nothing is added (`year1_cents` 0).
868
+ * Errors are the stable `field: problem` strings the claim validators use.
869
+ */
870
+ function validateMigrateAccountStateResponse(input, options) {
871
+ if (!isObject(input)) return {
872
+ ok: false,
873
+ errors: ["payload: not an object"]
874
+ };
875
+ const errors = [];
876
+ const planOk = MIGRATE_STUDIO_PLANS.includes(input.plan);
877
+ const currentOk = MIGRATE_STUDIO_PLANS.includes(input.current_plan);
878
+ if (!MIGRATE_ACCOUNT_STATES.includes(input.state)) errors.push("state: unknown");
879
+ if (!planOk) errors.push("plan: unknown plan");
880
+ if (!isCents(input.year1_cents)) errors.push("year1_cents: invalid");
881
+ else if (input.state === "covers" && input.year1_cents !== 0) errors.push("year1_cents: must be 0 when covers");
882
+ else if (input.state !== void 0 && input.state !== "covers" && input.year1_cents === 0) errors.push("year1_cents: must be > 0");
883
+ if (input.current_plan !== void 0 && !currentOk) errors.push("current_plan: unknown plan");
884
+ if (input.state === "none" && input.current_plan !== void 0) errors.push("current_plan: not allowed when none");
885
+ if ((input.state === "covers" || input.state === "too_small") && input.current_plan === void 0) errors.push("current_plan: required unless none");
886
+ const asked = options?.requested;
887
+ if (!MIGRATE_STUDIO_PLANS.includes(asked)) errors.push("requested: unknown plan");
888
+ else if (planOk) {
889
+ const plan = input.plan;
890
+ if (input.state === "covers") {
891
+ if (currentOk && PLAN_RANK[input.current_plan] < PLAN_RANK[asked]) errors.push("current_plan: below the requested plan");
892
+ if (currentOk && plan !== input.current_plan) errors.push("plan: must be the current plan when covers");
893
+ } else if (input.state === "none" || input.state === "too_small") {
894
+ if (plan !== asked) errors.push("plan: not the requested plan");
895
+ if (input.state === "too_small" && currentOk && PLAN_RANK[input.current_plan] >= PLAN_RANK[asked]) errors.push("current_plan: not below the requested plan");
896
+ }
897
+ }
898
+ return errors.length === 0 ? {
899
+ ok: true,
900
+ response: input
901
+ } : {
902
+ ok: false,
903
+ errors
904
+ };
905
+ }
769
906
  //#endregion
770
907
  //#region src/project-plan.ts
771
908
  const PROJECT_PLAN_FORMAT = "contentrain-project-plan@1";
@@ -799,7 +936,11 @@ const PLAN_TOKEN_ROLES = [
799
936
  "text-heading-2",
800
937
  "text-heading-3",
801
938
  "spacing-section",
802
- "color-link"
939
+ "color-link",
940
+ "color-page",
941
+ "color-card",
942
+ "shadow-card",
943
+ "spacing-card"
803
944
  ];
804
945
  const PLAN_VALUE_PATTERN = /^(?:field:[\w-]+|media:[\w-]+|ref:[\w-]+\.[\w-]+|href:(?:self|[\w-]+)|term:[\w-]+|ui:[\w.-]+|site:[\w-]+|menu:(?:primary|footer)|page:(?:base|current|total|breadcrumb)|const:(?:true|false|-?\d+(?:\.\d+)?|[a-z][a-z0-9_-]{0,31}))$/;
805
946
  const PLAN_STARTER_FEATURES = ["search"];
@@ -866,25 +1007,41 @@ function validateProjectPlan(plan) {
866
1007
  "cover"
867
1008
  ].includes(part)) || new Set(parts).size !== parts.length) errors.push("site.post.header lists a part twice or one the starter does not have");
868
1009
  if (!Number.isSafeInteger(site.post.more) || site.post.more < 0 || site.post.more > 20) errors.push("site.post.more is not a count from 0 to 20");
1010
+ if (site.post.moreIncludesCurrent !== void 0 && typeof site.post.moreIncludesCurrent !== "boolean") errors.push("site.post.moreIncludesCurrent is not true or false");
869
1011
  }
870
1012
  if (site?.lists && ![
871
1013
  "cards",
872
1014
  "list",
873
1015
  "full"
874
1016
  ].includes(site.lists.display)) errors.push(`site.lists.display ${site.lists.display} is not cards, list or full`);
1017
+ if (site?.lists?.tone !== void 0 && site.lists.tone !== "muted") errors.push(`site.lists.tone ${String(site.lists.tone)} is not muted`);
875
1018
  if (site?.lists?.text !== void 0 && !CSS_LENGTH.test(site.lists.text)) errors.push(`site.lists.text ${site.lists.text} is not a CSS size`);
1019
+ for (const [route, layout] of Object.entries(site?.entryLayouts ?? {})) {
1020
+ if (typeof layout?.adjacent !== "boolean") errors.push(`site.entryLayouts.${route}.adjacent is not true or false`);
1021
+ if (layout?.more !== void 0 && (!Number.isSafeInteger(layout.more) || layout.more < 0 || layout.more > 20)) errors.push(`site.entryLayouts.${route}.more is not a count from 0 to 20`);
1022
+ if (layout?.moreIncludesCurrent !== void 0 && typeof layout.moreIncludesCurrent !== "boolean") errors.push(`site.entryLayouts.${route}.moreIncludesCurrent is not true or false`);
1023
+ }
876
1024
  const chrome = site?.chrome;
877
1025
  if (chrome?.brand !== void 0 && !CSS_LENGTH.test(chrome.brand)) errors.push(`site.chrome.brand ${chrome.brand} is not a CSS size`);
878
1026
  if (chrome?.tagline !== void 0 && typeof chrome.tagline !== "boolean") errors.push("site.chrome.tagline is not a boolean");
879
1027
  if (chrome?.titleLinks !== void 0 && typeof chrome.titleLinks !== "boolean") errors.push("site.chrome.titleLinks is not a boolean");
880
1028
  if (chrome?.navLinks !== void 0 && typeof chrome.navLinks !== "boolean") errors.push("site.chrome.navLinks is not a boolean");
881
1029
  if (chrome?.footerAlign !== void 0 && !["start", "center"].includes(chrome.footerAlign)) errors.push(`site.chrome.footerAlign ${chrome.footerAlign} is not start or center`);
882
- for (const key of ["frame", "listFrame"]) {
1030
+ for (const key of [
1031
+ "frame",
1032
+ "listFrame",
1033
+ "postFrame"
1034
+ ]) {
883
1035
  const steps = chrome?.[key];
884
1036
  if (steps === void 0) continue;
885
1037
  if (!Array.isArray(steps) || steps.length === 0 || steps.length > 8) errors.push(`site.chrome.${key} is not a list of 1–8 steps`);
886
1038
  else if (steps.some((step, i) => !Number.isSafeInteger(step?.min) || !Number.isSafeInteger(step?.width) || step.min < 1 || step.width < 1 || step.min > 1e4 || step.width > 1e4 || i > 0 && step.min <= steps[i - 1].min)) errors.push(`site.chrome.${key} steps are not whole pixel widths in ascending order of min`);
887
1039
  }
1040
+ if (chrome?.listColumns !== void 0) {
1041
+ const steps = chrome.listColumns;
1042
+ if (!Array.isArray(steps) || steps.length === 0 || steps.length > 8) errors.push("site.chrome.listColumns is not a list of 1–8 steps");
1043
+ else if (steps.some((step, i) => !Number.isSafeInteger(step?.min) || !Number.isSafeInteger(step?.columns) || step.min < 1 || step.min > 1e4 || step.columns < 1 || step.columns > 6 || i > 0 && step.min <= steps[i - 1].min)) errors.push("site.chrome.listColumns steps are not a whole pixel min in ascending order and 1–6 columns");
1044
+ }
888
1045
  if (chrome?.copyright !== void 0 && (typeof chrome.copyright !== "string" || !chrome.copyright.trim() || chrome.copyright.length > 200 || /[<>]/.test(chrome.copyright))) errors.push("site.chrome.copyright is not a line of plain text (1–200 characters, no markup)");
889
1046
  const footer = site?.menus?.footer;
890
1047
  if (typeof footer === "string") {
@@ -2139,6 +2296,6 @@ function serializeMarkdownFrontmatter(data, body) {
2139
2296
  return lines.join("\n");
2140
2297
  }
2141
2298
  //#endregion
2142
- export { APPROVAL_GATES, APPROVAL_MODES, CANONICAL_JSON, CAPABILITY_KEYS, CHROME_BODY_SLOT, CHROME_COMPONENT_CLOSE, CHROME_COMPONENT_OPEN, CHROME_IF_CLOSE, CHROME_IF_OPEN, CHROME_REPEAT_CLOSE, CHROME_REPEAT_OPEN, COMMENTS_EXPORT_FORMAT, COMPONENT_TYPES, CONTENTRAIN_BRANCH, CONTENTRAIN_DIR, DEFAULT_APPROVAL_POLICY, DICTIONARY_TITLE_FIELD, ENTRY_ID_PATTERN, EXECUTION_CONTRACT_VERSION, INTEGRATION_CATEGORIES, INTEGRATION_EVIDENCE_KINDS, LEGACY_CSS_LAYER, LIST_ITEMS_SLOT, LOCALE_PATTERN, LOCAL_CAPABILITIES, MIGRATE_STUDIO_CLAIM_ALG, MIGRATE_STUDIO_CLAIM_AUDIENCE, MIGRATE_STUDIO_CLAIM_CLOCK_SKEW_SECONDS, MIGRATE_STUDIO_CLAIM_ISSUER, MIGRATE_STUDIO_CLAIM_MAX_TRIAL_DAYS, MIGRATE_STUDIO_CLAIM_MAX_TTL_SECONDS, MIGRATE_STUDIO_CLAIM_VERSION, MIGRATE_STUDIO_PLANS, MIGRATION_CONTRACT_VERSION, MODEL_EXTENSION_KEYS, MODEL_FIELD_ORDER, PAGE_BODY_KINDS, PATH_PATTERNS, PLAN_BEHAVIOR_REASON, PLAN_SECTION_RULE, PLAN_STARTER_FEATURES, PLAN_TOKEN_ROLES, PLAN_VALUE_PATTERN, PROJECT_PLAN_FORMAT, RAW_MARK_SUFFIX, RESERVED_PATHS, RISK_CLASSES, RUN_STATUSES, SCHEDULE_KINDS, SECRET_PATTERNS, SEO_PROVIDERS, SLUG_PATTERN, SOURCE_ACCESS_LADDER, SOURCE_DELTA_OPS, TERMINAL_RUN_STATUSES, TEXT_CANDIDATE_KINDS, TEXT_EXCLUDE_REASONS, TITLE_FIELD_TYPES, approversFor, canonicalStringify, commentsExportSource, componentSlot, computePlanHash, conflictId, describeModelLocaleScope, detectSecrets, effectiveRisk, evaluateApproval, fieldDepth, footerMenusOf, generateEntryId, highestRisk, isMediaType, isMigrateStudioClaim, isRepoRelativePath, isReservedPath, isStoredMediaPath, isTerminalRunStatus, isTitleFieldType, looksLikeCredential, orderedFieldNames, parseFrontmatterScalar, parseFrontmatterScalarString, parseMarkdownFrontmatter, planHashPayload, requiredApprovals, resolveFieldLabel, resolveModelLocales, rewriteEntryMedia, rewriteFieldMedia, rewriteMarkdownMedia, rewriteMediaUrl, riskRank, sectionFieldName, serializeMarkdownFrontmatter, sortKeys, splitFrontmatterList, stableHash, titleFieldTarget, titleFieldValue, toDeliveryUrl, validateAccept, validateEntryId, validateFieldValue, validateHandoffCommentsExport, validateLocale, validateMigrateStudioClaim, validateModelLocales, validateProjectPlan, validateSemanticType, validateSlug };
2299
+ export { APPROVAL_GATES, APPROVAL_MODES, CANONICAL_JSON, CAPABILITY_KEYS, CHROME_BODY_SLOT, CHROME_COMPONENT_CLOSE, CHROME_COMPONENT_OPEN, CHROME_IF_CLOSE, CHROME_IF_OPEN, CHROME_REPEAT_CLOSE, CHROME_REPEAT_OPEN, COMMENTS_EXPORT_FORMAT, COMPONENT_TYPES, CONTENTRAIN_BRANCH, CONTENTRAIN_DIR, DEFAULT_APPROVAL_POLICY, DICTIONARY_TITLE_FIELD, ENTRY_ID_PATTERN, EXECUTION_CONTRACT_VERSION, INTEGRATION_CATEGORIES, INTEGRATION_EVIDENCE_KINDS, LEGACY_CSS_LAYER, LIST_ITEMS_SLOT, LOCALE_PATTERN, LOCAL_CAPABILITIES, MIGRATE_ACCOUNT_STATES, MIGRATE_STUDIO_CLAIM_ALG, MIGRATE_STUDIO_CLAIM_AUDIENCE, MIGRATE_STUDIO_CLAIM_CLOCK_SKEW_SECONDS, MIGRATE_STUDIO_CLAIM_ISSUER, MIGRATE_STUDIO_CLAIM_MAX_TRIAL_DAYS, MIGRATE_STUDIO_CLAIM_MAX_TTL_SECONDS, MIGRATE_STUDIO_CLAIM_VERSION, MIGRATE_STUDIO_CLAIM_VERSION_2, MIGRATE_STUDIO_PLANS, MIGRATION_CONTRACT_VERSION, MODEL_EXTENSION_KEYS, MODEL_FIELD_ORDER, PAGE_BODY_KINDS, PATH_PATTERNS, PLAN_BEHAVIOR_REASON, PLAN_SECTION_RULE, PLAN_STARTER_FEATURES, PLAN_TOKEN_ROLES, PLAN_VALUE_PATTERN, PROJECT_PLAN_FORMAT, RAW_MARK_SUFFIX, RESERVED_PATHS, RISK_CLASSES, RUN_STATUSES, SCHEDULE_KINDS, SECRET_PATTERNS, SEO_PROVIDERS, SLUG_PATTERN, SOURCE_ACCESS_LADDER, SOURCE_DELTA_OPS, TERMINAL_RUN_STATUSES, TEXT_CANDIDATE_KINDS, TEXT_EXCLUDE_REASONS, TITLE_FIELD_TYPES, approversFor, canonicalStringify, commentsExportSource, componentSlot, computePlanHash, conflictId, describeModelLocaleScope, detectSecrets, effectiveRisk, evaluateApproval, fieldDepth, footerMenusOf, generateEntryId, highestRisk, isMediaType, isMigrateStudioClaim, isRepoRelativePath, isReservedPath, isStoredMediaPath, isTerminalRunStatus, isTitleFieldType, looksLikeCredential, orderedFieldNames, parseFrontmatterScalar, parseFrontmatterScalarString, parseMarkdownFrontmatter, planHashPayload, requiredApprovals, resolveFieldLabel, resolveModelLocales, rewriteEntryMedia, rewriteFieldMedia, rewriteMarkdownMedia, rewriteMediaUrl, riskRank, sectionFieldName, serializeMarkdownFrontmatter, sortKeys, splitFrontmatterList, stableHash, titleFieldTarget, titleFieldValue, toDeliveryUrl, validateAccept, validateEntryId, validateFieldValue, validateHandoffCommentsExport, validateLocale, validateMigrateAccountStateRequest, validateMigrateAccountStateResponse, validateMigrateStudioClaim, validateMigrateStudioClaimAny, validateMigrateStudioClaimV2, validateModelLocales, validateProjectPlan, validateSemanticType, validateSlug };
2143
2300
 
2144
2301
  //# sourceMappingURL=index.mjs.map