waha-shared 1.0.552 → 1.0.554

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 (27) hide show
  1. package/dist/chunks/{chunk-7VYOSR3V.mjs → chunk-46VSKJAN.mjs} +0 -188
  2. package/dist/chunks/{chunk-RQR7ADQ3.mjs → chunk-5JMRXTQB.mjs} +3 -1
  3. package/dist/chunks/{chunk-44FF5O3D.mjs → chunk-B6C4GGOM.mjs} +1 -1
  4. package/dist/chunks/{chunk-7HGUA25M.mjs → chunk-IYDI5F2O.mjs} +1 -2
  5. package/dist/chunks/{chunk-RKEA5BP2.mjs → chunk-TGVLQAXS.mjs} +3 -3
  6. package/dist/chunks/{chunk-FBVDZGXA.mjs → chunk-VYO3H52S.mjs} +3 -1
  7. package/dist/chunks/{chunk-KCYVCCJ5.mjs → chunk-YOWQLQC3.mjs} +1 -2
  8. package/dist/data/curriculumFoundations/curriculumFoundations.zod.d.ts +1 -1
  9. package/dist/data/curriculumFoundations/curriculumFoundations.zod.mjs +1 -1
  10. package/dist/data/curriculumFoundations/index.d.ts +1 -1
  11. package/dist/data/curriculumFoundations/index.mjs +2 -2
  12. package/dist/data/curriculumFoundations.mjs +2 -2
  13. package/dist/data/curriculumTopics/curriculumTopics.zod.d.ts +1 -1
  14. package/dist/data/curriculumTopics/curriculumTopics.zod.mjs +1 -1
  15. package/dist/data/curriculumTopics/index.d.ts +1 -1
  16. package/dist/data/curriculumTopics/index.mjs +2 -2
  17. package/dist/data/curriculumTopics.mjs +2 -2
  18. package/dist/data/translationsSet/index.mjs +1 -1
  19. package/dist/data/translationsSet.mjs +1 -1
  20. package/dist/functions/crowdin.d.ts +104 -13
  21. package/dist/functions/crowdin.mjs +99 -14
  22. package/dist/functions/languages.mjs +6 -6
  23. package/dist/functions/scripturePassages.mjs +7 -7
  24. package/dist/functions/sentry.d.ts +1 -0
  25. package/dist/functions/sentry.mjs +6 -0
  26. package/dist/functions/sets.mjs +7 -7
  27. package/package.json +1 -1
@@ -8926,194 +8926,6 @@ var require_translationsSet = __commonJS({
8926
8926
  }
8927
8927
  ],
