From c6aefe79967cfa7999879a30ad8d8367745c9c2e Mon Sep 17 00:00:00 2001 From: speakeasybot Date: Mon, 23 Feb 2026 00:09:23 +0000 Subject: [PATCH 1/2] =?UTF-8?q?##=20Java=20SDK=20Changes:=20*=20`novu.subs?= =?UTF-8?q?cribers.messages.updateActionStatus()`:=20=20`response`=20**Cha?= =?UTF-8?q?nged**=20(Breaking=20=E2=9A=A0=EF=B8=8F)=20*=20`novu.messages.l?= =?UTF-8?q?ist()`:=20=20`response.data[]`=20**Changed**=20(Breaking=20?= =?UTF-8?q?=E2=9A=A0=EF=B8=8F)=20*=20`novu.subscribersMessages.markAllAs()?= =?UTF-8?q?`:=20=20`response.[]`=20**Changed**=20(Breaking=20=E2=9A=A0?= =?UTF-8?q?=EF=B8=8F)=20*=20`novu.subscribersNotifications.getFeed()`:=20?= =?UTF-8?q?=20`response.data[].cta.action.result.payload`=20**Changed**=20?= =?UTF-8?q?(Breaking=20=E2=9A=A0=EF=B8=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .speakeasy/gen.lock | 170 ++++++++---------- .speakeasy/gen.yaml | 8 +- .speakeasy/workflow.lock | 16 +- README.md | 8 +- RELEASES.md | 12 +- docs/models/components/MessageActionResult.md | 8 +- .../components/MessageActionResultPayload.md | 9 - docs/models/components/MessageResponseDto.md | 4 +- .../components/MessageResponseDtoOverrides.md | 9 - .../components/MessageResponseDtoPayload.md | 9 - docs/sdks/subscribers/README.md | 3 + docs/sdks/tags/README.md | 2 +- docs/sdks/topics/README.md | 7 +- docs/sdks/translations/README.md | 3 + gradle.properties | 2 +- src/main/java/co/novu/AsyncNovu.java | 52 +++++- src/main/java/co/novu/AsyncSubscribers.java | 9 +- src/main/java/co/novu/AsyncTags.java | 6 +- src/main/java/co/novu/AsyncTopics.java | 23 ++- src/main/java/co/novu/AsyncTranslations.java | 6 +- src/main/java/co/novu/Novu.java | 52 +++++- src/main/java/co/novu/SDKConfiguration.java | 6 +- src/main/java/co/novu/Subscribers.java | 9 +- src/main/java/co/novu/Tags.java | 6 +- src/main/java/co/novu/Topics.java | 23 ++- src/main/java/co/novu/Translations.java | 6 +- .../components/MessageActionResult.java | 14 +- .../MessageActionResultPayload.java | 61 ------- .../models/components/MessageResponseDto.java | 26 +-- .../MessageResponseDtoOverrides.java | 61 ------- .../components/MessageResponseDtoPayload.java | 61 ------- src/main/java/co/novu/utils/EventStream.java | 37 ++-- .../co/novu/utils/EventStreamMessage.java | 19 +- src/main/java/co/novu/utils/RequestBody.java | 8 + src/main/java/co/novu/utils/Security.java | 5 +- .../co/novu/utils/SpeakeasyHTTPClient.java | 17 +- .../java/co/novu/utils/StreamingParser.java | 118 ++++++------ src/main/java/co/novu/utils/Utils.java | 19 +- .../co/novu/utils/reactive/EventStream.java | 6 +- 39 files changed, 434 insertions(+), 486 deletions(-) delete mode 100644 docs/models/components/MessageActionResultPayload.md delete mode 100644 docs/models/components/MessageResponseDtoOverrides.md delete mode 100644 docs/models/components/MessageResponseDtoPayload.md delete mode 100644 src/main/java/co/novu/models/components/MessageActionResultPayload.java delete mode 100644 src/main/java/co/novu/models/components/MessageResponseDtoOverrides.java delete mode 100644 src/main/java/co/novu/models/components/MessageResponseDtoPayload.java diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 9b040585..8cc719e3 100644 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,37 +1,37 @@ lockVersion: 2.0.0 id: caaab73e-db12-4a8b-93a0-536b113afa44 management: - docChecksum: 8d426ef45cf545c3a6f5e641e8c51fdf - docVersion: 3.12.0 - speakeasyVersion: 1.696.0 - generationVersion: 2.799.0 - releaseVersion: 3.12.0 - configChecksum: 7a9768031f31861611ccac36a80589c5 + docChecksum: eea385cba32be1129f7cd63abae5f18c + docVersion: 3.13.0 + speakeasyVersion: 1.723.0 + generationVersion: 2.835.2 + releaseVersion: 3.13.0 + configChecksum: 42fbfd7c22778190fc071607d1c2dab4 repoURL: https://github.com/novuhq/novu-java.git published: true persistentEdits: - generation_id: 75e69b0f-d52f-4bd8-8384-9009f6e5c09d - pristine_commit_hash: a1705c577141af9ef4d4c5cd4ff63986955a046d - pristine_tree_hash: b5d201100a255a67fc7f95a86d1a6bd1a4bf3720 + generation_id: de3401f4-5887-4038-bda7-b29b221741cd + pristine_commit_hash: 63d6f744cc9e21f379ef729153b159f0ee3efc7f + pristine_tree_hash: 8f544c61fe0e6c302d2d0eba9e6f389e1c03ac01 features: java: additionalDependencies: 0.1.0 additionalProperties: 0.0.1 - constsAndDefaults: 0.1.1 - core: 3.55.8 + constsAndDefaults: 0.1.2 + core: 3.55.14 deprecations: 2.81.2 examples: 2.81.6 flattening: 2.81.1 - globalSecurity: 2.83.1 + globalSecurity: 2.83.2 globalSecurityCallbacks: 0.1.0 globalSecurityFlattening: 0.1.0 globalServerURLs: 2.83.0 groups: 2.81.3 - nameOverrides: 2.81.3 + nameOverrides: 2.81.5 nullables: 0.1.0 retries: 0.1.1 sdkHooks: 1.2.0 - unions: 0.3.1 + unions: 0.3.2 uploadStreams: 0.1.0 trackedFiles: .gitattributes: @@ -1024,12 +1024,8 @@ trackedFiles: pristine_git_object: 7ae0e3d7ae61325027ac25dcd449f586c9e88957 docs/models/components/MessageActionResult.md: id: 35f11ad055a6 - last_write_checksum: sha1:6eb8e0d5271998b2ab9f7b12ec26da50b0715f83 - pristine_git_object: 3b403eaf15ffcc07f2f26cbf447678d4b50b06a0 - docs/models/components/MessageActionResultPayload.md: - id: 015779b04c88 - last_write_checksum: sha1:409c4257cef17dfd38b655786c13116c0c29d60a - pristine_git_object: 42af3bf8e6bc3a42caf2840f4650397144661534 + last_write_checksum: sha1:9b8e2c4e1e3adbbd09fc1264d85ef40c0e4f9373 + pristine_git_object: 080e52d3ba1fa8c5c347fe7e54c3d269ff2c6cd6 docs/models/components/MessageActionStatusEnum.md: id: 38403928f7cc last_write_checksum: sha1:0fc2a7ebec0b8782906d60fbace391080449b085 @@ -1060,16 +1056,8 @@ trackedFiles: pristine_git_object: 13c5a1df1decbe64628d0de2f61b2720b2169a98 docs/models/components/MessageResponseDto.md: id: 8dca237f7d69 - last_write_checksum: sha1:47e126ceb5c98575ec3cbf9200c4750f7fd73b79 - pristine_git_object: f24189610b2e926aebbd6592a723666b0a3ac3d8 - docs/models/components/MessageResponseDtoOverrides.md: - id: b54d02887cb2 - last_write_checksum: sha1:dabee1e288bb72b29cccb80eaeb7c7d6f9e49832 - pristine_git_object: b68cdd5261b380b99171b3c1d8248f6010fcf9e0 - docs/models/components/MessageResponseDtoPayload.md: - id: 25fab315797c - last_write_checksum: sha1:60ed8b16b912952f559335c433395d1e5c2f2a5e - pristine_git_object: 9e8f637aafd4ac9f70a4e8cfaac665a609e9187c + last_write_checksum: sha1:aeadacd3872d04ada2ce86f006ad1a7fc10bd7b7 + pristine_git_object: a4e410bfb4e63aa6368bc4c0e5052dd7582caa5b docs/models/components/MessageStatusEnum.md: id: 0d7f81e3b7eb last_write_checksum: sha1:1c9f8964c9c38fe5d980f910dae0e32a6df80d0d @@ -2828,8 +2816,8 @@ trackedFiles: pristine_git_object: 0484b0b1fd69ec344c0b06140dfe79c27e2dd92c docs/sdks/subscribers/README.md: id: 14c599d74195 - last_write_checksum: sha1:eceb885bc1d5de6c0c5695cc0ca817e922961ab2 - pristine_git_object: 330b148dca9714bb4ad172ffe773ec63f7548134 + last_write_checksum: sha1:30364b4fcbd0e1ff368a2571c4723a82cd2c84e6 + pristine_git_object: 5fa94aef5a8f1f2a174a773f83b17e29633ec204 docs/sdks/subscribersmessages1/README.md: id: cad1e73a3892 last_write_checksum: sha1:548ad86ebf2ad24d2a4043d6eff397bebed7c0d5 @@ -2860,20 +2848,20 @@ trackedFiles: pristine_git_object: 7bacb7be9a9ffbc817b40eed95c66cd8400b63e3 docs/sdks/tags/README.md: id: 971f8a95d807 - last_write_checksum: sha1:30620c894b2be6a54099f6dd093769364c9cba5c - pristine_git_object: 4ddbf9276ecdda8b746f3fef8447c3828730f490 + last_write_checksum: sha1:b3cc163f3f2eb3a60e74b73caba7eefe921feb68 + pristine_git_object: 81c64ed9be8cb62087245c91e3d34d62b655e7b6 docs/sdks/topics/README.md: id: db4aff1adac3 - last_write_checksum: sha1:57d5c64da04a84b6d1aff7ef683c14eee0fcb8fd - pristine_git_object: 69e48651c63a523ff31aeff4e083ee5ff8419c0d + last_write_checksum: sha1:aca7d377345f7782e2fc5541dfebac90c6d99371 + pristine_git_object: e92ec42a55d176ffdef5aa3feadb66db912f10cb docs/sdks/topicssubscribers/README.md: id: 7ae84d741547 last_write_checksum: sha1:317d411c5be972b7ac712549a4f08736d7046da4 pristine_git_object: 847d737d303d71393e05851b2ce1a34aafb0382a docs/sdks/translations/README.md: id: 0452749a3d5d - last_write_checksum: sha1:82d05cb0c330c5a516e1056a3ce010dbafcc67dc - pristine_git_object: 9cc85ccaaa2c8befb56775d82f3b23d3a8b1a735 + last_write_checksum: sha1:cb5a2c283ee3f12cf7bedbf173031e89bcdf4cbd + pristine_git_object: ee9ecb7c114da4f92c4c70621aaad00e63dd9a3a docs/sdks/workflows/README.md: id: 80c76ce944c0 last_write_checksum: sha1:a37a93255eed61a36ffbc712c0d0c718fb4748b7 @@ -2884,8 +2872,8 @@ trackedFiles: pristine_git_object: ebaa3566af4ce4249639e5a2dd8bca0edd2979bf gradle.properties: id: 2afbb999f001 - last_write_checksum: sha1:1634fbf197445b2a6181932f92cdcb8549cf5744 - pristine_git_object: 483db5e05227f66477ccbcff8eb21bf537783643 + last_write_checksum: sha1:4896e16e7e22e9560e58737e1557ec3af3d9e38e + pristine_git_object: c99b070f6067184e1ed6da5492f350218b0f004e gradle/wrapper/gradle-wrapper.jar: id: ec27dae6e852 last_write_checksum: sha1:f725fb1467084142d74fd7cd8eab691ab3442611 @@ -2984,8 +2972,8 @@ trackedFiles: pristine_git_object: 02a797be7d3b1f0b76e3c581b488b470ffa71a68 src/main/java/co/novu/AsyncNovu.java: id: caee93e13378 - last_write_checksum: sha1:5287a0a18de6f8f46bb0baeba86f1478ab0a835d - pristine_git_object: eead37f4c72676d6d3c0fcd24a91c75f4d187da2 + last_write_checksum: sha1:3164d948e4c7fe566093bfefbbad9181bf74f015 + pristine_git_object: 964253258923e9c9fd369c65db646fc33e3ab5f5 src/main/java/co/novu/AsyncPreferences.java: id: 432ad88a9ebe last_write_checksum: sha1:77dbba30a699d2ba4aecc59f875a0bb6ef846a41 @@ -2996,8 +2984,8 @@ trackedFiles: pristine_git_object: ba88046730f671db9e5e893ca5abe1e9a6c4d4e1 src/main/java/co/novu/AsyncSubscribers.java: id: 09ff40d6a4a5 - last_write_checksum: sha1:931e8ba40f0903ec4618e1b243a60c63e912c559 - pristine_git_object: 0104611e4eec9092d782131c1e6afbc91414e2c3 + last_write_checksum: sha1:c6d192f8ff9fa3ffdbf70ab06e5ba8df1920f876 + pristine_git_object: 1084cd5a20c0326c086dee88de16714cc7e761b3 src/main/java/co/novu/AsyncSubscribersMessages1.java: id: 9eaf02044a98 last_write_checksum: sha1:a81f93988e72e6988e8985773aecce3011e2ae11 @@ -3028,20 +3016,20 @@ trackedFiles: pristine_git_object: f5e233e461e7da29c85328f1e5717d6e332149f6 src/main/java/co/novu/AsyncTags.java: id: a01e29f50ef5 - last_write_checksum: sha1:3e7897dc6bc87ace4d2db359ad3f33f85a6e84e3 - pristine_git_object: 60688aa9abfb75998f40702e75e2907792df666c + last_write_checksum: sha1:6e587f3d9c4f291a34a0a50dcd911b9386fd3c51 + pristine_git_object: 65d76d5485b0c155cd7153e6077898430b014b98 src/main/java/co/novu/AsyncTopics.java: id: 0052739d3a47 - last_write_checksum: sha1:8f1785f576fa7a85545d4896b2f824f687335ab7 - pristine_git_object: 73fd700ffbd404e57fee10815b1df4703cd028b4 + last_write_checksum: sha1:b636a9e224b361787db714dada5eda235448893d + pristine_git_object: 41a9dba6c923489dd22f52806ff10754db2155d0 src/main/java/co/novu/AsyncTopicsSubscribers.java: id: 77cd8f3f28b1 last_write_checksum: sha1:8788b3c2d915e62075c555f1f5f632fc10dcefb2 pristine_git_object: 4a4f1a52df9df2e391308315e6359172c80a87e6 src/main/java/co/novu/AsyncTranslations.java: id: 2177400b230b - last_write_checksum: sha1:416f3f4e5c7d310976139c35353405371eca40a2 - pristine_git_object: 6b5107b4417a2fe94a463d697da7d6670df7804e + last_write_checksum: sha1:1b6ced6a118ac48bf622cfdffb5f45b0ff1dbb73 + pristine_git_object: 90054832af4571290821139c992acef4062d40ae src/main/java/co/novu/AsyncWorkflows.java: id: 3b574ed44a00 last_write_checksum: sha1:bd6e59e6c74d183468a3ffe5ee69fbd9299dcc67 @@ -3084,16 +3072,16 @@ trackedFiles: pristine_git_object: 7a5536e807a4bb48b23aac23d0983127a27c6459 src/main/java/co/novu/Novu.java: id: 11b62371bd26 - last_write_checksum: sha1:600010a96b53e0eba52e29f4e63f019e3874b817 - pristine_git_object: 6d0e53039c086a81b99a448ba9dfe75730358502 + last_write_checksum: sha1:9b593322d382ee233dac9938e51bfc1c0102d92d + pristine_git_object: dbd97cfaddb0029a62bc34785754de2f15b889db src/main/java/co/novu/Preferences.java: id: 40bb45282f6a last_write_checksum: sha1:b30819a1fdac34cceab61c91c1eb46dd8be83c23 pristine_git_object: 1b5f7ce4b77efc9d29be373d45eca57c867ad675 src/main/java/co/novu/SDKConfiguration.java: id: c8d0f1a7e696 - last_write_checksum: sha1:1337b621ddc816306ef8eaf9f5d133020d947160 - pristine_git_object: 6ee37664a9bf46863412b633c8a89108fc667222 + last_write_checksum: sha1:802f61c15776bc75547e3f14232eb211011b5dee + pristine_git_object: b7e4f8f5d6b9f6012b943fa727484aa950ba24c8 src/main/java/co/novu/SecuritySource.java: id: 8b19fc2daaf0 last_write_checksum: sha1:b876d0191046515ce80a9ea832f7c9b06bcfaa40 @@ -3104,8 +3092,8 @@ trackedFiles: pristine_git_object: 1d176108e99a3fcf79219f253fe1aaa26b90e936 src/main/java/co/novu/Subscribers.java: id: 5a5ebfabb771 - last_write_checksum: sha1:b1c56f68f34266c5b37b1de8f5d02b60bbb063bb - pristine_git_object: 85b0612a0cebee1a8adb9820df3ec6bbdb777bdb + last_write_checksum: sha1:3836e7146ac4efeb2877ef869f52ec69734b0cee + pristine_git_object: abdbca9ddbc13effd31e6e886cd4a8eac7682527 src/main/java/co/novu/SubscribersMessages1.java: id: e176ec83c434 last_write_checksum: sha1:30a570df99be6490650e121cfa7f5b964ea90dd9 @@ -3136,20 +3124,20 @@ trackedFiles: pristine_git_object: 312d6f66cd0426a3b09e6215d40303a5195da74d src/main/java/co/novu/Tags.java: id: 0b23aea361c8 - last_write_checksum: sha1:d899ab10db1ae5af52073d502771a6e2c0056c93 - pristine_git_object: cb5257c24c73224fe4cd2ee06a2faf7cb09bb94e + last_write_checksum: sha1:feba732f2d0b400c9bb1a54b3f5cd71490d33af7 + pristine_git_object: 995ea1c24292d034957efe9f4bbce4f469219420 src/main/java/co/novu/Topics.java: id: 0d2dfbed18d9 - last_write_checksum: sha1:ca3438c34161d05413c60cf3ae38dada88dccdca - pristine_git_object: ad872b17bd7b2643f1b4c27cea1f7b15c3d6954f + last_write_checksum: sha1:0ae2a7479e773c73ab1d9fb03c80a95f39cc0acd + pristine_git_object: 0f87d7f31ae05c10d6607c64ce86ee9c11501069 src/main/java/co/novu/TopicsSubscribers.java: id: b293f18e0ec3 last_write_checksum: sha1:78c896aeaf6871743365836c9cac91a72e0e03d2 pristine_git_object: 4c4d5fcfa9670ed54925cc52df58bab730ec8cba src/main/java/co/novu/Translations.java: id: c338d4f98598 - last_write_checksum: sha1:4f665d4648ce7a3996c7dd0e5ee4f662ef2d69f0 - pristine_git_object: a367ec3f43cb38e0e79d483026cf5fcca7c9c0d0 + last_write_checksum: sha1:3287928df729dd0f858bd1c6a0fad509683b443e + pristine_git_object: 9b6315f216625b81c92ff6cb02493b744904d9e4 src/main/java/co/novu/Workflows.java: id: d4015788d243 last_write_checksum: sha1:2777e2ac8ad3184866917161e6b4e9725d7c10c1 @@ -4136,12 +4124,8 @@ trackedFiles: pristine_git_object: 17215f0fa3a73311b4bcff5f13d0eb89d7a1a26f src/main/java/co/novu/models/components/MessageActionResult.java: id: 36b69f2e8c61 - last_write_checksum: sha1:88659b7b4c0d895f237c63c7c55c356bc652e797 - pristine_git_object: 28a000b732dc13767e9989499eff64bcae41bbd8 - src/main/java/co/novu/models/components/MessageActionResultPayload.java: - id: 97a19272f359 - last_write_checksum: sha1:e72b24854165565a7b1713886643347c7ab2ea39 - pristine_git_object: 46e40f0ed3640492898de82c1b736768920a2e6e + last_write_checksum: sha1:8f48f4dd2e0d3f51b961f9d051ddc2572181b808 + pristine_git_object: 745e9143d71b11904f70afc29f602dee8dcbad2a src/main/java/co/novu/models/components/MessageActionStatusEnum.java: id: bc6c20d4b4d1 last_write_checksum: sha1:a949b841d86befced915f450ceec0e892cdea504 @@ -4172,16 +4156,8 @@ trackedFiles: pristine_git_object: 1ced3ab74fa640bcbb5e7f0a9fb9dc7e0b4477f5 src/main/java/co/novu/models/components/MessageResponseDto.java: id: c3ef5890087f - last_write_checksum: sha1:90a48a7e0f26cec984f77d97e860ceece15305d7 - pristine_git_object: fa82090bef210806917d788fed0b79dda8b8a2fd - src/main/java/co/novu/models/components/MessageResponseDtoOverrides.java: - id: 326b79ba162e - last_write_checksum: sha1:0cc312cb3f4411e6ec83e4736f0fb02e22af44f6 - pristine_git_object: 876672b44308a85f5d7f5fce302a8c520f4e82b5 - src/main/java/co/novu/models/components/MessageResponseDtoPayload.java: - id: 8a4df2d21432 - last_write_checksum: sha1:044bd2c9445221a18a75f568625721bdd22adcaf - pristine_git_object: ddbbfb038c0c1f790a5222b13c9143f33ce677d2 + last_write_checksum: sha1:a1c285a9eaec6e01a33833a74e9e495b11fd120b + pristine_git_object: a8c96383123b97df3efb7fc8009138592e0e524e src/main/java/co/novu/models/components/MessageStatusEnum.java: id: c14df1b975a4 last_write_checksum: sha1:2a18abb8b667ac5d4d042e6596e97562dbc601b2 @@ -7476,12 +7452,12 @@ trackedFiles: pristine_git_object: 57e31191b71458895f41feff7b062d16273b0f9f src/main/java/co/novu/utils/EventStream.java: id: ccb172e74a46 - last_write_checksum: sha1:4392cceba797d6e74aaf50a5b7c2790706943b36 - pristine_git_object: 84220e05d6ed63bc748097ea436749c07f8379eb + last_write_checksum: sha1:4488dd7706035c2f4355b8cf6a57b94ffbba91b7 + pristine_git_object: 64a83bcd9198186d7a9b5d1bd3edb1737804af9c src/main/java/co/novu/utils/EventStreamMessage.java: id: 02120d6f4c32 - last_write_checksum: sha1:08253c0e1e3d8686141e97c18a8f71dead91041e - pristine_git_object: 865d54a11cc77c32c97658e89cde1d942d96f5ed + last_write_checksum: sha1:a26d79a101b5bf797014309a9afe567e0dfc26aa + pristine_git_object: 163ba3ffc8ea8ec3c80775d1ed6b6132399c7407 src/main/java/co/novu/utils/Exceptions.java: id: 4c04815ac3a8 last_write_checksum: sha1:124de1f0860136cf333b212adc3767383bd946fb @@ -7600,8 +7576,8 @@ trackedFiles: pristine_git_object: ce9bd2574d61d16d9f1cd07f602fbc36c2a948db src/main/java/co/novu/utils/RequestBody.java: id: 74293280fc97 - last_write_checksum: sha1:2eec41fe818e47af5ee6889491353d60b5537020 - pristine_git_object: 673a5240670891a939e6cc16181555f66c1cf526 + last_write_checksum: sha1:fe826b324147c4ea5b4906f29b7616f3652f0140 + pristine_git_object: 9cf7fec996bac21f0fdf64ffab211c9d06cb832f src/main/java/co/novu/utils/RequestMetadata.java: id: dbca31b65a61 last_write_checksum: sha1:1f0008a446c6b499fd71e6685f7cf7e2a66a5eda @@ -7628,8 +7604,8 @@ trackedFiles: pristine_git_object: 016df5f3ca97d7c5cc0e443e75e387990f9ff833 src/main/java/co/novu/utils/Security.java: id: 97326fcb4a7b - last_write_checksum: sha1:613d974c001ff494e529c3f15b90f1d8128bcd95 - pristine_git_object: 9c5d729c2a0e4472c8145fb402913528e07a7ac9 + last_write_checksum: sha1:bf1a21610c5c2d3a42c45b1992f7387b655e8ea9 + pristine_git_object: b701675da22f58ae593c15bc2c8af0945d9e36fe src/main/java/co/novu/utils/SecurityMetadata.java: id: f85bc89f790c last_write_checksum: sha1:de6c83d9190ecae3f4cd0f84ab38d361c05ac477 @@ -7644,8 +7620,8 @@ trackedFiles: pristine_git_object: d06af25d783c6451003c0a8b42aff78ce447e9d9 src/main/java/co/novu/utils/SpeakeasyHTTPClient.java: id: 70347640db04 - last_write_checksum: sha1:846669ad6770f5590b986f8f6153887c1ee354e1 - pristine_git_object: 830e93ade96a28658b2580ee79337d8bdbf9eed2 + last_write_checksum: sha1:b125408537a084f7d0746a23470ee21c3445c3a9 + pristine_git_object: 0bc1c8cb34de2d307e9ee38bd10561b25eb53a0f src/main/java/co/novu/utils/SpeakeasyLogger.java: id: cd82de2b2274 last_write_checksum: sha1:fe2c30a22be3c5d584b81b9766d9f9b7efdcc742 @@ -7656,8 +7632,8 @@ trackedFiles: pristine_git_object: 7b1bbfd9ab9d747d385a734809bed4887c964f27 src/main/java/co/novu/utils/StreamingParser.java: id: 26c06d644d58 - last_write_checksum: sha1:ad371da6d6ce0a90fe46d645500ca327accb8542 - pristine_git_object: 5e395b77bc537931bcb71dc69bea15aea67caccd + last_write_checksum: sha1:fb327eef9afc34290db9cb5e7706d9319772f779 + pristine_git_object: 759322653a15af1b9f41b6ca0c1e0d7a20887b75 src/main/java/co/novu/utils/TypedObject.java: id: 69cc6ad85e2f last_write_checksum: sha1:0a870efb02cb74fd7ed10c5cd370681f8ec24fa2 @@ -7676,12 +7652,12 @@ trackedFiles: pristine_git_object: 9960c147160e2182e18939d45de132c203c3df8b src/main/java/co/novu/utils/Utils.java: id: 5354c18edd72 - last_write_checksum: sha1:909cfe1d9b430b22529c961a5e791cfeead09fd1 - pristine_git_object: 039642c9ffbe6e9c02f7cf2b2776b6c9898e66af + last_write_checksum: sha1:73d92343e55822497b2682db10506eaa32bba9e7 + pristine_git_object: 30d53d28deff6a2345093556d77e0a3affc30b59 src/main/java/co/novu/utils/reactive/EventStream.java: id: 54e371592c06 - last_write_checksum: sha1:ed912e2f459fda27e14ac7627e984140a5e6fbd9 - pristine_git_object: 507494c1951c59eda717f99d3d2537b191e245c2 + last_write_checksum: sha1:e92f7a38c43d4ca9898f787c16fd8dec759737de + pristine_git_object: 838c5d306f29d61d4e7dc682f9957e84115a3c80 src/main/java/co/novu/utils/reactive/ReactiveUtils.java: id: 756072bd658e last_write_checksum: sha1:f4d33adb4a9a2199c21172385b778e4a98274d17 @@ -9237,5 +9213,7 @@ examples: examplesVersion: 1.0.2 releaseNotes: | ## Java SDK Changes: - * `novu.topics.upsert()`: **Added** - * `novu.topics.create()`: **Deleted** **Breaking** :warning: + * `novu.subscribers.messages.updateActionStatus()`: `response` **Changed** (Breaking ⚠️) + * `novu.messages.list()`: `response.data[]` **Changed** (Breaking ⚠️) + * `novu.subscribersMessages.markAllAs()`: `response.[]` **Changed** (Breaking ⚠️) + * `novu.subscribersNotifications.getFeed()`: `response.data[].cta.action.result.payload` **Changed** (Breaking ⚠️) diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index b9d754bc..948d5212 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -14,6 +14,7 @@ generation: securityFeb2025: true sharedErrorComponentsApr2025: true sharedNestedComponentsJan2026: true + nameOverrideFeb2026: false auth: oAuth2ClientCredentialsEnabled: true oAuth2PasswordEnabled: true @@ -23,13 +24,14 @@ generation: schemas: allOfMergeStrategy: shallowMerge requestBodyFieldName: body + versioningStrategy: automatic persistentEdits: {} tests: generateTests: false generateNewTests: true skipResponseBodyAssertions: false java: - version: 3.12.0 + version: 3.13.0 additionalDependencies: [] additionalPlugins: [] artifactID: novu @@ -41,10 +43,12 @@ java: companyURL: https://novu.co defaultErrorName: APIException enableCustomCodeRegions: false + enableFormatting: false enableSlf4jLogging: true enableStreamingUploads: true flattenGlobalSecurity: true forwardCompatibleEnumsByDefault: true + forwardCompatibleUnionsByDefault: "false" generateOptionalUnionAccessors: true generateSpringBootStarter: true githubURL: github.com/novuhq/novu-java @@ -67,10 +71,10 @@ java: maxMethodParams: 4 multipartArrayFormat: standard nullFriendlyParameters: true - openUnions: true operationScopedParams: true outputModelSuffix: output packageName: co.novu projectName: novu + respectTitlesForPrimitiveUnionMembers: false templateVersion: v2 unionStrategy: populated-fields diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 39b520d9..102d6efd 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,4 +1,4 @@ -speakeasyVersion: 1.696.0 +speakeasyVersion: 1.723.0 sources: 'DEPRECATED: Novu API. Use -openapi.{json,yaml} instead.': sourceNamespace: novu-oas @@ -9,20 +9,20 @@ sources: - 3.12.0 novu-OAS: sourceNamespace: novu-oas - sourceRevisionDigest: sha256:a4fbb15bb61b8963d50031aae18f985aceda5366f1006f4a94cc46a30b5ec47b - sourceBlobDigest: sha256:b05171ab57555446bc0e3be838b9667f5c44b575222c90ee36a7ab1416cefe1f + sourceRevisionDigest: sha256:17fc28f18d91df220a9de6e2c75cd3b666184d942a96db91a9d603bfe7854bcb + sourceBlobDigest: sha256:a874a5b9654c9565f69db73eb0b4f1d0a2569d0e37e750a69fe5bfcb2bc6054b tags: - latest - - speakeasy-sdk-regen-next-1769072241 - - 3.12.0 + - speakeasy-sdk-regen-next-1769213168 + - 3.13.0 targets: novu: source: novu-OAS sourceNamespace: novu-oas - sourceRevisionDigest: sha256:a4fbb15bb61b8963d50031aae18f985aceda5366f1006f4a94cc46a30b5ec47b - sourceBlobDigest: sha256:b05171ab57555446bc0e3be838b9667f5c44b575222c90ee36a7ab1416cefe1f + sourceRevisionDigest: sha256:17fc28f18d91df220a9de6e2c75cd3b666184d942a96db91a9d603bfe7854bcb + sourceBlobDigest: sha256:a874a5b9654c9565f69db73eb0b4f1d0a2569d0e37e750a69fe5bfcb2bc6054b codeSamplesNamespace: novu-oas-java-code-samples - codeSamplesRevisionDigest: sha256:9eecd94f19a0c7e69f99232c659351eed0e2f4b81e96c62631fa1f404239ef91 + codeSamplesRevisionDigest: sha256:5c2d4382f80ca859d4e2dc5a96f870c99a79ee4de6c5065fefeb34d9ba30ce97 workflow: workflowVersion: 1.0.0 speakeasyVersion: latest diff --git a/README.md b/README.md index 045608d8..ff5f41f5 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ The samples below show how a published SDK artifact is used: Gradle: ```groovy -implementation 'co.novu:novu:3.12.0' +implementation 'co.novu:novu:3.13.0' ``` Maven: @@ -58,7 +58,7 @@ Maven: co.novu novu - 3.12.0 + 3.13.0 ``` @@ -482,7 +482,7 @@ public class Application { #### [Environments.Tags](docs/sdks/tags/README.md) -* [get](docs/sdks/tags/README.md#get) - Get environment tags +* [get](docs/sdks/tags/README.md#get) - List environment tags ### [Integrations](docs/sdks/integrations/README.md) @@ -571,7 +571,7 @@ public class Application { * [modify](docs/sdks/topics/README.md#modify) - Update a topic * [remove](docs/sdks/topics/README.md#remove) - Delete a topic * [createSubscription](docs/sdks/topics/README.md#createsubscription) - Create topic subscriptions -* [getSubscriptionById](docs/sdks/topics/README.md#getsubscriptionbyid) - Get a topic subscription +* [getSubscriptionById](docs/sdks/topics/README.md#getsubscriptionbyid) - Retrieve a topic subscription ### [Topics.Subscribers](docs/sdks/topicssubscribers/README.md) diff --git a/RELEASES.md b/RELEASES.md index b1857cf4..40a1b956 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,4 +8,14 @@ Based on: ### Generated - [java v3.12.0] . ### Releases -- [Maven Central v3.12.0] https://central.sonatype.com/artifact/co.novu/novu/3.12.0 - . \ No newline at end of file +- [Maven Central v3.12.0] https://central.sonatype.com/artifact/co.novu/novu/3.12.0 - . + +## 2026-02-23 00:07:27 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.723.0 (2.835.2) https://github.com/speakeasy-api/speakeasy +### Generated +- [java v3.13.0] . +### Releases +- [Maven Central v3.13.0] https://central.sonatype.com/artifact/co.novu/novu/3.13.0 - . \ No newline at end of file diff --git a/docs/models/components/MessageActionResult.md b/docs/models/components/MessageActionResult.md index 3b403eaf..080e52d3 100644 --- a/docs/models/components/MessageActionResult.md +++ b/docs/models/components/MessageActionResult.md @@ -3,7 +3,7 @@ ## Fields -| Field | Type | Required | Description | -| ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| `payload` | [Optional\](../../models/components/MessageActionResultPayload.md) | :heavy_minus_sign: | Payload of the action result | -| `type` | [Optional\](../../models/components/ButtonTypeEnum.md) | :heavy_minus_sign: | Type of button for the action result | \ No newline at end of file +| Field | Type | Required | Description | +| ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| `payload` | Map\ | :heavy_minus_sign: | Payload of the action result | +| `type` | [Optional\](../../models/components/ButtonTypeEnum.md) | :heavy_minus_sign: | Type of button for the action result | \ No newline at end of file diff --git a/docs/models/components/MessageActionResultPayload.md b/docs/models/components/MessageActionResultPayload.md deleted file mode 100644 index 42af3bf8..00000000 --- a/docs/models/components/MessageActionResultPayload.md +++ /dev/null @@ -1,9 +0,0 @@ -# MessageActionResultPayload - -Payload of the action result - - -## Fields - -| Field | Type | Required | Description | -| ----------- | ----------- | ----------- | ----------- | \ No newline at end of file diff --git a/docs/models/components/MessageResponseDto.md b/docs/models/components/MessageResponseDto.md index f2418961..a4e410bf 100644 --- a/docs/models/components/MessageResponseDto.md +++ b/docs/models/components/MessageResponseDto.md @@ -37,6 +37,6 @@ | `status` | [MessageStatusEnum](../../models/components/MessageStatusEnum.md) | :heavy_check_mark: | Status of the message | | | `errorId` | *Optional\* | :heavy_minus_sign: | Error ID if the message has an error | | | `errorText` | *Optional\* | :heavy_minus_sign: | Error text if the message has an error | | -| `payload` | [Optional\](../../models/components/MessageResponseDtoPayload.md) | :heavy_minus_sign: | The payload that was used to send the notification trigger | | -| `overrides` | [Optional\](../../models/components/MessageResponseDtoOverrides.md) | :heavy_minus_sign: | Provider specific overrides used when triggering the notification | | +| `payload` | Map\ | :heavy_minus_sign: | The payload that was used to send the notification trigger | | +| `overrides` | Map\ | :heavy_minus_sign: | Provider specific overrides used when triggering the notification | | | `contextKeys` | List\<*String*> | :heavy_minus_sign: | Context (single or multi) in which the message was sent | [
"tenant:org-123",
"region:us-east-1"
] | \ No newline at end of file diff --git a/docs/models/components/MessageResponseDtoOverrides.md b/docs/models/components/MessageResponseDtoOverrides.md deleted file mode 100644 index b68cdd52..00000000 --- a/docs/models/components/MessageResponseDtoOverrides.md +++ /dev/null @@ -1,9 +0,0 @@ -# MessageResponseDtoOverrides - -Provider specific overrides used when triggering the notification - - -## Fields - -| Field | Type | Required | Description | -| ----------- | ----------- | ----------- | ----------- | \ No newline at end of file diff --git a/docs/models/components/MessageResponseDtoPayload.md b/docs/models/components/MessageResponseDtoPayload.md deleted file mode 100644 index 9e8f637a..00000000 --- a/docs/models/components/MessageResponseDtoPayload.md +++ /dev/null @@ -1,9 +0,0 @@ -# MessageResponseDtoPayload - -The payload that was used to send the notification trigger - - -## Fields - -| Field | Type | Required | Description | -| ----------- | ----------- | ----------- | ----------- | \ No newline at end of file diff --git a/docs/sdks/subscribers/README.md b/docs/sdks/subscribers/README.md index 330b148d..5fa94aef 100644 --- a/docs/sdks/subscribers/README.md +++ b/docs/sdks/subscribers/README.md @@ -2,6 +2,9 @@ ## Overview +A subscriber in Novu represents someone who should receive a message. A subscriber's profile information contains important attributes about the subscriber that will be used in messages (name, email). The subscriber object can contain other key-value pairs that can be used to further personalize your messages. + + ### Available Operations * [search](#search) - Search subscribers diff --git a/docs/sdks/tags/README.md b/docs/sdks/tags/README.md index 4ddbf927..81c64ed9 100644 --- a/docs/sdks/tags/README.md +++ b/docs/sdks/tags/README.md @@ -4,7 +4,7 @@ ### Available Operations -* [get](#get) - Get environment tags +* [get](#get) - List environment tags ## get diff --git a/docs/sdks/topics/README.md b/docs/sdks/topics/README.md index 69e48651..e92ec42a 100644 --- a/docs/sdks/topics/README.md +++ b/docs/sdks/topics/README.md @@ -2,6 +2,9 @@ ## Overview +Topics are a way to group subscribers together so that they can be notified of events at once. A topic is identified by a custom key. This can be helpful for things like sending out marketing emails or notifying users of new features. Topics can also be used to send notifications to the subscribers who have been grouped together based on their interests, location, activities and much more. + + ### Available Operations * [fetchAll](#fetchall) - List all topics @@ -10,7 +13,7 @@ * [modify](#modify) - Update a topic * [remove](#remove) - Delete a topic * [createSubscription](#createsubscription) - Create topic subscriptions -* [getSubscriptionById](#getsubscriptionbyid) - Get a topic subscription +* [getSubscriptionById](#getsubscriptionbyid) - Retrieve a topic subscription ## fetchAll @@ -395,7 +398,7 @@ public class Application { ## getSubscriptionById -Get a subscription by its unique identifier for a topic. +Retrieve a subscription by its unique identifier for a topic. ### Example Usage diff --git a/docs/sdks/translations/README.md b/docs/sdks/translations/README.md index 9cc85cca..ee9ecb7c 100644 --- a/docs/sdks/translations/README.md +++ b/docs/sdks/translations/README.md @@ -2,6 +2,9 @@ ## Overview +Used to localize your notifications to different languages. + + ### Available Operations * [create](#create) - Create a translation diff --git a/gradle.properties b/gradle.properties index 483db5e0..c99b070f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ groupId=co.novu artifactId=novu -version=3.12.0 +version=3.13.0 org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g diff --git a/src/main/java/co/novu/AsyncNovu.java b/src/main/java/co/novu/AsyncNovu.java index eead37f4..96425325 100644 --- a/src/main/java/co/novu/AsyncNovu.java +++ b/src/main/java/co/novu/AsyncNovu.java @@ -56,13 +56,33 @@ public class AsyncNovu { *

