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.
- datacustomcode/client.py +56 -99
- datacustomcode/config.yaml +0 -6
- datacustomcode/deploy.py +2 -7
- datacustomcode/function/runtime.py +0 -16
- datacustomcode/io/writer/base.py +12 -0
- datacustomcode/io/writer/csv.py +8 -0
- datacustomcode/io/writer/print.py +7 -0
- datacustomcode/run.py +0 -7
- datacustomcode/templates/script/examples/streaming_deltas/entrypoint.py +37 -24
- datacustomcode/templates/script/jupyterlab.sh +18 -4
- {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/METADATA +3 -3
- {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/RECORD +15 -38
- datacustomcode/named_credential/__init__.py +0 -28
- datacustomcode/named_credential/base.py +0 -54
- datacustomcode/named_credential/default.py +0 -93
- datacustomcode/named_credential/direct/__init__.py +0 -19
- datacustomcode/named_credential/direct/auth.py +0 -63
- datacustomcode/named_credential/direct/credentials.py +0 -121
- datacustomcode/named_credential/direct/transport.py +0 -110
- datacustomcode/named_credential/direct/url_resolver.py +0 -112
- datacustomcode/named_credential/errors.py +0 -36
- datacustomcode/named_credential/spark_base.py +0 -93
- datacustomcode/named_credential/spark_default.py +0 -154
- datacustomcode/named_credential/types/__init__.py +0 -14
- datacustomcode/named_credential/types/http_method.py +0 -29
- datacustomcode/named_credential/types/http_request.py +0 -63
- datacustomcode/named_credential/types/http_request_builder.py +0 -55
- datacustomcode/named_credential/types/http_response.py +0 -43
- datacustomcode/named_credential/types/http_response_builder.py +0 -24
- datacustomcode/named_credential_config.py +0 -105
- datacustomcode/templates/function/example/chunking_with_external_callout/README.md +0 -119
- datacustomcode/templates/function/example/chunking_with_external_callout/config.json +0 -3
- datacustomcode/templates/function/example/chunking_with_external_callout/entrypoint.py +0 -161
- datacustomcode/templates/function/example/chunking_with_external_callout/external_callout_config.json +0 -11
- datacustomcode/templates/function/example/chunking_with_external_callout/tests/test.json +0 -16
- {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/WHEEL +0 -0
- {salesforce_data_customcode-6.1.0.dev4.dist-info → salesforce_data_customcode-6.1.0.dev5.dist-info}/entry_points.txt +0 -0
- {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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
41
|
-
datacustomcode/io/writer/csv.py,sha256=
|
|
42
|
-
datacustomcode/io/writer/print.py,sha256=
|
|
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=
|
|
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=
|
|
115
|
-
datacustomcode/templates/script/jupyterlab.sh,sha256=
|
|
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.
|
|
123
|
-
salesforce_data_customcode-6.1.0.
|
|
124
|
-
salesforce_data_customcode-6.1.0.
|
|
125
|
-
salesforce_data_customcode-6.1.0.
|
|
126
|
-
salesforce_data_customcode-6.1.0.
|
|
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
|
-
}
|