8928
8928
  eng: [
8929
- {
8930
- lessonTitles: {
8931
- "01.063.001": "Creation",
8932
- "01.063.002": "Creation of Humans",
8933
- "01.063.003": "Humans Disobey God",
8934
- "01.063.004": "God Destroys an Evil Humanity",
8935
- "01.063.005": "Tower of Babel",
8936
- "01.063.006": "Abraham Trusted God",
8937
- "01.063.007": "Abraham Obeyed God",
8938
- "01.063.008": "God's Call to Moses",
8939
- "01.063.009": "The Passover Sacrifice",
8940
- "01.063.010": "The Ten Commandments and Sacrifice",
8941
- "01.063.011": "Cycle of Disobedience",
8942
- "01.063.012": "The Suffering Servant of God",
8943
- "01.063.013": "The Promised Saviour",
8944
- "01.063.014": "The Birth of Jesus"
8945
- },
8946
- pauseAndDiscuss: "Pause now and discuss.",
8947
- setDescription: "Start your journey toward discovering God by learning how He created the universe and everything in it. Find out how God began His relationship with mankind and what went wrong early on. These lessons give an overview of God\u2019s loving character and our need for forgiveness.",
8948
- setId: "01.063",
8949
- setTitle: "From Creation to the Birth of Jesus"
8950
- },
8951
- {
8952
- lessonTitles: {
8953
- "01.064.001": "John Testifies of the Saviour",
8954
- "01.064.002": "Temptation and Ministry of Jesus",
8955
- "01.064.003": "Jesus Heals and Forgives",
8956
- "01.064.004": "Jesus' Power ",
8957
- "01.064.005": "Forgiveness & Sacrifice",
8958
- "01.064.006": "Love God and Love Your Neighbor",
8959
- "01.064.007": "God Seeks the Lost",
8960
- "01.064.008": "Different Responses to God",
8961
- "01.064.009": "Jesus' Power Over Death",
8962
- "01.064.010": "Jesus' Humility",
8963
- "01.064.011": "Passover with the Disciples",
8964
- "01.064.012": "Jesus Arrested",
8965
- "01.064.013": "The Crucifixion",
8966
- "01.064.014": "The Resurrection and Ascension",
8967
- "01.064.015": "Jesus in Heaven"
8968
- },
8969
- setDescription: "Was Jesus a mighty prophet, a wise teacher, or something even more? These lessons introduce Jesus Christ as He demonstrates how we can be right with God and find the peace so many of us have been looking for.",
8970
- setId: "01.064",
8971
- setTitle: "The Life and Message of Jesus"
8972
- },
8973
- {
8974
- lessonTitles: {
8975
- "01.065.001": "Who is Jesus?",
8976
- "01.065.002": "What does Jesus offer you and ask you?",
8977
- "01.065.003": "What is the result of faith in Jesus?",
8978
- "01.065.004": "What is the price of following Jesus?",
8979
- "01.065.005": "Should we expect persecution?",
8980
- "01.065.006": "What is your response? ",
8981
- "01.065.007": "What does Baptism mean?",
8982
- "01.065.008": "What are His promises for His followers?",
8983
- "01.065.009": "How will God help us? ",
8984
- "01.065.010": "What does He tell us to do?"
8985
- },
8986
- setDescription: "As we begin to understand who Jesus is and what He did, it becomes clear we need to choose how to respond to Him. These lessons help ensure you know everything you need in order to make that big decision.",
8987
- setId: "01.065",
8988
- setTitle: "Invitation of Jesus"
8989
- },
8990
- {
8991
- lessonTitles: {
8992
- "01.066.001": "Disciples Love God and Love Others",
8993
- "01.066.002": "Disciples Are Forgiven",
8994
- "01.066.003": "Disciples Are Children of God",
8995
- "01.066.004": "Disciples Seek our Father",
8996
- "01.066.005": "Disciples Rely on God's Word",
8997
- "01.066.006": "Disciples Are Led by God",
8998
- "01.066.007": "Disciples Obey Jesus and Fish for People",
8999
- "01.066.008": "Disciples Abide and Bear Fruit in Jesus",
9000
- "01.066.009": "Disciples Live by the Spirit",
9001
- "01.066.010": "Disciples Cannot be Separated from God's Love"
9002
- },
9003
- setDescription: "What does it mean to become a disciple of Jesus? How should your life be different now compared to before you encountered Him? These lessons help answer any questions you may have about being a disciple.",
9004
- setId: "01.066",
9005
- setTitle: "Being Disciples"
9006
- },
9007
- {
9008
- lessonTitles: {
9009
- "01.067.001": "The Church is the Body of Christ",
9010
- "01.067.002": "The Church is the Bride of Christ",
9011
- "01.067.003": "The Church is God\u2019s Family",
9012
- "01.067.004": "The Church is a Spiritual Temple and Priests",
9013
- "01.067.005": "The Church is United",
9014
- "01.067.006": "The Church is Guided by the Spirit",
9015
- "01.067.007": "The Church is God's Community",
9016
- "01.067.008": "The Church Praises God",
9017
- "01.067.009": "The Church Serves One Another",
9018
- "01.067.010": "The Church Does Signs and Wonders by the Spirit",
9019
- "01.067.011": "The Church Gives Generously",
9020
- "01.067.012": "The Church Remembers Christ's Sacrifice"
9021
- },
9022
- setDescription: "One of the first things we realize when we become a disciple of Jesus is that we aren\u2019t the only ones. There are a lot of other disciples out there, known collectively as the Church. These lessons help you learn what the Bible says about the Church and why it\u2019s important.",
9023
- setId: "01.067",
9024
- setTitle: "Being a Jesus Community"
9025
- },
9026
- {
9027
- lessonTitles: {
9028
- "01.068.001": "Jesus as Servant",
9029
- "01.068.002": "Jesus talks about Leadership",
9030
- "01.068.003": "What do good leaders do?",
9031
- "01.068.004": "What do bad leaders do?",
9032
- "01.068.005": "Jesus' Example as the Good Shepherd",
9033
- "01.068.006": "Paul's Example ",
9034
- "01.068.007": "Faithfulness and Multiplying",
9035
- "01.068.008": "Equipping the Disciples",
9036
- "01.068.009": "Paul's Instructions to Leaders",
9037
- "01.068.010": "A Sacrificed Life",
9038
- "01.068.011": "Leadership Qualifications",
9039
- "01.068.012": "Multiply Leaders"
9040
- },
9041
- setDescription: "As a disciple of Jesus, you have been given the Holy Spirit, and that makes you a leader. Whether God guides you to lead in your workplace, the Church, or even just your family it is important to know what the Bible says about leadership. These lessons will help you lead in everyday life.",
9042
- setId: "01.068",
9043
- setTitle: "Being Leaders"
9044
- },
9045
- {
9046
- lessonTitles: {
9047
- "01.069.001": "Disciples Seek God",
9048
- "01.069.002": "Disciples Are Blessed by God",
9049
- "01.069.003": "Disciples Seek God's Kingdom",
9050
- "01.069.004": "Disciples Will Sacrifice to Follow Jesus",
9051
- "01.069.005": "Disciples Go into the Harvest",
9052
- "01.069.006": "Disciples Go with Jesus' Authority",
9053
- "01.069.007": "Disciples Fight with God's Word",
9054
- "01.069.008": "Disciples Live by the Spirit's Power",
9055
- "01.069.009": "Disciples Put Off the Old, Put on the New",
9056
- "01.069.010": " Disciples Confess Sins ",
9057
- "01.069.011": "Disciples Forgive others as the Lord forgives them",
9058
- "01.069.012": "Disciples Put on God's Armor"
9059
- },
9060
- setDescription: "Being a disciple is not just a one-time experience. It is a new way of life that involves growing and learning to be more like Jesus every day. These lessons will guide you into deeper discussions about what it really means to live as disciples of Jesus.",
9061
- setId: "01.069",
9062
- setTitle: "Growing as Disciples"
9063
- },
9064
- {
9065
- lessonTitles: {
9066
- "01.070.001": "The Church Belongs to God",
9067
- "01.070.002": "The Church Is the Household of God",
9068
- "01.070.003": "The Church Praises God",
9069
- "01.070.004": "The Church Helps Each Other",
9070
- "01.070.005": "The Church Serves Each Other",
9071
- "01.070.006": "The Church Prays Together",
9072
- "01.070.007": "The Church Prays For Each Other",
9073
- "01.070.008": "The Church Gives Sacrificially",
9074
- "01.070.009": "The Church Cannot Lie to God",
9075
- "01.070.010": "The Church Deals with Sin",
9076
- "01.070.011": "The Church Serves Others",
9077
- "01.070.012": "The Church Sends Workers Out"
9078
- },
9079
- setDescription: "If you\u2019ve been meeting for some time now, you might be wondering if God has something more for your church. What does it look like to really get serious about serving God and advancing His Kingdom? These lessons will shed more light on church growth.",
9080
- setId: "01.070",
9081
- setTitle: "Growing as a Jesus Community"
9082
- },
9083
- {
9084
- lessonTitles: {
9085
- "01.071.001": "Leaders Point People to Jesus",
9086
- "01.071.002": "Leaders Obey God in Everything",
9087
- "01.071.003": "Leaders Obey and Teach others to Obey",
9088
- "01.071.004": "Leaders Pray for Followers",
9089
- "01.071.005": "Leaders Judge Rightly",
9090
- "01.071.006": "Leaders Follow God's Wisdom",
9091
- "01.071.007": "Leaders are Good Stewards",
9092
- "01.071.008": "Leaders Sometimes Stumble but Can Still Serve",
9093
- "01.071.009": "Leaders Warn and Encourage",
9094
- "01.071.010": "Leaders Communicate Across Cultures",
9095
- "01.071.011": "Leaders Have Faith and Endurance",
9096
- "01.071.012": "Leaders Give Up Their Rights"
9097
- },
9098
- setDescription: "If you are living life as a disciple that makes disciples, then by now you probably realize you need to grow as a more capable leader. These lessons will tackle some of the most difficult questions of leadership, and help you understand the wisdom the Bible holds for those who serve others.",
9099
- setId: "01.071",
9100
- setTitle: "Growing as Leaders"
9101
- },
9102
- {
9103
- lessonTitles: {
9104
- "02.073.001": "Hope for the Rejected",
9105
- "02.073.002": "Hope for the Non-religious",
9106
- "02.073.003": "Hope for the Sick and Sinful",
9107
- "02.073.004": "Hope for the Religious",
9108
- "02.073.005": "Hope Changes Lives",
9109
- "02.073.006": "Hope Forgives",
9110
- "02.073.007": "Hungry for Hope",
9111
- "02.073.008": "Hope is Waiting for You"
9112
- },
9113
- setId: "02.073",
9114
- setTag: "Truth",
9115
- setTitle: "Hope"
9116
- },
9117
8929
  {
9118
8930
  lessonTitles: {
9119
8931
  "03.005.001": "Vision",
@@ -3,7 +3,9 @@ import { z } from "zod";
3
3
  var CurriculumTopics = z.array(
4
4
  z.object({
5
5
  curriculumId: z.string(),
6
- crowdinProjectId: z.string(),
6
+ crowdinProjectId: z.string().optional().describe(
7
+ "The Crowdin project for this curriculum's title translations. Leave it out when the curriculum has no titles of its own, like ASL, whose sets take their titles from the main set with the same name. Prep and the Crowdin config then skip it."
8
+ ),
7
9
  sets: z.array(z.string()).describe(
8
10
  "An array of set ids that make up this topics curriculum. Set ids must be linked to valid sets present in data/sets.json."
9
11
  )
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-PV7LVBQJ.mjs";
4
4
  import {
5
5
  numerals
6
- } from "./chunk-RKEA5BP2.mjs";
6
+ } from "./chunk-TGVLQAXS.mjs";
7
7
  import {
8
8
  getBibleInfo
9
9
  } from "./chunk-LZ7M5WP7.mjs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CurriculumFoundations
3
- } from "./chunk-FBVDZGXA.mjs";
3
+ } from "./chunk-VYO3H52S.mjs";
4
4
  import {
5
5
  __commonJS
6
6
  } from "./chunk-5AVXA5JL.mjs";
@@ -66,7 +66,6 @@ var require_curriculumFoundations = __commonJS({
66
66
  },
67
67
  {
68
68
  curriculumId: "ase",
69
- crowdinProjectId: "549537",
70
69
  sets: [
71
70
  "01.063",
72
71
  "01.064",
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  curriculumFoundations
3
- } from "./chunk-7HGUA25M.mjs";
3
+ } from "./chunk-IYDI5F2O.mjs";
4
4
  import {
5
5
  curriculumTopics
6
- } from "./chunk-KCYVCCJ5.mjs";
6
+ } from "./chunk-YOWQLQC3.mjs";
7
7
  import {
8
8
  curriculumQuestions
9
9
  } from "./chunk-LODLCRYD.mjs";
@@ -24,7 +24,7 @@ import {
24
24
  } from "./chunk-VSLJCKFL.mjs";
25
25
  import {
26
26
  translationsSet
27
- } from "./chunk-7VYOSR3V.mjs";
27
+ } from "./chunk-46VSKJAN.mjs";
28
28
  import {
29
29
  translationsQuestion
30
30
  } from "./chunk-OCE4ZKES.mjs";
@@ -3,7 +3,9 @@ import { z } from "zod";
3
3
  var CurriculumFoundations = z.array(
4
4
  z.object({
5
5
  curriculumId: z.string(),
6
- crowdinProjectId: z.string(),
6
+ crowdinProjectId: z.string().optional().describe(
7
+ "The Crowdin project for this curriculum's title translations. Leave it out when the curriculum has no titles of its own, like ASL, whose sets take their titles from the main set with the same name. Prep and the Crowdin config then skip it."
8
+ ),
7
9
  sets: z.array(z.string()).describe(
8
10
  "An array of set ids that make up this foundations curriculum. Set ids must be linked to valid sets present in data/sets.json."
9
11
  )
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CurriculumTopics
3
- } from "./chunk-RQR7ADQ3.mjs";
3
+ } from "./chunk-5JMRXTQB.mjs";
4
4
  import {
5
5
  __commonJS
6
6
  } from "./chunk-5AVXA5JL.mjs";
@@ -15,7 +15,6 @@ var require_curriculumTopics = __commonJS({
15
15
  data: [
16
16
  {
17
17
  curriculumId: "ase",
18
- crowdinProjectId: "549537",
19
18
  sets: ["02.073", "02.075", "02.076", "02.078", "02.079", "02.080"]
20
19
  },
21
20
  {
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  export declare const CurriculumFoundations: z.ZodArray<z.ZodObject<{
3
3
  curriculumId: z.ZodString;
4
- crowdinProjectId: z.ZodString;
4
+ crowdinProjectId: z.ZodOptional<z.ZodString>;
5
5
  sets: z.ZodArray<z.ZodString>;
6
6
  }, z.core.$strict>>;
7
7
  export type CurriculumFoundations = z.infer<typeof CurriculumFoundations>;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CurriculumFoundations
3
- } from "../../chunks/chunk-FBVDZGXA.mjs";
3
+ } from "../../chunks/chunk-VYO3H52S.mjs";
4
4
  import "../../chunks/chunk-5AVXA5JL.mjs";
5
5
  export {
6
6
  CurriculumFoundations
@@ -1,5 +1,5 @@
1
1
  export declare const curriculumFoundations: {
2
2
  curriculumId: string;
3
- crowdinProjectId: string;
4
3
  sets: string[];
4
+ crowdinProjectId?: string | undefined;
5
5
  }[];
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  curriculumFoundations
3
- } from "../../chunks/chunk-7HGUA25M.mjs";
4
- import "../../chunks/chunk-FBVDZGXA.mjs";
3
+ } from "../../chunks/chunk-IYDI5F2O.mjs";
4
+ import "../../chunks/chunk-VYO3H52S.mjs";
5
5
  import "../../chunks/chunk-5AVXA5JL.mjs";
6
6
  export {
7
7
  curriculumFoundations
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  curriculumFoundations
3
- } from "../chunks/chunk-7HGUA25M.mjs";
4
- import "../chunks/chunk-FBVDZGXA.mjs";
3
+ } from "../chunks/chunk-IYDI5F2O.mjs";
4
+ import "../chunks/chunk-VYO3H52S.mjs";
5
5
  import "../chunks/chunk-5AVXA5JL.mjs";
6
6
  export {
7
7
  curriculumFoundations
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  export declare const CurriculumTopics: z.ZodArray<z.ZodObject<{
3
3
  curriculumId: z.ZodString;
4
- crowdinProjectId: z.ZodString;
4
+ crowdinProjectId: z.ZodOptional<z.ZodString>;
5
5
  sets: z.ZodArray<z.ZodString>;
6
6
  }, z.core.$strict>>;
7
7
  export type CurriculumTopics = z.infer<typeof CurriculumTopics>;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CurriculumTopics
3
- } from "../../chunks/chunk-RQR7ADQ3.mjs";
3
+ } from "../../chunks/chunk-5JMRXTQB.mjs";
4
4
  import "../../chunks/chunk-5AVXA5JL.mjs";
5
5
  export {
6
6
  CurriculumTopics
@@ -1,5 +1,5 @@
1
1
  export declare const curriculumTopics: {
2
2
  curriculumId: string;
3
- crowdinProjectId: string;
4
3
  sets: string[];
4
+ crowdinProjectId?: string | undefined;
5
5
  }[];
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  curriculumTopics
3
- } from "../../chunks/chunk-KCYVCCJ5.mjs";
4
- import "../../chunks/chunk-RQR7ADQ3.mjs";
3
+ } from "../../chunks/chunk-YOWQLQC3.mjs";
4
+ import "../../chunks/chunk-5JMRXTQB.mjs";
5
5
  import "../../chunks/chunk-5AVXA5JL.mjs";
6
6
  export {
7
7
  curriculumTopics
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  curriculumTopics
3
- } from "../chunks/chunk-KCYVCCJ5.mjs";
4
- import "../chunks/chunk-RQR7ADQ3.mjs";
3
+ } from "../chunks/chunk-YOWQLQC3.mjs";
4
+ import "../chunks/chunk-5JMRXTQB.mjs";
5
5
  import "../chunks/chunk-5AVXA5JL.mjs";