https://docs.novu.co/platform/workflow/layouts */ private final AsyncLayouts layouts; - + /** + * A subscriber in Novu represents someone who should receive a message. A subscriber's profile + * information contains important attributes about the subscriber that will be used in messages (name, + * email). The subscriber object can contain other key-value pairs that can be used to further + * personalize your messages. + * + *

https://docs.novu.co/subscribers/subscribers + */ private final AsyncSubscribers subscribers; private final AsyncSubscribersTopics subscribersTopics; - + /** + * Topics are a way to group subscribers together so that they can be notified of events at once. A + * topic is identified by a custom key. This can be helpful for things like sending out marketing + * emails or notifying users of new features. + * + *

Topics can also be used to send notifications to the subscribers who have been grouped together + * based on their interests, location, activities and much more. + * + *

https://docs.novu.co/subscribers/topics + */ private final AsyncTopics topics; - + /** + * Used to localize your notifications to different languages. + * + *

https://docs.novu.co/platform/workflow/translations + */ private final AsyncTranslations translations; /** * All notifications are sent via a workflow. Each workflow acts as a container for the logic and @@ -125,7 +145,14 @@ public AsyncActivity activity() { public AsyncLayouts layouts() { return layouts; } - + /** + * A subscriber in Novu represents someone who should receive a message. A subscriber's profile + * information contains important attributes about the subscriber that will be used in messages (name, + * email). The subscriber object can contain other key-value pairs that can be used to further + * personalize your messages. + * + *

