salesforce-data-customcode 6.1.0.dev4__py3-none-any.whl → 6.1.0.dev5__py3-none-any.whl

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 (38) hide show
  1. datacustomcode/client.py +56 -99
  2. datacustomcode/config.yaml +0 -6
  3. datacustomcode/deploy.py +2 -7
  4. datacustomcode/function/runtime.py +0 -16
  5. datacustomcode/io/writer/base.py +12 -0
  6. datacustomcode/io/writer/csv.py +8 -0
  7. datacustomcode/io/writer/print.py +7 -0
  8. datacustomcode/run.py +0 -7
  9. datacustomcode/templates/script/examples/streaming_deltas/entrypoint.py +37 -24
  10. datacustomcode/templates/script/jupyterlab.sh +18 -4
  11. {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/METADATA +3 -3
  12. {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/RECORD +15 -38
  13. datacustomcode/named_credential/__init__.py +0 -28
  14. datacustomcode/named_credential/base.py +0 -54
  15. datacustomcode/named_credential/default.py +0 -93
  16. datacustomcode/named_credential/direct/__init__.py +0 -19
  17. datacustomcode/named_credential/direct/auth.py +0 -63
  18. datacustomcode/named_credential/direct/credentials.py +0 -121
  19. datacustomcode/named_credential/direct/transport.py +0 -110
  20. datacustomcode/named_credential/direct/url_resolver.py +0 -112
  21. datacustomcode/named_credential/errors.py +0 -36
  22. datacustomcode/named_credential/spark_base.py +0 -93
  23. datacustomcode/named_credential/spark_default.py +0 -154
  24. datacustomcode/named_credential/types/__init__.py +0 -14
  25. datacustomcode/named_credential/types/http_method.py +0 -29
  26. datacustomcode/named_credential/types/http_request.py +0 -63
  27. datacustomcode/named_credential/types/http_request_builder.py +0 -55
  28. datacustomcode/named_credential/types/http_response.py +0 -43
  29. datacustomcode/named_credential/types/http_response_builder.py +0 -24
  30. datacustomcode/named_credential_config.py +0 -105
  31. datacustomcode/templates/function/example/chunking_with_external_callout/README.md +0 -119
  32. datacustomcode/templates/function/example/chunking_with_external_callout/config.json +0 -3
  33. datacustomcode/templates/function/example/chunking_with_external_callout/entrypoint.py +0 -161
  34. datacustomcode/templates/function/example/chunking_with_external_callout/external_callout_config.json +0 -11
  35. datacustomcode/templates/function/example/chunking_with_external_callout/tests/test.json +0 -16
  36. {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/WHEEL +0 -0
  37. {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/entry_points.txt +0 -0
  38. {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,14 +1,14 @@
1
1
  datacustomcode/__init__.py,sha256=5vvWRk5gb2mZIaVZ9BSPRL45uKSUwmSerxhLp6A4Q-4,2815
2
2
  datacustomcode/auth.py,sha256=fpSjhIBdv9trC8yq2vuljAix_Euu-4Ah7HDCGhYjOxI,8309
3
3
  datacustomcode/cli.py,sha256=K4LHL5xrb7-erXbjYz7pT4Kg4jG6Wf81c9wl_8tLabE,14162
4
- datacustomcode/client.py,sha256=0uw9qptultCYT-fZ3cXwaPvIFW5J9E79nD46tnu4NUE,28743
4
+ datacustomcode/client.py,sha256=1vX41y2KvKC-qvs48Vrp0ylpQovytECXS4LrsAdMCC4,26568
5
5
  datacustomcode/cmd.py,sha256=ZMs46aydJw2EaU26JgCtZmnqESQFHvvaJz10hnjZTBk,3537
6
6
  datacustomcode/common_config.py,sha256=SAUnxj3kqmOeWwPmFoYq4tuxokMgURVm4QwcGi-avL4,1928
7
7
  datacustomcode/config.py,sha256=lqed3jcWfoIweikSFZelaAoyBa0cXXScL8O6vaqdeRU,4372
8
- datacustomcode/config.yaml,sha256=LqpbkZhzN0nZOPEPnaz2qOCbchp8fxC4GHamT_b56D0,1082
8
+ datacustomcode/config.yaml,sha256=ldssmQYPghmYSSPaelm3F2mC99njavhrWsINRSzWymM,933
9
9
  datacustomcode/constants.py,sha256=NCGptcql30En5N7WAH96TYD_DTzHFYdh1sZZ5f327cs,1686
10
10
  datacustomcode/credentials.py,sha256=D-7Zd3Nh_wStdj8_wUy5cnC8M_mdbfBijhIAi-2EbXs,9467
11
- datacustomcode/deploy.py,sha256=kyd8QqvWrw_thHvGWEnjbeNVgAyjpoqR8TKqjcIriGA,23678
11
+ datacustomcode/deploy.py,sha256=HvKoXcUfBwBRsTWCDp22Qg3fJV1qRZ-TFNQ-Od8AATE,23441
12
12
  datacustomcode/einstein_platform_client.py,sha256=ON2B_m--vdbCVVMVcLc81T-BRZ5-UuxVCer8E6OEQPA,4083
13
13
  datacustomcode/einstein_platform_config.py,sha256=6lb_FRbEzdt5a8-2cR15f13ZKw674uvRJ4Xq0o_pQXE,1490
14
14
  datacustomcode/einstein_predictions/__init__.py,sha256=_RIDTqcEHDRu6AsCsj9lRBykNkHI8Ch8JBILL1ioPtA,1237
@@ -27,7 +27,7 @@ datacustomcode/function/__init__.py,sha256=oag8FevDxbx1vR0tFhtxPd5SvmUEYDj8esRo4
27
27
  datacustomcode/function/base.py,sha256=H_i80GcsFScvHJJ6bYLry5phTpsEU1KubpR8D3qnsjo,691
28
28
  datacustomcode/function/feature_types/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
29
29
  datacustomcode/function/feature_types/chunking.py,sha256=_tCCHj7slD59-aLLEZUFRPOX37q_MEKkL4thi9CNwMw,7180
30
- datacustomcode/function/runtime.py,sha256=Q6h-vcW1TNhOh3q1rlmQ24zs-OloNkJexdtbFyIxt4o,4437
30
+ datacustomcode/function/runtime.py,sha256=jUduf-pve-0JAv0Lg0HPyLCZ9_Hgcxe25dI7t-DgX9o,3696
31
31
  datacustomcode/function_utils.py,sha256=y6vaoSSaJ9CeHhjLCNyqzJT4vx6yCePWRxNLz38ddjQ,12920
32
32
  datacustomcode/io/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
33
33
  datacustomcode/io/base.py,sha256=gbwZWWVUbCbGR4jIg_4h4qOz8tOMjE4RDTleD23WFKo,973
@@ -37,9 +37,9 @@ datacustomcode/io/reader/query_api.py,sha256=eVrohrcnTnhSMsGfPRHu5XltjFtGG0hyHt1
37
37
  datacustomcode/io/reader/sf_cli.py,sha256=x5QacVqRZaZSyph1_wwxo67s8r29wsOcUsOaiF9cDWE,6324
38
38
  datacustomcode/io/reader/utils.py,sha256=HlHhPZoHfmWA3mF8kTnd3m4Nd2exaz4NsOJJfQY7Pew,1656
39
39
  datacustomcode/io/writer/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
40
- datacustomcode/io/writer/base.py,sha256=LtyOtkcEsX3oQZ-2zWFeNutVae1T3ialbGbvwl-7spU,3246
41
- datacustomcode/io/writer/csv.py,sha256=asty5teBpNQ1fMGHZ7wA3suLhq0sk0lVQPN5x7TOSRk,1555
42
- datacustomcode/io/writer/print.py,sha256=0g2sP_1Wb95UIyEELWJt3dqM18Iv_CWhDW3mDxcIhns,5105
40
+ datacustomcode/io/writer/base.py,sha256=W0QmsmszCjOIYPlEqbAjld0O855CAFvZjm_FT7szyb4,3806
41
+ datacustomcode/io/writer/csv.py,sha256=LYQpTZlIQdn0RRx_dRah22V2Vgm-InKP4KHRKfWGiRY,1963
42
+ datacustomcode/io/writer/print.py,sha256=Tpy5-0NmJ_renC6uah5TdHQZFzDbx23ltm1tIPK0978,5388
43
43
  datacustomcode/llm_gateway/__init__.py,sha256=rcoGpSkv36tZuAOcTxKkhNpM0qV03qgmer_ej07Vmfc,1088
44
44
  datacustomcode/llm_gateway/base.py,sha256=CTUhZiZ0JFlmWj6kQpTR4_-mUvqkBKl_Fkdvv9VwxY8,1262
45
45
  datacustomcode/llm_gateway/default.py,sha256=QiwrDaUvrh00I-fYYhmogTtqC5r0fmm-JrXxNQLvTc0,1854
@@ -53,26 +53,8 @@ datacustomcode/llm_gateway/types/generate_text_response.py,sha256=NSvj6nvzR4cZ0c
53
53
  datacustomcode/llm_gateway/types/generate_text_response_builder.py,sha256=6MV6JZuTyHUId3Slw9k7m0KBgjj-5S9HI4qtd94Jl2A,1272
54
54
  datacustomcode/llm_gateway_config.py,sha256=ECm9CFqOFOaLHwenvVFAjiRSzG9Eg9fY4pb8nHbQ34c,3312
55
55
  datacustomcode/mixin.py,sha256=ZtROqO1W1_D7MV8lw4cw6zzcchJLoZS0aAiXrolYR4k,4914
56
- datacustomcode/named_credential/__init__.py,sha256=XD_UI8ggOkFvkqCOZI_3dP1AkviqPIZFOt3RI1_RDe4,1163
57
- datacustomcode/named_credential/base.py,sha256=-LMskZkKNoaFg-Zc80M_4IPLF7ru5pfnbkfLI7YXrFc,1816
58
- datacustomcode/named_credential/default.py,sha256=z03B0daZvTPiTmJWGAtDCICB1srelESg7QmPH2iRK5o,3339
59
- datacustomcode/named_credential/direct/__init__.py,sha256=zqErMI1GqEhseLnYkrWtq3WipRi_dP153c8wwLvgI-o,799
60
- datacustomcode/named_credential/direct/auth.py,sha256=U09jO0Pn3OEOEudmvcBmtkwoXqE0Ae_Mv6TAMqb3eG4,2201
61
- datacustomcode/named_credential/direct/credentials.py,sha256=fibIZTyBT1IbAGFjXwAXqYcQt9o_sB8zFmuixGmibE4,4534
62
- datacustomcode/named_credential/direct/transport.py,sha256=UL5eJJsyoAjr8ovJDQKQY3O20DivvbWFPGRyM8Y2or4,4078
63
- datacustomcode/named_credential/direct/url_resolver.py,sha256=KItv12Az0qoxnVacCTcM9t9AY7qB9_tqPWMgiP-7Y6s,3823
64
- datacustomcode/named_credential/errors.py,sha256=zyMEgljTf85digXrLrlR9HBh5Un4WtG0WsZx0K4EWt0,1212
65
- datacustomcode/named_credential/spark_base.py,sha256=w34B-Pg6m_hcUqUbjmB2b6zUme_MSgg6VeghbMMYYN4,3288
66
- datacustomcode/named_credential/spark_default.py,sha256=DY_STX9-1le8cS5M_vGqB3VUtQ2XCZZYDAmKId7YekA,5219
67
- datacustomcode/named_credential/types/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
68
- datacustomcode/named_credential/types/http_method.py,sha256=NFf8emmW_Y73q8q2pseWHqOQ-1SoFwKp2vCMr1OdmEU,952
69
- datacustomcode/named_credential/types/http_request.py,sha256=LXW4EcvUfyOJHf8-VtFSRWy6JsTJJsd0N4-X6WxxFnA,2170
70
- datacustomcode/named_credential/types/http_request_builder.py,sha256=qdToSlX2xw3FzuLF6Kas3VzCp1ubdXZb4_WkjQ5fBY0,1862
71
- datacustomcode/named_credential/types/http_response.py,sha256=ZqX52RMjSdn8OpHSDkKJo9730QRx8o4_ZT-1noSMRe8,1480
72
- datacustomcode/named_credential/types/http_response_builder.py,sha256=MoUjpT-P5W2uT1-h1rIfKpBQHpMj_ZA_nUmn-FyBdbQ,896
73
- datacustomcode/named_credential_config.py,sha256=M07-oWzYj0KTrfA0fqvk3BQvaaDaw7C6nxbR0s3lOUk,3645
74
56
  datacustomcode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- datacustomcode/run.py,sha256=G0b5PCU0nucOFGX578LlYjmCpmgAASADnf2rh8NmccI,8485
57
+ datacustomcode/run.py,sha256=Ky58Di6Nh7gk6Ic-5Jxt3Y4xB3vRNmzlUcoSlK-OLvo,8169
76
58
  datacustomcode/scan.py,sha256=9rq1Wae_tYACJykaOmBOv1covYvOSdky8w13exnmyJ0,19170
77
59
  datacustomcode/spark/__init__.py,sha256=12drVVlRiczCxOQw-EzuGtLsikCM8baBXvDEgwvelCI,860
78
60
  datacustomcode/spark/base.py,sha256=tlGqM4LxuLoDa7OxJF5nVeb7phO5uvD1DHBQeH7NMMs,1036
@@ -86,11 +68,6 @@ datacustomcode/templates/function/build_native_dependencies.sh,sha256=dk9vhzlObd
86
68
  datacustomcode/templates/function/chunking/payload/config.json,sha256=RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o,2
87
69
  datacustomcode/templates/function/chunking/payload/entrypoint.py,sha256=tzpQJjODulwzLilOoKdOo8GjpdIlCDByjnawpHIQYQA,4517
88
70
  datacustomcode/templates/function/chunking/requirements.txt,sha256=Ih0KsVdiTdo7KuIsqFB_AJMRT2r0ao_xDEb3hiDmf48,46
89
- datacustomcode/templates/function/example/chunking_with_external_callout/README.md,sha256=RIgoUysFniAE4lC5LiZl5u55Rro1w5gmM2mMnsQF_HI,4716
90
- datacustomcode/templates/function/example/chunking_with_external_callout/config.json,sha256=EvjuOVssRg2SjcUb5F50RRMGDqag_f69bv8AOflaK1g,38
91
- datacustomcode/templates/function/example/chunking_with_external_callout/entrypoint.py,sha256=QqJLeJHgtW4RkDwTaUIsb2ng_ODwwClXpn5F7XyXBes,5296
92
- datacustomcode/templates/function/example/chunking_with_external_callout/external_callout_config.json,sha256=PUCmw_humbVoCyswFneuGYx0INbqSTPOumDqtGOztiM,320
93
- datacustomcode/templates/function/example/chunking_with_external_callout/tests/test.json,sha256=ZqUthCT9F9HoyT493tXg4nFDSbEAeaFHY1iHo-9Qx7g,2703
94
71
  datacustomcode/templates/function/example/chunking_with_llm/config.json,sha256=EvjuOVssRg2SjcUb5F50RRMGDqag_f69bv8AOflaK1g,38
95
72
  datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py,sha256=6AMVf_busCCDALktG8vkCtjnzJheMgM-OOLML5iLKOg,3437
96
73
  datacustomcode/templates/function/example/chunking_with_llm/files/chunking_prompt.txt,sha256=w_gSYNXwZmbMTMjZ_YYwm1IpMsVpI3hyC3ew60zqs_0,446
@@ -111,16 +88,16 @@ datacustomcode/templates/script/account.ipynb,sha256=LIbxgiVxflNASdspF2lfpMKkKAT
111
88
  datacustomcode/templates/script/build_native_dependencies.sh,sha256=ICRrp4f1ATBwPaUiuVGjY-MwiubFswNJLf8gMGU6YNg,197
112
89
  datacustomcode/templates/script/examples/employee_hierarchy/employee_data.csv,sha256=C7ggLBfoyi3M2BdMLNyOeKqF-5OO-Da76lkwgWg2cVQ,302
113
90
  datacustomcode/templates/script/examples/employee_hierarchy/entrypoint.py,sha256=Mfm3iQtEHTQRW6cmZTwRKdTh3IeGWR-teXrd6x-YLSY,2223
114
- datacustomcode/templates/script/examples/streaming_deltas/entrypoint.py,sha256=1PpYyZck2j9IRTnoI-kfHbMf21vN8gA49_-qJr3rDjk,1984
115
- datacustomcode/templates/script/jupyterlab.sh,sha256=IHR3YQ8d_busuyvesByhJgzCKULIFPI-Hqogs0NPhCs,2432
91
+ datacustomcode/templates/script/examples/streaming_deltas/entrypoint.py,sha256=UQr1EhJURFFGI5626efvv-MxGHltzcpJcEJVmz5ZQdo,2333
92
+ datacustomcode/templates/script/jupyterlab.sh,sha256=0O_rPZ8w2DM1hxPo9Wig9j-ymhS2dRzVO2PlFClWdlA,2786
116
93
  datacustomcode/templates/script/payload/config.json,sha256=0d2mEMt4NHIeOUTsgiPMuRKdOLIQxmh-Wq-IfEqU-gc,28
117
94
  datacustomcode/templates/script/payload/entrypoint.py,sha256=4Uph0ILa5ukk_6C90paK3uzQn0zZvNLr9ho3o_ZwErQ,2474
118
95
  datacustomcode/templates/script/requirements-dev.txt,sha256=OWwuy1awesqOZOS3Zizmdd6BDnSePpGFN5bq5IrALvc,176
119
96
  datacustomcode/templates/script/requirements.txt,sha256=qJbqzs5z0Hrx590U3T7dHq_m8UQEx2TdhgrJSz-QHIQ,40
120
97
  datacustomcode/token_provider.py,sha256=qA_e4vqSXnxn0MccFFPULWO8ZeUOEAu5QpBnoYCg-fc,6839
121
98
  datacustomcode/version.py,sha256=9LlbVrzwBvut1L308QbwNBgxdQk5CrghH39JARVSxms,989
122
- salesforce_data_customcode-6.1.0.dev4.dist-info/METADATA,sha256=Z3pzLUNQb2iRxImuljMvwdpumcV5x8wJEVtySG545pc,27207
123
- salesforce_data_customcode-6.1.0.dev4.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
124
- salesforce_data_customcode-6.1.0.dev4.dist-info/entry_points.txt,sha256=WpQ94UB7UuRCYGOLtJV3vAgm1tl7iVf43VYRWIuNu5Y,74
125
- salesforce_data_customcode-6.1.0.dev4.dist-info/licenses/LICENSE.txt,sha256=iOi8EmQpfkFhMENi7VYtkl2EqS14pEOccoXHiW2dyPU,11443
126
- salesforce_data_customcode-6.1.0.dev4.dist-info/RECORD,,
99
+ salesforce_data_customcode-6.1.0.dev5.dist-info/METADATA,sha256=VCspB8hb-Qia1FvP5047hBU8M8uEO-VcuNP-6Wf_7nc,27417
100
+ salesforce_data_customcode-6.1.0.dev5.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
101
+ salesforce_data_customcode-6.1.0.dev5.dist-info/entry_points.txt,sha256=WpQ94UB7UuRCYGOLtJV3vAgm1tl7iVf43VYRWIuNu5Y,74
102
+ salesforce_data_customcode-6.1.0.dev5.dist-info/licenses/LICENSE.txt,sha256=iOi8EmQpfkFhMENi7VYtkl2EqS14pEOccoXHiW2dyPU,11443
103
+ salesforce_data_customcode-6.1.0.dev5.dist-info/RECORD,,
@@ -1,28 +0,0 @@
1
- # Copyright (c) 2025, Salesforce, Inc.
2
- # SPDX-License-Identifier: Apache-2
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- from datacustomcode.named_credential.base import NamedCredential
17
- from datacustomcode.named_credential.default import DefaultNamedCredential
18
- from datacustomcode.named_credential.errors import NamedCredentialCallError
19
- from datacustomcode.named_credential.spark_base import SparkNamedCredential
20
- from datacustomcode.named_credential.spark_default import DefaultSparkNamedCredential
21
-
22
- __all__ = [
23
- "DefaultNamedCredential",
24
- "DefaultSparkNamedCredential",
25
- "NamedCredential",
26
- "NamedCredentialCallError",
27
- "SparkNamedCredential",
28
- ]
@@ -1,54 +0,0 @@
1
- # Copyright (c) 2025, Salesforce, Inc.
2
- # SPDX-License-Identifier: Apache-2
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
- from __future__ import annotations
16
-
17
- from abc import ABC, abstractmethod
18
- from typing import TYPE_CHECKING, Optional
19
-
20
- from datacustomcode.mixin import UserExtendableNamedConfigMixin
21
-
22
- if TYPE_CHECKING:
23
- from datacustomcode.named_credential.types.http_request import HTTPRequest
24
- from datacustomcode.named_credential.types.http_response import HTTPResponse
25
-
26
-
27
- class NamedCredential(ABC, UserExtendableNamedConfigMixin):
28
- CONFIG_NAME: str
29
-
30
- def __init__(self, **kwargs):
31
- pass
32
-
33
- @abstractmethod
34
- def request(
35
- self,
36
- request: HTTPRequest,
37
- body: Optional[str] = None,
38
- ) -> HTTPResponse:
39
- """Make an external callout through a Named Credential.
40
-
41
- The endpoint and its authentication are resolved server-side from the
42
- Named Credential referenced by ``request.url``; the function never sees
43
- the external credential.
44
-
45
- Args:
46
- request: The callout request
47
- body: Optional request body. Set the
48
- ``Content-Type`` header to match the format; the SDK
49
- does not assume or inject one.
50
-
51
- Returns:
52
- The external service's response.
53
- """
54
- ...
@@ -1,93 +0,0 @@
1
- # Copyright (c) 2025, Salesforce, Inc.
2
- # SPDX-License-Identifier: Apache-2
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- from typing import (
17
- Any,
18
- Dict,
19
- Optional,
20
- )
21
-
22
- from datacustomcode.named_credential.base import NamedCredential
23
- from datacustomcode.named_credential.types.http_request import HTTPRequest
24
- from datacustomcode.named_credential.types.http_response import HTTPResponse
25
- from datacustomcode.named_credential.types.http_response_builder import (
26
- HTTPResponseBuilder,
27
- )
28
-
29
-
30
- class DefaultNamedCredential(NamedCredential):
31
- """
32
- Executes the callout directly via :class:`DirectCalloutTransport`, resolving
33
- the URL from the Named Credential Connect API (falling back to
34
- ``external_callout_config.json``) and injecting auth from the same file.
35
- """
36
-
37
- CONFIG_NAME = "DefaultNamedCredential"
38
-
39
- def __init__(
40
- self,
41
- credentials_profile: str = "default",
42
- sf_cli_org: Optional[str] = None,
43
- credential_file: Optional[str] = None,
44
- **kwargs: Any,
45
- ) -> None:
46
- super().__init__(**kwargs)
47
- self._credentials_profile = credentials_profile
48
- self._sf_cli_org = sf_cli_org
49
- self._credential_file = credential_file
50
- self._transport: Optional[Any] = None
51
-
52
- def request(
53
- self,
54
- request: HTTPRequest,
55
- body: Optional[str] = None,
56
- ) -> HTTPResponse:
57
- # Body and response are treated as opaque strings; the SDK makes no
58
- # assumption about their format (JSON, XML, text, ...).
59
- callout_request = {
60
- "path": request.url,
61
- "method": request.method,
62
- "headers": dict(request.headers),
63
- "body": body if body is not None else "",
64
- }
65
- callout_response = self._callout(callout_request)
66
- return HTTPResponseBuilder.build(
67
- {
68
- "status_code": callout_response.get("status_code"),
69
- "headers": callout_response.get("headers", {}),
70
- "body": callout_response.get("body") or "",
71
- }
72
- )
73
-
74
- def _callout(self, callout_request: Dict[str, Any]) -> Dict[str, Any]:
75
- """Execute the callout via the transport.
76
-
77
- Returns a dict with ``status_code``, ``headers``, and ``body``.
78
- """
79
- result: Dict[str, Any] = self._get_transport().callout(callout_request)
80
- return result
81
-
82
- def _get_transport(self) -> Any:
83
- if self._transport is None:
84
- from datacustomcode.named_credential.direct.transport import (
85
- DirectCalloutTransport,
86
- )
87
-
88
- self._transport = DirectCalloutTransport(
89
- credentials_profile=self._credentials_profile,
90
- sf_cli_org=self._sf_cli_org,
91
- credential_file=self._credential_file,
92
- )
93
- return self._transport
@@ -1,19 +0,0 @@
1
- # Copyright (c) 2025, Salesforce, Inc.
2
- # SPDX-License-Identifier: Apache-2
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
- """Named Credential callout path.
16
-
17
- This resolves the endpoint via the NamedCredential Connect API
18
- and injects auth from a developer-provided ``external_callout_config.json``
19
- """
@@ -1,63 +0,0 @@
1
- # Copyright (c) 2025, Salesforce, Inc.
2
- # SPDX-License-Identifier: Apache-2
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
- """
16
- Inject external credential auth into an outgoing request.
17
- """
18
-
19
- from __future__ import annotations
20
-
21
- import base64
22
- from typing import (
23
- TYPE_CHECKING,
24
- Any,
25
- Dict,
26
- )
27
-
28
- from requests.auth import AuthBase
29
-
30
- from datacustomcode.named_credential.direct.credentials import AuthType
31
-
32
- if TYPE_CHECKING:
33
- from requests.models import PreparedRequest
34
-
35
-
36
- class DynamicAuthHandler(AuthBase):
37
- def __init__(self, cred_config: Dict[str, Any]) -> None:
38
- self.config = cred_config
39
- self.auth_type = cred_config.get("auth_type")
40
-
41
- def __call__(self, request: PreparedRequest) -> PreparedRequest:
42
- if self.auth_type == AuthType.BASIC.value:
43
- user = self.config.get("username", "")
44
- pwd = self.config.get("password", "")
45
- token = base64.b64encode(f"{user}:{pwd}".encode()).decode()
46
- request.headers["Authorization"] = f"Basic {token}"
47
-
48
- elif self.auth_type == AuthType.CUSTOM.value:
49
- for name, value in self.config.get("custom_headers", {}).items():
50
- request.headers[name] = value
51
-
52
- elif self.auth_type in (AuthType.OAUTH.value, AuthType.JWT.value):
53
- bearer = self.config.get("access_token") or self.config.get("token")
54
- if not bearer:
55
- raise ValueError(
56
- f"'{self.auth_type}' auth requires an 'access_token' or 'token'."
57
- )
58
- request.headers["Authorization"] = f"Bearer {bearer}"
59
-
60
- else:
61
- raise ValueError(f"Unsupported auth_type '{self.auth_type}'.")
62
-
63
- return request
@@ -1,121 +0,0 @@
1
- # Copyright (c) 2025, Salesforce, Inc.
2
- # SPDX-License-Identifier: Apache-2
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
- """Load developer credentials for direct callouts from ``external_callout_config.json``.
16
-
17
- The file lives in the parent of the payload folder so it is never packaged in
18
- the deployment zip. Its ``credentials`` section is keyed by callout reference
19
- (``callout:<NamedCredential>``); each value carries a mandatory ``auth_type``
20
- and an optional ``target_url``.
21
- """
22
-
23
- from __future__ import annotations
24
-
25
- from enum import Enum
26
- import json
27
- import os
28
- from pathlib import Path
29
- from typing import (
30
- Any,
31
- Dict,
32
- Optional,
33
- )
34
-
35
- # Default file name; discovered in the parent of the payload folder.
36
- EXTERNAL_CALLOUT_CREDENTIAL = "external_callout_config.json"
37
- # Absolute-path override, primarily for tests and non-standard layouts.
38
- CREDENTIAL_FILE_ENV_VAR = "DATACUSTOMCODE_EXTERNAL_CALLOUT_CONFIG"
39
-
40
-
41
- class AuthType(str, Enum):
42
- """External Credential auth types supported by External Services."""
43
-
44
- BASIC = "Basic"
45
- CUSTOM = "Custom"
46
- JWT = "Jwt"
47
- OAUTH = "OAuth"
48
-
49
-
50
- class CredentialError(RuntimeError):
51
- """Raised when credentials cannot be found or are invalid."""
52
-
53
-
54
- def _discover_credential_file() -> Optional[Path]:
55
- """Find the config file via env override, then by walking up from cwd."""
56
- override = os.environ.get(CREDENTIAL_FILE_ENV_VAR)
57
- if override:
58
- return Path(override)
59
-
60
- for directory in (Path.cwd(), *Path.cwd().parents):
61
- candidate = directory / EXTERNAL_CALLOUT_CREDENTIAL
62
- if candidate.is_file():
63
- return candidate
64
- return None
65
-
66
-
67
- class CredentialStore:
68
- """Reads ``external_callout_config.json`` and returns per-callout config."""
69
-
70
- def __init__(self, credential_file: Optional[str] = None) -> None:
71
- self._explicit_path = Path(credential_file) if credential_file else None
72
- self._credentials: Optional[Dict[str, Dict[str, Any]]] = None
73
-
74
- def _load(self) -> Dict[str, Dict[str, Any]]:
75
- if self._credentials is not None:
76
- return self._credentials
77
-
78
- path = self._explicit_path or _discover_credential_file()
79
- if path is None or not path.is_file():
80
- raise CredentialError(
81
- f"Could not find '{EXTERNAL_CALLOUT_CREDENTIAL}'. Place it in the "
82
- f"parent of your payload folder, or set "
83
- f"${CREDENTIAL_FILE_ENV_VAR} to its path."
84
- )
85
- try:
86
- with open(path, "r") as f:
87
- data = json.load(f)
88
- except (OSError, json.JSONDecodeError) as exc:
89
- raise CredentialError(f"Failed to read '{path}': {exc}") from exc
90
-
91
- # Per-callout entries live under the ``credentials`` section, leaving
92
- # room for other config sections alongside them in the future.
93
- credentials = data.get("credentials") if isinstance(data, dict) else None
94
- if not isinstance(credentials, dict):
95
- raise CredentialError(
96
- f"'{path}' must be a JSON object with a 'credentials' section "
97
- f"keyed by callout reference."
98
- )
99
- self._credentials = credentials
100
- return credentials
101
-
102
- def get(self, callout_key: str) -> Dict[str, Any]:
103
- """Return the config for a callout key (e.g. ``callout:AWS_S3_Service``).
104
-
105
- Raises:
106
- CredentialError: if the key is missing or has no ``auth_type``.
107
- """
108
- credentials = self._load()
109
- config = credentials.get(callout_key)
110
- if config is None:
111
- raise CredentialError(
112
- f"No credential configuration found for '{callout_key}'. "
113
- f"Add it to the 'credentials' section of "
114
- f"'{EXTERNAL_CALLOUT_CREDENTIAL}'."
115
- )
116
- if not isinstance(config, dict) or not config.get("auth_type"):
117
- raise CredentialError(
118
- f"Credential for '{callout_key}' is missing the mandatory "
119
- f"'auth_type' field."
120
- )
121
- return config
@@ -1,110 +0,0 @@
1
- # Copyright (c) 2025, Salesforce, Inc.
2
- # SPDX-License-Identifier: Apache-2
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
- """Send a Named Credential callout over HTTP.
16
-
17
- Resolves the ``callout:<NamedCredential>/<path>`` reference to a real endpoint
18
- (via the Named Credential Connect API, falling back to ``target_url`` in
19
- ``external_callout_config.json``), attaches the credential's auth, and returns the raw
20
- ``{status_code, headers, body}`` response.
21
- """
22
-
23
- from __future__ import annotations
24
-
25
- from typing import (
26
- Any,
27
- Dict,
28
- Optional,
29
- )
30
-
31
- import requests
32
-
33
- from datacustomcode.named_credential.direct.auth import DynamicAuthHandler
34
- from datacustomcode.named_credential.direct.credentials import CredentialStore
35
- from datacustomcode.named_credential.direct.url_resolver import resolve_base_url
36
- from datacustomcode.named_credential.errors import NamedCredentialCallError
37
- from datacustomcode.token_provider import (
38
- CredentialsTokenProvider,
39
- SFCLITokenProvider,
40
- TokenProvider,
41
- )
42
-
43
-
44
- class DirectCalloutTransport:
45
- def __init__(
46
- self,
47
- credentials_profile: str = "default",
48
- sf_cli_org: Optional[str] = None,
49
- credential_file: Optional[str] = None,
50
- ) -> None:
51
- self._store = CredentialStore(credential_file)
52
- self._token_provider = self._build_token_provider(
53
- credentials_profile, sf_cli_org
54
- )
55
- # Resolved base URL per callout key. Stable for the transport's life, so
56
- # cache it to avoid a token fetch + Connect API call on every row
57
- self._base_url_cache: Dict[str, str] = {}
58
-
59
- @staticmethod
60
- def _build_token_provider(
61
- credentials_profile: str, sf_cli_org: Optional[str]
62
- ) -> TokenProvider:
63
- if sf_cli_org:
64
- return SFCLITokenProvider(sf_cli_org)
65
- return CredentialsTokenProvider(credentials_profile)
66
-
67
- def callout(self, callout_request: Dict[str, Any]) -> Dict[str, Any]:
68
- raw_url = callout_request["path"]
69
- if not raw_url.startswith("callout:"):
70
- raise NamedCredentialCallError(
71
- f"Callout URL must start with 'callout:', got '{raw_url}'."
72
- )
73
-
74
- # Split the named credential reference at the first '/' or '?'; the remainder
75
- # path or query string is appended to the resolved base URL verbatim.
76
- sep_idx = min(
77
- (i for i in (raw_url.find("/"), raw_url.find("?")) if i != -1),
78
- default=len(raw_url),
79
- )
80
- callout_key = raw_url[:sep_idx]
81
- path_suffix = raw_url[sep_idx:]
82
-
83
- if callout_key == "callout:":
84
- raise NamedCredentialCallError(
85
- f"Named Credential name is empty in URL '{raw_url}'."
86
- )
87
-
88
- cred_config = self._store.get(callout_key)
89
- base_url = self._base_url_cache.get(callout_key)
90
- if base_url is None:
91
- base_url = resolve_base_url(callout_key, cred_config, self._token_provider)
92
- self._base_url_cache[callout_key] = base_url
93
-
94
- body = callout_request.get("body") or None
95
- # Headers are passed; the SDK assumes no Content-Type.
96
- headers = dict(callout_request.get("headers", {}))
97
-
98
- response = requests.request(
99
- method=callout_request["method"],
100
- url=base_url + path_suffix,
101
- headers=headers,
102
- data=body,
103
- auth=DynamicAuthHandler(cred_config),
104
- timeout=30,
105
- )
106
- return {
107
- "status_code": response.status_code,
108
- "headers": dict(response.headers),
109
- "body": response.text,
110
- }