6
6
  export {
7
7
  curriculumTopics
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  translationsSet
3
- } from "../../chunks/chunk-7VYOSR3V.mjs";
3
+ } from "../../chunks/chunk-46VSKJAN.mjs";
4
4
  import "../../chunks/chunk-SMLKJF5I.mjs";
5
5
  import "../../chunks/chunk-5AVXA5JL.mjs";
6
6
  export {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  translationsSet
3
- } from "../chunks/chunk-7VYOSR3V.mjs";
3
+ } from "../chunks/chunk-46VSKJAN.mjs";
4
4
  import "../chunks/chunk-SMLKJF5I.mjs";
5
5
  import "../chunks/chunk-5AVXA5JL.mjs";
6
6
  export {
@@ -54,16 +54,32 @@ interface DownloadTranslationsParams {
54
54
  * Downloads translations from Crowdin for a given project ID and source path.
55
55
  */
56
56
  export declare function downloadTranslations({ projectId, translationsFolder, token, sourcePattern, }: DownloadTranslationsParams): void;
57
+ /**
58
+ * Parser and import settings for files Crowdin can't read with its defaults,
59
+ * such as the `fm_md` drip emails. `type` only applies on create; Crowdin
60
+ * rejects it on update.
61
+ */
62
+ export interface CrowdinFileSettings {
63
+ type?: SourceFilesModel.FileType;
64
+ importOptions?: SourceFilesModel.ImportOptions;
65
+ }
57
66
  interface UploadSourceParams {
58
67
  /** The id of the project to upload to, from `crowdinProjectIds`. */
59
68
  projectId: string;
60
69
  /**
61
- * Absolute path to the source file to upload, somewhere under a `crowdin/`
62
- * directory (e.g. `/path/to/project/crowdin/eng/app_interface_text.json`,
63
- * or `/path/to/project/crowdin/foo.md` for a project that keeps sources at
64
- * the root). The path Crowdin sees is everything after `crowdin/`.
70
+ * Absolute path to the local source file. When `dest` is omitted this must
71
+ * sit somewhere under a `crowdin/` directory (e.g.
72
+ * `/path/to/project/crowdin/eng/app_interface_text.json`) so the Crowdin
73
+ * path can be derived from it.
65
74
  */
66
75
  source: string;
76
+ /**
77
+ * Where the file lives in Crowdin, e.g. `main.json`. Defaults to everything
78
+ * after `crowdin/` in `source`, which is wrong when the project's layout
79
+ * differs from the repo's. A wrong path creates a new file with none of the
80
+ * real one's translations, hence `allowCreate`.
81
+ */
82
+ dest?: string;
67
83
  /** The Crowdin personal access token to use for authentication. */
68
84
  token: string;
69
85
  /**
@@ -72,11 +88,15 @@ interface UploadSourceParams {
72
88
  */
73
89
  label?: string;
74
90
  /** Parser and import settings, for files needing more than the defaults. */
75
- fileSettings?: FileSettings;
76
- }
77
- interface FileSettings {
78
- type?: SourceFilesModel.FileType;
79
- importOptions?: SourceFilesModel.ImportOptions;
91
+ fileSettings?: CrowdinFileSettings;
92
+ /**
93
+ * Whether a file Crowdin doesn't already have may be created. Defaults to
94
+ * true. Pass false to make the upload update-only, so a mistyped path throws
95
+ * instead of orphaning the real file's translations.
96
+ */
97
+ allowCreate?: boolean;
98
+ /** Resolve what would happen and report it without uploading anything. */
99
+ dryRun?: boolean;
80
100
  }
81
101
  /**
82
102
  * The request that replaces an existing file. Built separately from
@@ -88,19 +108,26 @@ interface FileSettings {
88
108
  */
89
109
  export declare function replaceFileRequest({ storageId, fileSettings, attachLabelIds, }: {
90
110
  storageId: number;
91
- fileSettings?: FileSettings;
111
+ fileSettings?: CrowdinFileSettings;
92
112
  attachLabelIds?: number[];
93
113
  }): SourceFilesModel.ReplaceFileFromStorageRequest;
94
114
  /** The request that creates a new file. See {@link replaceFileRequest}. */
95
115
  export declare function createFileRequest({ storageId, name, fileSettings, attachLabelIds, directoryId, }: {
96
116
  storageId: number;
97
117
  name: string;
98
- fileSettings?: FileSettings;
118
+ fileSettings?: CrowdinFileSettings;
99
119
  attachLabelIds?: number[];
100
120
  directoryId?: number;
101
121
  }): SourceFilesModel.CreateFileRequest;
102
- /** Uploads a source file to Crowdin, creating it or replacing its contents. */
103
- export declare function uploadSource({ projectId, source, token, label, fileSettings, }: UploadSourceParams): Promise<void>;
122
+ /**
123
+ * Whether an upload created a new file in Crowdin or updated an existing one.
124
+ */
125
+ export type UploadSourceOutcome = 'created' | 'updated';
126
+ /**
127
+ * Uploads a source file to Crowdin, creating it or replacing its contents, and
128
+ * reports which of the two it did.
129
+ */
130
+ export declare function uploadSource({ projectId, source, dest, token, label, fileSettings, allowCreate, dryRun, }: UploadSourceParams): Promise<UploadSourceOutcome>;
104
131
  /**
105
132
  * The directory a new file at `relativePath` belongs in, or undefined for a
106
133
  * file at the project root.
@@ -115,4 +142,68 @@ export interface CrowdinDirectory {
115
142
  path: string;
116
143
  }
117
144
  export declare function findDirectoryId(directories: CrowdinDirectory[], projectId: number, relativePath: string): number | undefined;
145
+ /** One source file a repo owns, as declared in its Crowdin sources config. */
146
+ export interface CrowdinSourceFileConfig {
147
+ /**
148
+ * Path to the local file, relative to the `baseDir` passed to
149
+ * `uploadSources`. With the repo's `crowdin/` directory as `baseDir`, that's
150
+ * `eng/main.json`.
151
+ */
152
+ source: string;
153
+ /** The project this file belongs to, from `crowdinProjectIds`. */
154
+ projectId: string;
155
+ /**
156
+ * Where the file lives in Crowdin. Defaults to the part of `source` below
157
+ * the repo's `crowdin/` directory. See `UploadSourceParams['dest']`.
158
+ */
159
+ dest?: string;
160
+ /** Parser and import settings, for files needing more than the defaults. */
161
+ fileSettings?: CrowdinFileSettings;
162
+ /**
163
+ * Lets this file be created even when the run doesn't allow it. For files
164
+ * where a new one is routine rather than a typo, like the drip emails (one
165
+ * file per email). Leave it off for hand-maintained files.
166
+ */
167
+ allowCreate?: boolean;
168
+ }
169
+ /**
170
+ * Everything a repo uploads to Crowdin. One config per repo rather than per
171
+ * project, since a repo's files often span several projects and one list
172
+ * leaves one place to register a file.
173
+ */
174
+ export interface CrowdinSourcesConfig {
175
+ files: CrowdinSourceFileConfig[];
176
+ }
177
+ interface UploadSourcesParams {
178
+ config: CrowdinSourcesConfig;
179
+ /** The directory `config`'s `source` paths are relative to. */
180
+ baseDir: string;
181
+ /** The Crowdin personal access token to use for authentication. */
182
+ token: string;
183
+ /** Label to attach to new strings in every uploaded file. */
184
+ label?: string;
185
+ /**
186
+ * Whether files Crowdin doesn't already have may be created. Defaults to
187
+ * false, unlike `uploadSource`, so an unattended run fails on a wrong path.
188
+ * Entries that set their own `allowCreate` may be created either way.
189
+ */
190
+ allowCreate?: boolean;
191
+ /**
192
+ * Upload only the entries with these `source` paths, e.g.
193
+ * `['eng/app_interface_text.json']`, including every project a file is in.
194
+ * A path matching no entry throws before anything is uploaded.
195
+ */
196
+ only?: string[];
197
+ /** Report what each file would do without uploading anything. */
198
+ dryRun?: boolean;
199
+ }
200
+ /**
201
+ * Uploads every file in a Crowdin sources config, one at a time to stay under
202
+ * Crowdin's rate limit and keep the log readable, and returns how many it
203
+ * uploaded.
204
+ *
205
+ * A failed file doesn't stop the others: the run finishes, then throws with
206
+ * every failure listed.
207
+ */
208
+ export declare function uploadSources({ config, baseDir, token, label, allowCreate, only, dryRun, }: UploadSourcesParams): Promise<number>;
118
209
  export {};
@@ -1,7 +1,10 @@
1
1
  import "../chunks/chunk-5AVXA5JL.mjs";
2
2
 
3
3
  // functions/crowdin.ts
4
- import CrowdinClient from "@crowdin/crowdin-api-client";
4
+ import {
5
+ Client as CrowdinClient,
6
+ CrowdinError
7
+ } from "@crowdin/crowdin-api-client";
5
8
  import fs from "fs";
6
9
  import { spawnSync } from "node:child_process";
7
10
  import path from "path";
@@ -46,9 +49,22 @@ function downloadTranslations({
46
49
  }
47
50
  );
48
51
  }
49
- var exportOptions = {
50
- exportPattern: `/${CROWDIN_TRANSLATION_PATTERN}`
51
- };
52
+ function crowdinClient(token) {
53
+ return new CrowdinClient(
54
+ { token },
55
+ {
56
+ retryConfig: {
57
+ retries: 3,
58
+ waitInterval: 5e3,
59
+ conditions: [
60
+ {
61
+ test: (error) => error instanceof CrowdinError && error.code < 500 && error.code !== 429
62
+ }
63
+ ]
64
+ }
65
+ }
66
+ );
67
+ }
52
68
  function replaceFileRequest({
53
69
  storageId,
54
70
  fileSettings,
@@ -56,10 +72,14 @@ function replaceFileRequest({
56
72
  }) {
57
73
  return {
58
74
  storageId,
59
- exportOptions,
60
75
  // Keeps translations of revised strings but drops their approvals, so a
61
76
  // reviewer looks again rather than stale copy staying green.
62
77
  updateOption: "keep_translations",
78
+ /*
79
+ * No `exportOptions`, so a project's custom export pattern survives an
80
+ * update (Waha Training exports `glossary-8064.tbx` as
81
+ * `03.009.000.glossary.tbx`).
82
+ */
63
83
  ...fileSettings?.importOptions && {
64
84
  importOptions: fileSettings.importOptions
65
85
  },
@@ -76,7 +96,7 @@ function createFileRequest({
76
96
  return {
77
97
  storageId,
78
98
  name,
79
- exportOptions,
99
+ exportOptions: { exportPattern: `/${CROWDIN_TRANSLATION_PATTERN}` },
80
100
  ...fileSettings,
81
101
  ...attachLabelIds && { attachLabelIds },
82
102
  ...directoryId !== void 0 && { directoryId }
@@ -85,17 +105,17 @@ function createFileRequest({
85
105
  async function uploadSource({
86
106
  projectId,
87
107
  source,
108
+ dest,
88
109
  token,
89
110
  label,
90
- fileSettings
111
+ fileSettings,
112
+ allowCreate = true,
113
+ dryRun = false
91
114
  }) {
92
- const client = new CrowdinClient({ token });
115
+ const client = crowdinClient(token);
93
116
  const id = Number(projectId);
94
- const relativePath = crowdinRelativePath(source);
117
+ const relativePath = (dest ?? crowdinRelativePath(source)).replace(/^\//, "");
95
118
  const fileName = relativePath.slice(relativePath.lastIndexOf("/") + 1);
96
- const contents = fs.readFileSync(source, "utf8");
97
- const storage = await client.uploadStorageApi.addStorage(fileName, contents);
98
- const storageId = storage.data.id;
99
119
  const files = await client.sourceFilesApi.listProjectFiles(id, {
100
120
  filter: fileName,
101
121
  limit: 500
@@ -103,6 +123,15 @@ async function uploadSource({
103
123
  const existing = files.data.find(
104
124
  (file) => file.data.path === `/${relativePath}`
105
125
  );
126
+ if (!existing && !allowCreate) {
127
+ throw new Error(
128
+ `Crowdin project ${projectId} has no /${relativePath}, and creating it was not allowed. Either the path is wrong \u2014 check it against the project's Sources & Translations page \u2014 or the file really is new, in which case upload it once with creation enabled.`
129
+ );
130
+ }
131
+ if (dryRun) return existing ? "updated" : "created";
132
+ const contents = fs.readFileSync(source, "utf8");
133
+ const storage = await client.uploadStorageApi.addStorage(fileName, contents);
134
+ const storageId = storage.data.id;
106
135
  const attachLabelIds = label ? [await labelId(client, id, label)] : void 0;
107
136
  if (existing) {
108
137
  await client.sourceFilesApi.updateOrRestoreFile(
@@ -110,7 +139,7 @@ async function uploadSource({
110
139
  existing.data.id,
111
140
  replaceFileRequest({ storageId, fileSettings, attachLabelIds })
112
141
  );
113
- return;
142
+ return "updated";
114
143
  }
115
144
  const directories = relativePath.includes("/") ? await client.sourceFilesApi.listProjectDirectories(id, { limit: 500 }) : { data: [] };
116
145
  await client.sourceFilesApi.createFile(
@@ -127,6 +156,7 @@ async function uploadSource({
127
156
  )
128
157
  })
129
158
  );
159
+ return "created";
130
160
  }
131
161
  async function labelId(client, projectId, title) {
132
162
  const labels = await client.labelsApi.listLabels(projectId, { limit: 500 });
@@ -146,6 +176,60 @@ function findDirectoryId(directories, projectId, relativePath) {
146
176
  }
147
177
  return match.id;
148
178
  }
179
+ async function uploadSources({
180
+ config,
181
+ baseDir,
182
+ token,
183
+ label,
184
+ allowCreate = false,
185
+ only,
186
+ dryRun = false
187
+ }) {
188
+ const files = only ? config.files.filter((file) => only.includes(file.source)) : config.files;
189
+ const unmatched = (only ?? []).filter(
190
+ (source) => !files.some((file) => file.source === source)
191
+ );
192
+ if (unmatched.length > 0) {
193
+ throw new Error(
194
+ `No Crowdin sources config entry for ${unmatched.join(", ")}. Paths are relative to ${baseDir}, e.g. eng/app_interface_text.json.`
195
+ );
196
+ }
197
+ const failures = [];
198
+ for (const file of files) {
199
+ const source = path.resolve(baseDir, file.source);
200
+ const target = `${file.source} -> project ${file.projectId}`;
201
+ if (!fs.existsSync(source)) {
202
+ failures.push(` ${file.source}: Local file ${source} does not exist.`);
203
+ console.log(`failed: ${target} (missing)`);
204
+ continue;
205
+ }
206
+ const dest = (file.dest ?? crowdinRelativePath(source)).replace(/^\//, "");
207
+ try {
208
+ const outcome = await uploadSource({
209
+ projectId: file.projectId,
210
+ source,
211
+ dest,
212
+ token,
213
+ label,
214
+ fileSettings: file.fileSettings,
215
+ allowCreate: allowCreate || Boolean(file.allowCreate),
216
+ dryRun
217
+ });
218
+ console.log(`${dryRun ? "would be " : ""}${outcome}: ${target} /${dest}`);
219
+ } catch (error) {
220
+ const message = error instanceof Error ? error.message : String(error);
221
+ failures.push(` ${file.source}: ${message}`);
222
+ console.log(`failed: ${target} /${dest}`);
223
+ }
224
+ }
225
+ if (failures.length > 0) {
226
+ throw new Error(
227
+ `${failures.length} of ${files.length} Crowdin uploads failed:
228
+ ` + failures.join("\n")
229
+ );
230
+ }
231
+ return files.length;
232
+ }
149
233
  export {
150
234
  CROWDIN_TRANSLATION_PATTERN,
151
235
  createFileRequest,
@@ -154,5 +238,6 @@ export {
154
238
  downloadTranslations,
155
239
  findDirectoryId,
156
240
  replaceFileRequest,
157
- uploadSource
241
+ uploadSource,
242
+ uploadSources
158
243
  };
@@ -5,11 +5,11 @@ import {
5
5
  getMeetTranslations,
6
6
  isLanguageAvailable,
7
7
  numerals
8
- } from "../chunks/chunk-RKEA5BP2.mjs";
9
- import "../chunks/chunk-7HGUA25M.mjs";
10
- import "../chunks/chunk-FBVDZGXA.mjs";
11
- import "../chunks/chunk-KCYVCCJ5.mjs";
12
- import "../chunks/chunk-RQR7ADQ3.mjs";
8
+ } from "../chunks/chunk-TGVLQAXS.mjs";
9
+ import "../chunks/chunk-IYDI5F2O.mjs";
10
+ import "../chunks/chunk-VYO3H52S.mjs";
11
+ import "../chunks/chunk-YOWQLQC3.mjs";
12
+ import "../chunks/chunk-5JMRXTQB.mjs";
13
13
  import "../chunks/chunk-LODLCRYD.mjs";
14
14
  import "../chunks/chunk-LUPH55O7.mjs";
15
15
  import "../chunks/chunk-DQQEFFNA.mjs";
@@ -22,7 +22,7 @@ import "../chunks/chunk-BS5UUPEA.mjs";
22
22
  import "../chunks/chunk-MZGGI6PG.mjs";
23
23
  import "../chunks/chunk-VSLJCKFL.mjs";
24
24
  import "../chunks/chunk-MG76FEEV.mjs";
25
- import "../chunks/chunk-7VYOSR3V.mjs";
25
+ import "../chunks/chunk-46VSKJAN.mjs";
26
26
  import "../chunks/chunk-SMLKJF5I.mjs";
27
27
  import "../chunks/chunk-OCE4ZKES.mjs";
28
28
  import "../chunks/chunk-Y7GBCSFN.mjs";
@@ -8,13 +8,13 @@ import {
8
8
  normalizeVerseTimings,
9
9
  verseToSuperscript,
10
10
  withChapterPlaceholders
11
- } from "../chunks/chunk-44FF5O3D.mjs";
11
+ } from "../chunks/chunk-B6C4GGOM.mjs";
12
12
  import "../chunks/chunk-PV7LVBQJ.mjs";
13
- import "../chunks/chunk-RKEA5BP2.mjs";
14
- import "../chunks/chunk-7HGUA25M.mjs";
15
- import "../chunks/chunk-FBVDZGXA.mjs";
16
- import "../chunks/chunk-KCYVCCJ5.mjs";
17
- import "../chunks/chunk-RQR7ADQ3.mjs";
13
+ import "../chunks/chunk-TGVLQAXS.mjs";
14
+ import "../chunks/chunk-IYDI5F2O.mjs";
15
+ import "../chunks/chunk-VYO3H52S.mjs";
16
+ import "../chunks/chunk-YOWQLQC3.mjs";
17
+ import "../chunks/chunk-5JMRXTQB.mjs";
18
18
  import "../chunks/chunk-LODLCRYD.mjs";
19
19
  import "../chunks/chunk-LUPH55O7.mjs";
20
20
  import "../chunks/chunk-DQQEFFNA.mjs";
@@ -27,7 +27,7 @@ import "../chunks/chunk-BS5UUPEA.mjs";
27
27
  import "../chunks/chunk-MZGGI6PG.mjs";
28
28
  import "../chunks/chunk-VSLJCKFL.mjs";
29
29
  import "../chunks/chunk-MG76FEEV.mjs";
30
- import "../chunks/chunk-7VYOSR3V.mjs";
30
+ import "../chunks/chunk-46VSKJAN.mjs";
31
31
  import "../chunks/chunk-SMLKJF5I.mjs";
32
32
  import "../chunks/chunk-OCE4ZKES.mjs";
33
33
  import "../chunks/chunk-Y7GBCSFN.mjs";
@@ -22,5 +22,6 @@ export declare function sentryOptions({ dsn, enabled, }: {
22
22
  sendDefaultPii: false;
23
23
  sendClientReports: false;
24
24
  integrations: (defaults: Integration[]) => Integration[];
25
+ ignoreErrors: string[];
25
26
  beforeSend: typeof stripFileQueries;
26
27
  };
@@ -16,6 +16,11 @@ function stripFileQueries(event) {
16
16
  });
17
17
  return event;
18
18
  }
19
+ var ignoredErrors = [
20
+ // Firebase Analytics registering an installation while the visitor is
21
+ // offline. It rejects a promise inside `getAnalytics` that nothing awaits.
22
+ "installations/app-offline"
23
+ ];
19
24
  function sentryOptions({
20
25
  dsn,
21
26
  enabled
@@ -28,6 +33,7 @@ function sentryOptions({
28
33
  // browser only contacts Sentry to report an error.
29
34
  sendClientReports: false,
30
35
  integrations: (defaults) => defaults.filter((integration) => integration.name !== "BrowserSession"),
36
+ ignoreErrors: ignoredErrors,
31
37
  beforeSend: stripFileQueries
32
38
  };
33
39
  }
@@ -9,13 +9,13 @@ import "../chunks/chunk-2A7C3PEI.mjs";
9
9
  import {
10
10
  getFtbDuration,
11
11
  getPassagesString
12
- } from "../chunks/chunk-44FF5O3D.mjs";
12
+ } from "../chunks/chunk-B6C4GGOM.mjs";
13
13
  import "../chunks/chunk-PV7LVBQJ.mjs";
14
- import "../chunks/chunk-RKEA5BP2.mjs";
15
- import "../chunks/chunk-7HGUA25M.mjs";
16
- import "../chunks/chunk-FBVDZGXA.mjs";
17
- import "../chunks/chunk-KCYVCCJ5.mjs";
18
- import "../chunks/chunk-RQR7ADQ3.mjs";
14
+ import "../chunks/chunk-TGVLQAXS.mjs";
15
+ import "../chunks/chunk-IYDI5F2O.mjs";
16
+ import "../chunks/chunk-VYO3H52S.mjs";
17
+ import "../chunks/chunk-YOWQLQC3.mjs";
18
+ import "../chunks/chunk-5JMRXTQB.mjs";
19
19
  import "../chunks/chunk-LODLCRYD.mjs";
20
20
  import "../chunks/chunk-LUPH55O7.mjs";
21
21
  import "../chunks/chunk-DQQEFFNA.mjs";
@@ -30,7 +30,7 @@ import {
30
30
  specialIds
31
31
  } from "../chunks/chunk-VSLJCKFL.mjs";
32
32
  import "../chunks/chunk-MG76FEEV.mjs";
33
- import "../chunks/chunk-7VYOSR3V.mjs";
33
+ import "../chunks/chunk-46VSKJAN.mjs";
34
34
  import "../chunks/chunk-SMLKJF5I.mjs";
35
35
  import "../chunks/chunk-OCE4ZKES.mjs";
36
36
  import "../chunks/chunk-Y7GBCSFN.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waha-shared",
3
- "version": "1.0.552",
3
+ "version": "1.0.554",
4
4
  "author": "Waha",
5
5
  "dependencies": {
6
6
  "@types/signale": "^1.4.7",