https://docs.novu.co/subscribers/subscribers + */ public AsyncSubscribers subscribers() { return subscribers; } @@ -133,11 +160,24 @@ public AsyncSubscribers subscribers() { public AsyncSubscribersTopics subscribersTopics() { return subscribersTopics; } - + /** + * Topics are a way to group subscribers together so that they can be notified of events at once. A + * topic is identified by a custom key. This can be helpful for things like sending out marketing + * emails or notifying users of new features. + * + *

Topics can also be used to send notifications to the subscribers who have been grouped together + * based on their interests, location, activities and much more. + * + *

https://docs.novu.co/subscribers/topics + */ public AsyncTopics topics() { return topics; } - + /** + * Used to localize your notifications to different languages. + * + *

https://docs.novu.co/platform/workflow/translations + */ public AsyncTranslations translations() { return translations; } diff --git a/src/main/java/co/novu/AsyncSubscribers.java b/src/main/java/co/novu/AsyncSubscribers.java index 0104611e..1084cd5a 100644 --- a/src/main/java/co/novu/AsyncSubscribers.java +++ b/src/main/java/co/novu/AsyncSubscribers.java @@ -59,7 +59,14 @@ import java.lang.String; import java.util.concurrent.CompletableFuture; - +/** + * A subscriber in Novu represents someone who should receive a message. A subscriber's profile + * information contains important attributes about the subscriber that will be used in messages (name, + * email). The subscriber object can contain other key-value pairs that can be used to further + * personalize your messages. + * + *

https://docs.novu.co/subscribers/subscribers + */ public class AsyncSubscribers { private static final Headers _headers = Headers.EMPTY; private final SDKConfiguration sdkConfiguration; diff --git a/src/main/java/co/novu/AsyncTags.java b/src/main/java/co/novu/AsyncTags.java index 60688aa9..65d76d54 100644 --- a/src/main/java/co/novu/AsyncTags.java +++ b/src/main/java/co/novu/AsyncTags.java @@ -38,7 +38,7 @@ public Tags sync() { /** - * Get environment tags + * List environment tags * *

Retrieve all unique tags used in workflows within the specified environment. These tags can be used * for filtering workflows. @@ -50,7 +50,7 @@ public EnvironmentsControllerGetEnvironmentTagsRequestBuilder get() { } /** - * Get environment tags + * List environment tags * *

Retrieve all unique tags used in workflows within the specified environment. These tags can be used * for filtering workflows. @@ -63,7 +63,7 @@ public CompletableFuture get(@ } /** - * Get environment tags + * List environment tags * *

Retrieve all unique tags used in workflows within the specified environment. These tags can be used * for filtering workflows. diff --git a/src/main/java/co/novu/AsyncTopics.java b/src/main/java/co/novu/AsyncTopics.java index 73fd700f..41a9dba6 100644 --- a/src/main/java/co/novu/AsyncTopics.java +++ b/src/main/java/co/novu/AsyncTopics.java @@ -44,7 +44,16 @@ import java.lang.String; import java.util.concurrent.CompletableFuture; - +/** + * Topics are a way to group subscribers together so that they can be notified of events at once. A + * topic is identified by a custom key. This can be helpful for things like sending out marketing + * emails or notifying users of new features. + * + *

Topics can also be used to send notifications to the subscribers who have been grouped together + * based on their interests, location, activities and much more. + * + *

https://docs.novu.co/subscribers/topics + */ public class AsyncTopics { private static final Headers _headers = Headers.EMPTY; private final SDKConfiguration sdkConfiguration; @@ -376,9 +385,9 @@ public CompletableFuture creat /** - * Get a topic subscription + * Retrieve a topic subscription * - *

Get a subscription by its unique identifier for a topic. + *

Retrieve a subscription by its unique identifier for a topic. * * @return The async call builder */ @@ -387,9 +396,9 @@ public TopicsControllerGetTopicSubscriptionRequestBuilder getSubscriptionById() } /** - * Get a topic subscription + * Retrieve a topic subscription * - *

Get a subscription by its unique identifier for a topic. + *

Retrieve a subscription by its unique identifier for a topic. * * @param topicKey The key identifier of the topic * @param identifier The unique identifier of the subscription @@ -402,9 +411,9 @@ public CompletableFuture getSubscr } /** - * Get a topic subscription + * Retrieve a topic subscription * - *

Get a subscription by its unique identifier for a topic. + *

Retrieve a subscription by its unique identifier for a topic. * * @param topicKey The key identifier of the topic * @param identifier The unique identifier of the subscription diff --git a/src/main/java/co/novu/AsyncTranslations.java b/src/main/java/co/novu/AsyncTranslations.java index 6b5107b4..90054832 100644 --- a/src/main/java/co/novu/AsyncTranslations.java +++ b/src/main/java/co/novu/AsyncTranslations.java @@ -56,7 +56,11 @@ import java.lang.String; import java.util.concurrent.CompletableFuture; - +/** + * Used to localize your notifications to different languages. + * + *

https://docs.novu.co/platform/workflow/translations + */ public class AsyncTranslations { private static final Headers _headers = Headers.EMPTY; private final SDKConfiguration sdkConfiguration; diff --git a/src/main/java/co/novu/Novu.java b/src/main/java/co/novu/Novu.java index 6d0e5303..dbd97cfa 100644 --- a/src/main/java/co/novu/Novu.java +++ b/src/main/java/co/novu/Novu.java @@ -79,16 +79,36 @@ public class Novu { */ private final Layouts layouts; - + /** + * A subscriber in Novu represents someone who should receive a message. A subscriber's profile + * information contains important attributes about the subscriber that will be used in messages (name, + * email). The subscriber object can contain other key-value pairs that can be used to further + * personalize your messages. + * + *

https://docs.novu.co/subscribers/subscribers + */ private final Subscribers subscribers; private final SubscribersTopics subscribersTopics; - + /** + * Topics are a way to group subscribers together so that they can be notified of events at once. A + * topic is identified by a custom key. This can be helpful for things like sending out marketing + * emails or notifying users of new features. + * + *

Topics can also be used to send notifications to the subscribers who have been grouped together + * based on their interests, location, activities and much more. + * + *

https://docs.novu.co/subscribers/topics + */ private final Topics topics; - + /** + * Used to localize your notifications to different languages. + * + *

https://docs.novu.co/platform/workflow/translations + */ private final Translations translations; /** @@ -165,7 +185,14 @@ public Layouts layouts() { return layouts; } - + /** + * A subscriber in Novu represents someone who should receive a message. A subscriber's profile + * information contains important attributes about the subscriber that will be used in messages (name, + * email). The subscriber object can contain other key-value pairs that can be used to further + * personalize your messages. + * + *

https://docs.novu.co/subscribers/subscribers + */ public Subscribers subscribers() { return subscribers; } @@ -175,12 +202,25 @@ public SubscribersTopics subscribersTopics() { return subscribersTopics; } - + /** + * Topics are a way to group subscribers together so that they can be notified of events at once. A + * topic is identified by a custom key. This can be helpful for things like sending out marketing + * emails or notifying users of new features. + * + *

Topics can also be used to send notifications to the subscribers who have been grouped together + * based on their interests, location, activities and much more. + * + *

https://docs.novu.co/subscribers/topics + */ public Topics topics() { return topics; } - + /** + * Used to localize your notifications to different languages. + * + *

https://docs.novu.co/platform/workflow/translations + */ public Translations translations() { return translations; } diff --git a/src/main/java/co/novu/SDKConfiguration.java b/src/main/java/co/novu/SDKConfiguration.java index 6ee37664..b7e4f8f5 100644 --- a/src/main/java/co/novu/SDKConfiguration.java +++ b/src/main/java/co/novu/SDKConfiguration.java @@ -18,9 +18,9 @@ public class SDKConfiguration { private static final String LANGUAGE = "java"; - public static final String OPENAPI_DOC_VERSION = "3.12.0"; - public static final String SDK_VERSION = "3.12.0"; - public static final String GEN_VERSION = "2.799.0"; + public static final String OPENAPI_DOC_VERSION = "3.13.0"; + public static final String SDK_VERSION = "3.13.0"; + public static final String GEN_VERSION = "2.835.2"; private static final String BASE_PACKAGE = "co.novu"; public static final String USER_AGENT = String.format("speakeasy-sdk/%s %s %s %s %s", diff --git a/src/main/java/co/novu/Subscribers.java b/src/main/java/co/novu/Subscribers.java index 85b0612a..abdbca9d 100644 --- a/src/main/java/co/novu/Subscribers.java +++ b/src/main/java/co/novu/Subscribers.java @@ -58,7 +58,14 @@ import java.lang.Boolean; import java.lang.String; - +/** + * A subscriber in Novu represents someone who should receive a message. A subscriber's profile + * information contains important attributes about the subscriber that will be used in messages (name, + * email). The subscriber object can contain other key-value pairs that can be used to further + * personalize your messages. + * + *

https://docs.novu.co/subscribers/subscribers + */ public class Subscribers { private static final Headers _headers = Headers.EMPTY; private final SDKConfiguration sdkConfiguration; diff --git a/src/main/java/co/novu/Tags.java b/src/main/java/co/novu/Tags.java index cb5257c2..995ea1c2 100644 --- a/src/main/java/co/novu/Tags.java +++ b/src/main/java/co/novu/Tags.java @@ -36,7 +36,7 @@ public AsyncTags async() { } /** - * Get environment tags + * List environment tags * *

Retrieve all unique tags used in workflows within the specified environment. These tags can be used * for filtering workflows. @@ -48,7 +48,7 @@ public EnvironmentsControllerGetEnvironmentTagsRequestBuilder get() { } /** - * Get environment tags + * List environment tags * *

Retrieve all unique tags used in workflows within the specified environment. These tags can be used * for filtering workflows. @@ -62,7 +62,7 @@ public EnvironmentsControllerGetEnvironmentTagsResponse get(@Nonnull String envi } /** - * Get environment tags + * List environment tags * *

Retrieve all unique tags used in workflows within the specified environment. These tags can be used * for filtering workflows. diff --git a/src/main/java/co/novu/Topics.java b/src/main/java/co/novu/Topics.java index ad872b17..0f87d7f3 100644 --- a/src/main/java/co/novu/Topics.java +++ b/src/main/java/co/novu/Topics.java @@ -43,7 +43,16 @@ import java.lang.Boolean; import java.lang.String; - +/** + * Topics are a way to group subscribers together so that they can be notified of events at once. A + * topic is identified by a custom key. This can be helpful for things like sending out marketing + * emails or notifying users of new features. + * + *

Topics can also be used to send notifications to the subscribers who have been grouped together + * based on their interests, location, activities and much more. + * + *

https://docs.novu.co/subscribers/topics + */ public class Topics { private static final Headers _headers = Headers.EMPTY; private final SDKConfiguration sdkConfiguration; @@ -359,9 +368,9 @@ public TopicsControllerCreateTopicSubscriptionsResponse createSubscription( } /** - * Get a topic subscription + * Retrieve a topic subscription * - *

Get a subscription by its unique identifier for a topic. + *

Retrieve a subscription by its unique identifier for a topic. * * @return The call builder */ @@ -370,9 +379,9 @@ public TopicsControllerGetTopicSubscriptionRequestBuilder getSubscriptionById() } /** - * Get a topic subscription + * Retrieve a topic subscription * - *

Get a subscription by its unique identifier for a topic. + *

Retrieve a subscription by its unique identifier for a topic. * * @param topicKey The key identifier of the topic * @param identifier The unique identifier of the subscription @@ -385,9 +394,9 @@ public TopicsControllerGetTopicSubscriptionResponse getSubscriptionById(@Nonnull } /** - * Get a topic subscription + * Retrieve a topic subscription * - *

Get a subscription by its unique identifier for a topic. + *

Retrieve a subscription by its unique identifier for a topic. * * @param topicKey The key identifier of the topic * @param identifier The unique identifier of the subscription diff --git a/src/main/java/co/novu/Translations.java b/src/main/java/co/novu/Translations.java index a367ec3f..9b6315f2 100644 --- a/src/main/java/co/novu/Translations.java +++ b/src/main/java/co/novu/Translations.java @@ -55,7 +55,11 @@ import jakarta.annotation.Nullable; import java.lang.String; - +/** + * Used to localize your notifications to different languages. + * + *

https://docs.novu.co/platform/workflow/translations + */ public class Translations { private static final Headers _headers = Headers.EMPTY; private final SDKConfiguration sdkConfiguration; diff --git a/src/main/java/co/novu/models/components/MessageActionResult.java b/src/main/java/co/novu/models/components/MessageActionResult.java index 28a000b7..745e9143 100644 --- a/src/main/java/co/novu/models/components/MessageActionResult.java +++ b/src/main/java/co/novu/models/components/MessageActionResult.java @@ -9,8 +9,10 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.annotation.Nullable; +import java.lang.Object; import java.lang.Override; import java.lang.String; +import java.util.Map; import java.util.Optional; @@ -20,7 +22,7 @@ public class MessageActionResult { */ @JsonInclude(Include.NON_ABSENT) @JsonProperty("payload") - private MessageActionResultPayload payload; + private Map payload; /** * Type of button for the action result @@ -31,7 +33,7 @@ public class MessageActionResult { @JsonCreator public MessageActionResult( - @JsonProperty("payload") @Nullable MessageActionResultPayload payload, + @JsonProperty("payload") @Nullable Map payload, @JsonProperty("type") @Nullable ButtonTypeEnum type) { this.payload = payload; this.type = type; @@ -44,7 +46,7 @@ public MessageActionResult() { /** * Payload of the action result */ - public Optional payload() { + public Optional> payload() { return Optional.ofNullable(this.payload); } @@ -63,7 +65,7 @@ public static Builder builder() { /** * Payload of the action result */ - public MessageActionResult withPayload(@Nullable MessageActionResultPayload payload) { + public MessageActionResult withPayload(@Nullable Map payload) { this.payload = payload; return this; } @@ -108,7 +110,7 @@ public String toString() { @SuppressWarnings("UnusedReturnValue") public final static class Builder { - private MessageActionResultPayload payload; + private Map payload; private ButtonTypeEnum type; @@ -119,7 +121,7 @@ private Builder() { /** * Payload of the action result */ - public Builder payload(@Nullable MessageActionResultPayload payload) { + public Builder payload(@Nullable Map payload) { this.payload = payload; return this; } diff --git a/src/main/java/co/novu/models/components/MessageActionResultPayload.java b/src/main/java/co/novu/models/components/MessageActionResultPayload.java deleted file mode 100644 index 46e40f0e..00000000 --- a/src/main/java/co/novu/models/components/MessageActionResultPayload.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ -package co.novu.models.components; - -import co.novu.utils.Utils; -import com.fasterxml.jackson.annotation.JsonCreator; -import java.lang.Override; -import java.lang.String; - -/** - * MessageActionResultPayload - * - *

Payload of the action result - */ -public class MessageActionResultPayload { - @JsonCreator - public MessageActionResultPayload() { - } - - public static Builder builder() { - return new Builder(); - } - - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return Utils.enhancedHash( - ); - } - - @Override - public String toString() { - return Utils.toString(MessageActionResultPayload.class); - } - - @SuppressWarnings("UnusedReturnValue") - public final static class Builder { - - private Builder() { - // force use of static builder() method - } - - public MessageActionResultPayload build() { - return new MessageActionResultPayload( - ); - } - - } -} diff --git a/src/main/java/co/novu/models/components/MessageResponseDto.java b/src/main/java/co/novu/models/components/MessageResponseDto.java index fa82090b..a8c96383 100644 --- a/src/main/java/co/novu/models/components/MessageResponseDto.java +++ b/src/main/java/co/novu/models/components/MessageResponseDto.java @@ -10,9 +10,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +import java.lang.Object; import java.lang.Override; import java.lang.String; import java.util.List; +import java.util.Map; import java.util.Optional; import org.openapitools.jackson.nullable.JsonNullable; @@ -237,14 +239,14 @@ public class MessageResponseDto { */ @JsonInclude(Include.NON_ABSENT) @JsonProperty("payload") - private MessageResponseDtoPayload payload; + private Map payload; /** * Provider specific overrides used when triggering the notification */ @JsonInclude(Include.NON_ABSENT) @JsonProperty("overrides") - private MessageResponseDtoOverrides overrides; + private Map overrides; /** * Context (single or multi) in which the message was sent @@ -287,8 +289,8 @@ public MessageResponseDto( @JsonProperty("status") @Nonnull MessageStatusEnum status, @JsonProperty("errorId") @Nullable String errorId, @JsonProperty("errorText") @Nullable String errorText, - @JsonProperty("payload") @Nullable MessageResponseDtoPayload payload, - @JsonProperty("overrides") @Nullable MessageResponseDtoOverrides overrides, + @JsonProperty("payload") @Nullable Map payload, + @JsonProperty("overrides") @Nullable Map overrides, @JsonProperty("contextKeys") @Nullable List contextKeys) { this.id = id; this.templateId = Optional.ofNullable(templateId) @@ -594,14 +596,14 @@ public Optional errorText() { /** * The payload that was used to send the notification trigger */ - public Optional payload() { + public Optional> payload() { return Optional.ofNullable(this.payload); } /** * Provider specific overrides used when triggering the notification */ - public Optional overrides() { + public Optional> overrides() { return Optional.ofNullable(this.overrides); } @@ -909,7 +911,7 @@ public MessageResponseDto withErrorText(@Nullable String errorText) { /** * The payload that was used to send the notification trigger */ - public MessageResponseDto withPayload(@Nullable MessageResponseDtoPayload payload) { + public MessageResponseDto withPayload(@Nullable Map payload) { this.payload = payload; return this; } @@ -918,7 +920,7 @@ public MessageResponseDto withPayload(@Nullable MessageResponseDtoPayload payloa /** * Provider specific overrides used when triggering the notification */ - public MessageResponseDto withOverrides(@Nullable MessageResponseDtoOverrides overrides) { + public MessageResponseDto withOverrides(@Nullable Map overrides) { this.overrides = overrides; return this; } @@ -1104,9 +1106,9 @@ public final static class Builder { private String errorText; - private MessageResponseDtoPayload payload; + private Map payload; - private MessageResponseDtoOverrides overrides; + private Map overrides; private List contextKeys; @@ -1374,7 +1376,7 @@ public Builder errorText(@Nullable String errorText) { /** * The payload that was used to send the notification trigger */ - public Builder payload(@Nullable MessageResponseDtoPayload payload) { + public Builder payload(@Nullable Map payload) { this.payload = payload; return this; } @@ -1382,7 +1384,7 @@ public Builder payload(@Nullable MessageResponseDtoPayload payload) { /** * Provider specific overrides used when triggering the notification */ - public Builder overrides(@Nullable MessageResponseDtoOverrides overrides) { + public Builder overrides(@Nullable Map overrides) { this.overrides = overrides; return this; } diff --git a/src/main/java/co/novu/models/components/MessageResponseDtoOverrides.java b/src/main/java/co/novu/models/components/MessageResponseDtoOverrides.java deleted file mode 100644 index 876672b4..00000000 --- a/src/main/java/co/novu/models/components/MessageResponseDtoOverrides.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ -package co.novu.models.components; - -import co.novu.utils.Utils; -import com.fasterxml.jackson.annotation.JsonCreator; -import java.lang.Override; -import java.lang.String; - -/** - * MessageResponseDtoOverrides - * - *

Provider specific overrides used when triggering the notification - */ -public class MessageResponseDtoOverrides { - @JsonCreator - public MessageResponseDtoOverrides() { - } - - public static Builder builder() { - return new Builder(); - } - - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return Utils.enhancedHash( - ); - } - - @Override - public String toString() { - return Utils.toString(MessageResponseDtoOverrides.class); - } - - @SuppressWarnings("UnusedReturnValue") - public final static class Builder { - - private Builder() { - // force use of static builder() method - } - - public MessageResponseDtoOverrides build() { - return new MessageResponseDtoOverrides( - ); - } - - } -} diff --git a/src/main/java/co/novu/models/components/MessageResponseDtoPayload.java b/src/main/java/co/novu/models/components/MessageResponseDtoPayload.java deleted file mode 100644 index ddbbfb03..00000000 --- a/src/main/java/co/novu/models/components/MessageResponseDtoPayload.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ -package co.novu.models.components; - -import co.novu.utils.Utils; -import com.fasterxml.jackson.annotation.JsonCreator; -import java.lang.Override; -import java.lang.String; - -/** - * MessageResponseDtoPayload - * - *

The payload that was used to send the notification trigger - */ -public class MessageResponseDtoPayload { - @JsonCreator - public MessageResponseDtoPayload() { - } - - public static Builder builder() { - return new Builder(); - } - - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return Utils.enhancedHash( - ); - } - - @Override - public String toString() { - return Utils.toString(MessageResponseDtoPayload.class); - } - - @SuppressWarnings("UnusedReturnValue") - public final static class Builder { - - private Builder() { - // force use of static builder() method - } - - public MessageResponseDtoPayload build() { - return new MessageResponseDtoPayload( - ); - } - - } -} diff --git a/src/main/java/co/novu/utils/EventStream.java b/src/main/java/co/novu/utils/EventStream.java index 84220e05..64a83bcd 100644 --- a/src/main/java/co/novu/utils/EventStream.java +++ b/src/main/java/co/novu/utils/EventStream.java @@ -74,6 +74,8 @@ public final class EventStream implements Iterable, AutoCloseable { private final TypeReference typeReference; private final ObjectMapper mapper; private final Optional terminalMessage; + private boolean terminated = false; + private boolean closed = false; // Internal use only public EventStream(InputStream in, TypeReference typeReference, ObjectMapper mapper, Optional terminalMessage) { @@ -93,17 +95,25 @@ public EventStream(InputStream in, TypeReference typeReference, ObjectMapper * @throws IOException when parsing the next message. */ public Optional next() throws IOException { - Optional result = parser.next() // - .filter(x -> { - boolean isTerminal = terminalMessage.map(sentinel -> sentinel.equals(x.data())).orElse(false); - if (isTerminal && logger.isTraceEnabled()) { - logger.trace("Terminal message encountered in EventStream"); - } - return !isTerminal; - }) - .map(x -> Utils.asType(x, mapper, typeReference)); - - if (logger.isTraceEnabled() && result.isPresent()) { + if (terminated) { + return Optional.empty(); + } + Optional message = parser.next(); + if (message.isEmpty()) { + terminated = true; + return Optional.empty(); + } + EventStreamMessage msg = message.get(); + boolean isTerminal = terminalMessage.flatMap(sentinel -> msg.data().map(sentinel::equals)).orElse(false); + if (isTerminal) { + terminated = true; + if (logger.isTraceEnabled()) { + logger.trace("Terminal message encountered in EventStream"); + } + return Optional.empty(); + } + Optional result = Optional.of(Utils.asType(msg, mapper, typeReference)); + if (logger.isTraceEnabled()) { logger.trace("EventStream item processed"); } return result; @@ -162,10 +172,15 @@ public Stream stream() { @Override public void close() throws IOException { + closed = true; logger.debug("EventStream closed"); parser.close(); } + public boolean isClosed() { + return closed; + } + static class EventIterator implements Iterator { private final EventStream stream; private Optional next = Optional.empty(); diff --git a/src/main/java/co/novu/utils/EventStreamMessage.java b/src/main/java/co/novu/utils/EventStreamMessage.java index 865d54a1..163ba3ff 100644 --- a/src/main/java/co/novu/utils/EventStreamMessage.java +++ b/src/main/java/co/novu/utils/EventStreamMessage.java @@ -6,16 +6,13 @@ import java.util.Optional; public class EventStreamMessage { - + private final Optional event; private final Optional id; private final Optional retryMs; - private final String data; + private final Optional data; - public EventStreamMessage(Optional event, Optional id, Optional retryMs, String data) { - if (data == null) { - throw new IllegalArgumentException("data cannot be null"); - } + public EventStreamMessage(Optional event, Optional id, Optional retryMs, Optional data) { this.event = event; this.id = id; this.retryMs = retryMs; @@ -34,23 +31,21 @@ public Optional retryMs() { return retryMs; } - public String data() { + public Optional data() { return data; } public boolean isEmpty() { - return !event.isPresent() && !id().isPresent() && !retryMs().isPresent() && data.isEmpty(); + return !event.isPresent() && !id().isPresent() && !retryMs().isPresent() && !data.isPresent(); } - + @Override public String toString() { StringBuilder b = new StringBuilder(); event.ifPresent(value -> b.append("event: " + value + "\n")); id.ifPresent(value -> b.append("id: " + value + "\n")); retryMs.ifPresent(value -> b.append("retry: " + value + "\n")); - if (!data.isEmpty()) { - b.append("data: " + data); - } + data.ifPresent(value -> b.append("data: " + value)); return b.toString(); } } diff --git a/src/main/java/co/novu/utils/RequestBody.java b/src/main/java/co/novu/utils/RequestBody.java index 673a5240..9cf7fec9 100644 --- a/src/main/java/co/novu/utils/RequestBody.java +++ b/src/main/java/co/novu/utils/RequestBody.java @@ -47,6 +47,14 @@ public static SerializedBody serialize(Object request, String requestField, Stri request); } + // If no requestField specified, the request object IS the body — serialize it directly + // without attempting any field lookup. This is the case when an operation has no + // parameters alongside the body (i.e. IsRequestBody=true at the callsite). + if (requestField == null || requestField.isEmpty()) { + return serializeContentType(requestField, SERIALIZATION_METHOD_TO_CONTENT_TYPE.get(serializationMethod), + request); + } + Field reqField = null; try { diff --git a/src/main/java/co/novu/utils/Security.java b/src/main/java/co/novu/utils/Security.java index 9c5d729c..b701675d 100644 --- a/src/main/java/co/novu/utils/Security.java +++ b/src/main/java/co/novu/utils/Security.java @@ -141,8 +141,11 @@ private static void parseSecuritySchemeValue(HTTPRequest request, SecurityMetada case "bearer": request.addHeader(securityMetadata.name, Utils.prefixBearer(Utils.valToString(value))); break; + case "basic": + request.addHeader(securityMetadata.name, Utils.valToString(value)); + break; case "custom": - // customers are expected to consume the security object and transform requests + // customers are expected to consume the security object and transform requests // in their own BeforeRequest hook. break; default: diff --git a/src/main/java/co/novu/utils/SpeakeasyHTTPClient.java b/src/main/java/co/novu/utils/SpeakeasyHTTPClient.java index 830e93ad..0bc1c8cb 100644 --- a/src/main/java/co/novu/utils/SpeakeasyHTTPClient.java +++ b/src/main/java/co/novu/utils/SpeakeasyHTTPClient.java @@ -147,16 +147,21 @@ private HttpRequest logRequest(HttpRequest request, boolean logBody) { } private static HttpResponse logResponse(HttpResponse response, boolean logBody) throws IOException { + String contentType = response.headers().firstValue("Content-Type").orElse("application/octet-stream"); + slf4jLogger.debug("Received response: {}", response); + slf4jLogger.debug("Response headers: {}", redactHeaders(response.headers())); + + // skip caching for streaming responses - they may hang + if (contentType.startsWith("text/event-stream") || contentType.startsWith("application/x-ndjson")) { + return response; + } + // make the response re-readable by loading the response body into a byte array // and allowing the InputStream to be read many times response = Utils.cache(response); - slf4jLogger.debug("Received response: {}", response); - slf4jLogger.debug("Response headers: {}", redactHeaders(response.headers())); + // only log the response body if logBody is true and the content type is JSON or plain text - if (logBody && response.headers() // - .firstValue("Content-Type") // - .filter(x -> x.equals("application/json") || x.equals("text/plain")) // - .isPresent()) { + if (logBody && (contentType.startsWith("application/json") || contentType.startsWith("text/plain"))) { // the response is re-readable so we can read and close it without // affecting later processing of the response. diff --git a/src/main/java/co/novu/utils/StreamingParser.java b/src/main/java/co/novu/utils/StreamingParser.java index 5e395b77..75932265 100644 --- a/src/main/java/co/novu/utils/StreamingParser.java +++ b/src/main/java/co/novu/utils/StreamingParser.java @@ -6,8 +6,6 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Generic streaming parser that handles byte buffer management and delegates @@ -208,36 +206,37 @@ public Optional processContent(String content) { */ private static class SSEContentProcessor implements StreamContentProcessor { private static final String BYTE_ORDER_MARK = "\uFEFF"; - private static final Pattern LINE_PATTERN = Pattern.compile("^([a-zA-Z]+): ?(.*)$"); private static final char LINEFEED = '\n'; - // Message boundary patterns private static final byte CR = '\r'; private static final byte LF = '\n'; - private static final byte[] CRLF_CRLF = {CR, LF, CR, LF}; // \r\n\r\n - private static final byte[] CRLF_LF = {CR, LF, LF}; // \r\n\n - private static final byte[] LF_CRLF = {LF, CR, LF}; // \n\r\n - private static final byte[] LF_LF = {LF, LF}; // \n\n + private static final byte[][] BOUNDARY_PATTERNS = { + {CR, LF}, + {LF}, + {CR} + }; + + private Optional eventId = Optional.empty(); @Override public BoundaryInfo findBoundary(byte[] data, int limit) { - for (int i = 0; i < limit; i++) { - // Need at least 2 bytes for any boundary pattern - if (i + 1 >= limit) { - continue; - } - // Check longest patterns first to avoid partial matches - if (matchesPattern(data, i, limit, CRLF_CRLF)) { - return new BoundaryInfo(i, CRLF_CRLF.length); - } - if (matchesPattern(data, i, limit, CRLF_LF)) { - return new BoundaryInfo(i, CRLF_LF.length); - } - if (matchesPattern(data, i, limit, LF_CRLF)) { - return new BoundaryInfo(i, LF_CRLF.length); - } - if (matchesPattern(data, i, limit, LF_LF)) { - return new BoundaryInfo(i, LF_LF.length); + int lineStart = 0, i = lineStart; + while (i < limit) { + for (byte[] pattern : BOUNDARY_PATTERNS) { + if (matchesPattern(data, i, limit, pattern)) { + if (i == lineStart) { // empty line + int boundStart = i; + while (boundStart > 0 && (data[boundStart - 1] == CR || data[boundStart - 1] == LF)) { + boundStart--; + } + int boundLength = (lineStart - boundStart) + pattern.length; + return new BoundaryInfo(boundStart, boundLength); + } + lineStart = i + pattern.length; + i = lineStart - 1; + break; + } } + i++; } return new BoundaryInfo(-1, 0); } @@ -262,45 +261,52 @@ public String sanitizeContent(String rawContent, boolean isFirst) { private EventStreamMessage parseMessage(String text) { String[] lines = text.split("\n"); Optional event = Optional.empty(); - Optional id = Optional.empty(); Optional retryMs = Optional.empty(); - StringBuilder data = new StringBuilder(); - boolean firstData = true; + Optional data = Optional.empty(); for (String line : lines) { - // Skip comment lines if (line.startsWith(":")) { continue; } - Matcher m = LINE_PATTERN.matcher(line); - if (m.find()) { - String key = m.group(1).toLowerCase(); - String value = m.group(2); - switch (key) { - case "event": - event = Optional.of(value); - break; - case "id": - id = Optional.of(value); - break; - case "retry": - try { - retryMs = Optional.of(Integer.parseInt(value)); - } catch (NumberFormatException e) { - // ignore invalid retry values - } - break; - case "data": - if (!firstData) { - data.append(LINEFEED); - } - firstData = false; - data.append(value); - break; - // ignore unknown fields + String key; + String value; + int colonIndex = line.indexOf(':'); + if (colonIndex >= 0) { + key = line.substring(0, colonIndex); + value = line.substring(colonIndex + 1); + if (value.startsWith(" ")) { + value = value.substring(1); } + } else { + key = line; + value = ""; + } + switch (key) { + case "event": + event = Optional.of(value); + break; + case "id": + if (value.indexOf('\0') < 0) { + eventId = Optional.of(value); + } + break; + case "retry": + try { + retryMs = Optional.of(Integer.parseInt(value)); + } catch (NumberFormatException e) { + // ignore invalid retry values + } + break; + case "data": + if (data.isEmpty()) { + data = Optional.of(new StringBuilder()); + } else { + data.get().append(LINEFEED); + } + data.get().append(value); + break; } } - return new EventStreamMessage(event, id, retryMs, data.toString()); + return new EventStreamMessage(event, eventId, retryMs, data.map(StringBuilder::toString)); } } diff --git a/src/main/java/co/novu/utils/Utils.java b/src/main/java/co/novu/utils/Utils.java index 039642c9..30d53d28 100644 --- a/src/main/java/co/novu/utils/Utils.java +++ b/src/main/java/co/novu/utils/Utils.java @@ -983,13 +983,18 @@ public static String json(EventStreamMessage m, ObjectMapper mapper, boolean dat m.event().ifPresent(value -> node.set("event", new TextNode(value))); m.id().ifPresent(value -> node.set("id", new TextNode(value))); m.retryMs().ifPresent(value -> node.set("retry", new IntNode(value))); - // data is always present (but may be an empty string) - if (dataIsPlainText || m.data().trim().isEmpty()) { - node.set("data", new TextNode(m.data())); - } else { - JsonNode tree = mapper.readTree(m.data()); - node.set("data", tree); - } + m.data().ifPresent(data -> { + if (dataIsPlainText) { + node.set("data", new TextNode(data)); + } else { + try { + JsonNode tree = mapper.readTree(data); + node.set("data", tree); + } catch (JsonProcessingException e) { + node.set("data", new TextNode(data)); + } + } + }); return mapper.writeValueAsString(node); } diff --git a/src/main/java/co/novu/utils/reactive/EventStream.java b/src/main/java/co/novu/utils/reactive/EventStream.java index 507494c1..838c5d30 100644 --- a/src/main/java/co/novu/utils/reactive/EventStream.java +++ b/src/main/java/co/novu/utils/reactive/EventStream.java @@ -334,17 +334,13 @@ public StreamingParser createParser() { @Override public ItemT processItem(EventStreamMessage message, ObjectMapper objectMapper, TypeReference typeReference) { - // Skip empty data messages - if (message.data().isEmpty()) { - return null; - } return Utils.asType(message, objectMapper, typeReference); } @Override public boolean shouldStop(EventStreamMessage message) { // Check if this is a terminal message - return terminalMessage != null && terminalMessage.equals(message.data()); + return terminalMessage != null && message.data().map(terminalMessage::equals).orElse(false); } } From ad5807d2483c52fbab220d790e5d0e8579b345ba Mon Sep 17 00:00:00 2001 From: "speakeasy-github[bot]" <128539517+speakeasy-github[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 00:09:40 +0000 Subject: [PATCH 2/2] empty commit to trigger [run-tests] workflow