@rashidee/co2 1.2.5

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 (190) hide show
  1. package/dist/index.js +25449 -0
  2. package/drizzle/0000_remarkable_charles_xavier.sql +210 -0
  3. package/drizzle/0001_wise_wolf_cub.sql +13 -0
  4. package/drizzle/0002_secret_spyke.sql +16 -0
  5. package/drizzle/0003_workspace_config_singleton.sql +16 -0
  6. package/drizzle/0004_terminal_claim_v120.sql +11 -0
  7. package/drizzle/0005_brainstorm_v124.sql +10 -0
  8. package/drizzle/0006_project_v140.sql +6 -0
  9. package/drizzle/0007_prd_wizard_v124.sql +14 -0
  10. package/drizzle/0008_workflow_artifact_v126.sql +24 -0
  11. package/drizzle/0009_project_import_v150.sql +7 -0
  12. package/drizzle/0010_quality_v151.sql +3 -0
  13. package/drizzle/meta/0000_snapshot.json +1335 -0
  14. package/drizzle/meta/0001_snapshot.json +1416 -0
  15. package/drizzle/meta/0002_snapshot.json +1510 -0
  16. package/drizzle/meta/_journal.json +83 -0
  17. package/package.json +41 -0
  18. package/plugin/.claude-plugin/marketplace.json +36 -0
  19. package/plugin/.claude-plugin/plugin.json +22 -0
  20. package/plugin/README.md +625 -0
  21. package/plugin/SKILLS.md +350 -0
  22. package/plugin/co2.svg +5 -0
  23. package/plugin/commands/brainstorm-loop.md +129 -0
  24. package/plugin/skills/conductor-defect/SKILL.md +898 -0
  25. package/plugin/skills/conductor-feature-develop/SKILL.md +1383 -0
  26. package/plugin/skills/conductor-feature-develop/references/implementation-domain-template.md +131 -0
  27. package/plugin/skills/conductor-feature-develop/references/implementation-master-template.md +89 -0
  28. package/plugin/skills/conductor-feature-develop/references/playwright-setup.md +224 -0
  29. package/plugin/skills/conductor-feature-prepare/SKILL.md +604 -0
  30. package/plugin/skills/depgen-k8s/SKILL.md +468 -0
  31. package/plugin/skills/depgen-k8s/references/dockerfile-laravel.md +197 -0
  32. package/plugin/skills/depgen-k8s/references/dockerfile-nodejs.md +163 -0
  33. package/plugin/skills/depgen-k8s/references/dockerfile-spring-boot.md +174 -0
  34. package/plugin/skills/depgen-k8s/references/k8s-patterns.md +869 -0
  35. package/plugin/skills/mockgen-shadcn/SKILL.md +1067 -0
  36. package/plugin/skills/mockgen-shadcn/references/admin-layout-template.md +1467 -0
  37. package/plugin/skills/mockgen-shadcn/references/mockup-hub-template.md +498 -0
  38. package/plugin/skills/mockgen-shadcn/references/mockup-index-template.md +216 -0
  39. package/plugin/skills/mockgen-tailwind/SKILL.md +904 -0
  40. package/plugin/skills/mockgen-tailwind/references/admin-layout-template.md +720 -0
  41. package/plugin/skills/mockgen-tailwind/references/mockup-hub-template.md +498 -0
  42. package/plugin/skills/mockgen-tailwind/references/mockup-index-template.md +190 -0
  43. package/plugin/skills/modelgen-nosql/SKILL.md +617 -0
  44. package/plugin/skills/modelgen-nosql/references/model-extraction-methodology.md +497 -0
  45. package/plugin/skills/modelgen-nosql/references/nosql-design-guide.md +258 -0
  46. package/plugin/skills/modelgen-relational/SKILL.md +707 -0
  47. package/plugin/skills/modelgen-relational/references/model-extraction-methodology.md +499 -0
  48. package/plugin/skills/specgen-flutter-riverpod/SKILL.md +898 -0
  49. package/plugin/skills/specgen-flutter-riverpod/references/component-patterns.md +971 -0
  50. package/plugin/skills/specgen-flutter-riverpod/references/notification-patterns.md +457 -0
  51. package/plugin/skills/specgen-flutter-riverpod/references/routing-patterns.md +362 -0
  52. package/plugin/skills/specgen-flutter-riverpod/references/security-patterns.md +709 -0
  53. package/plugin/skills/specgen-flutter-riverpod/references/spec-template.md +1566 -0
  54. package/plugin/skills/specgen-flutter-riverpod/references/state-patterns.md +518 -0
  55. package/plugin/skills/specgen-flutter-riverpod/references/storage-patterns.md +370 -0
  56. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/SKILL.md +984 -0
  57. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/batch-patterns.md +359 -0
  58. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/messaging-patterns.md +468 -0
  59. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/modulith-patterns.md +461 -0
  60. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/reporting-patterns.md +803 -0
  61. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/security-patterns.md +501 -0
  62. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/spec-template.md +1268 -0
  63. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/web-patterns.md +301 -0
  64. package/plugin/skills/specgen-node-cli-web/SKILL.md +561 -0
  65. package/plugin/skills/specgen-node-cli-web/references/auth-patterns.md +293 -0
  66. package/plugin/skills/specgen-node-cli-web/references/cli-packaging-patterns.md +250 -0
  67. package/plugin/skills/specgen-node-cli-web/references/server-patterns.md +247 -0
  68. package/plugin/skills/specgen-node-cli-web/references/spec-template.md +401 -0
  69. package/plugin/skills/specgen-node-cli-web/references/testing-patterns.md +174 -0
  70. package/plugin/skills/specgen-react-mui/SKILL.md +789 -0
  71. package/plugin/skills/specgen-react-mui/references/component-patterns.md +1077 -0
  72. package/plugin/skills/specgen-react-mui/references/reporting-patterns.md +1998 -0
  73. package/plugin/skills/specgen-react-mui/references/routing-patterns.md +461 -0
  74. package/plugin/skills/specgen-react-mui/references/security-patterns.md +599 -0
  75. package/plugin/skills/specgen-react-mui/references/spec-template.md +1030 -0
  76. package/plugin/skills/specgen-react-mui/references/state-patterns.md +327 -0
  77. package/plugin/skills/specgen-react-tailwind/SKILL.md +859 -0
  78. package/plugin/skills/specgen-react-tailwind/references/component-patterns.md +1212 -0
  79. package/plugin/skills/specgen-react-tailwind/references/reporting-patterns.md +1529 -0
  80. package/plugin/skills/specgen-react-tailwind/references/routing-patterns.md +669 -0
  81. package/plugin/skills/specgen-react-tailwind/references/security-patterns.md +656 -0
  82. package/plugin/skills/specgen-react-tailwind/references/spec-template.md +1237 -0
  83. package/plugin/skills/specgen-react-tailwind/references/state-patterns.md +327 -0
  84. package/plugin/skills/specgen-sdk-java/SKILL.md +933 -0
  85. package/plugin/skills/specgen-sdk-java/references/api-extraction-patterns.md +247 -0
  86. package/plugin/skills/specgen-sdk-java/references/http-client-patterns.md +495 -0
  87. package/plugin/skills/specgen-sdk-java/references/packaging-patterns.md +366 -0
  88. package/plugin/skills/specgen-sdk-java/references/spec-template.md +956 -0
  89. package/plugin/skills/specgen-spring-jpa-jtehtmx/SKILL.md +1284 -0
  90. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/batch-patterns.md +1224 -0
  91. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/jasper-patterns.md +1638 -0
  92. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/messaging-patterns.md +512 -0
  93. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/modulith-patterns.md +354 -0
  94. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/security-patterns.md +551 -0
  95. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/spec-template.md +2502 -0
  96. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/web-patterns.md +503 -0
  97. package/plugin/skills/specgen-spring-jpa-restapi/SKILL.md +990 -0
  98. package/plugin/skills/specgen-spring-jpa-restapi/references/batch-patterns.md +1224 -0
  99. package/plugin/skills/specgen-spring-jpa-restapi/references/messaging-patterns.md +512 -0
  100. package/plugin/skills/specgen-spring-jpa-restapi/references/modulith-patterns.md +279 -0
  101. package/plugin/skills/specgen-spring-jpa-restapi/references/reporting-patterns.md +1536 -0
  102. package/plugin/skills/specgen-spring-jpa-restapi/references/restapi-patterns.md +722 -0
  103. package/plugin/skills/specgen-spring-jpa-restapi/references/security-patterns.md +351 -0
  104. package/plugin/skills/specgen-spring-jpa-restapi/references/spec-template.md +553 -0
  105. package/plugin/skills/specgen-ts-cli/SKILL.md +861 -0
  106. package/plugin/skills/specgen-ts-cli/references/async-patterns.md +1101 -0
  107. package/plugin/skills/specgen-ts-cli/references/command-patterns.md +383 -0
  108. package/plugin/skills/specgen-ts-cli/references/config-patterns.md +430 -0
  109. package/plugin/skills/specgen-ts-cli/references/database-patterns.md +750 -0
  110. package/plugin/skills/specgen-ts-cli/references/packaging-patterns.md +426 -0
  111. package/plugin/skills/specgen-ts-cli/references/spec-template.md +1391 -0
  112. package/plugin/skills/specgen-ts-cli/references/testing-patterns.md +909 -0
  113. package/plugin/skills/testgen-functional/SKILL.md +1381 -0
  114. package/plugin/skills/tracegen-matrix/SKILL.md +243 -0
  115. package/plugin/skills/util-preparek8senv/SKILL.md +422 -0
  116. package/plugin/skills/util-projectinit/SKILL.md +307 -0
  117. package/plugin/skills/util-projectinit/reference/brainstorm-loop.md +129 -0
  118. package/plugin/skills/util-projectinit/reference/brainstorm-protocol.md +144 -0
  119. package/plugin/skills/util-projectinit/reference/brainstorm-setup-guide.md +153 -0
  120. package/plugin/skills/util-projectinit/reference/brainstorm-template-appdev.md +87 -0
  121. package/plugin/skills/util-projectinit/reference/co2-context-generation-guide.md +761 -0
  122. package/plugin/skills/util-projectsync/SKILL.md +501 -0
  123. package/plugin/skills/util-updprd/SKILL.md +324 -0
  124. package/plugin/skills/util-usanalyzer/SKILL.md +307 -0
  125. package/plugin/skills/util-ustagger/SKILL.md +154 -0
  126. package/static/assets/abnfDiagram-VRR7QNED-DvPuwyCV.js +1 -0
  127. package/static/assets/arc-DRKw7sjs.js +1 -0
  128. package/static/assets/architectureDiagram-ZJ3FMSHR-CaNcxUbC.js +36 -0
  129. package/static/assets/blockDiagram-677ZJIJ3-Demd4AOK.js +132 -0
  130. package/static/assets/c4Diagram-LMCZKHZV-PVKUfc2x.js +10 -0
  131. package/static/assets/channel-C2nVbuwv.js +1 -0
  132. package/static/assets/chunk-2Q5K7J3B-CExf8ww_.js +1 -0
  133. package/static/assets/chunk-32BRIVSS-CFPaoONF.js +1 -0
  134. package/static/assets/chunk-5VM5RSS4-DE2esM67.js +15 -0
  135. package/static/assets/chunk-EX3LRPZG-SON_YdDG.js +231 -0
  136. package/static/assets/chunk-JWPE2WC7-Qxah8LNr.js +1 -0
  137. package/static/assets/chunk-MOJQB5TN-BcWGQV3j.js +88 -0
  138. package/static/assets/chunk-RYQCIY6F-DkDj-OR5.js +1 -0
  139. package/static/assets/chunk-V7JOEXUC-BlI1Mrah.js +206 -0
  140. package/static/assets/chunk-VR4S4FIN-Agf__duj.js +1 -0
  141. package/static/assets/chunk-XXDRQBXY-B5CfAh85.js +1 -0
  142. package/static/assets/classDiagram-OUVF2IWQ-DXJIljsR.js +1 -0
  143. package/static/assets/classDiagram-v2-EOCWNBFH-DXJIljsR.js +1 -0
  144. package/static/assets/cose-bilkent-JH36ORCC-DO0cQkcy.js +1 -0
  145. package/static/assets/cynefin-VYW2F7L2-CfOnsnXc.js +178 -0
  146. package/static/assets/cynefinDiagram-TSTJHNR4-BJ8tULAv.js +62 -0
  147. package/static/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
  148. package/static/assets/dagre-VKFMJZFB-DfjwzHqP.js +4 -0
  149. package/static/assets/defaultLocale-DX6XiGOO.js +1 -0
  150. package/static/assets/diagram-FQU43EPY-CndSOIIM.js +3 -0
  151. package/static/assets/diagram-G47NLZAW-Czf5hN0Z.js +24 -0
  152. package/static/assets/diagram-NH7WQ7WH-COAyojGh.js +24 -0
  153. package/static/assets/diagram-OA4YK3LP-H8PoiN2m.js +30 -0
  154. package/static/assets/diagram-WEI45ONY-DzcaVzjp.js +41 -0
  155. package/static/assets/ebnfDiagram-CCIWWBDH-DPazGYLJ.js +1 -0
  156. package/static/assets/erDiagram-Q63AITRT-Bo-fubgF.js +85 -0
  157. package/static/assets/flowDiagram-23GEKE2U-CSvxUDwh.js +156 -0
  158. package/static/assets/ganttDiagram-NO4QXBWP-DnBveWX6.js +292 -0
  159. package/static/assets/gitGraphDiagram-IHSO6WYX-B3rVL8c-.js +106 -0
  160. package/static/assets/graph-C9eacEi8.js +1 -0
  161. package/static/assets/index-LZSQkLE2.css +41 -0
  162. package/static/assets/index-y7XDSgMG.js +495 -0
  163. package/static/assets/infoDiagram-FWYZ7A6U-CvWV9yy2.js +2 -0
  164. package/static/assets/init-Gi6I4Gst.js +1 -0
  165. package/static/assets/ishikawaDiagram-FXEZZL3T-DF28a1N6.js +70 -0
  166. package/static/assets/journeyDiagram-5HDEW3XC-CB6CugYk.js +139 -0
  167. package/static/assets/kanban-definition-HUTT4EX6-ResSLF6d.js +89 -0
  168. package/static/assets/katex-C5jXJg4s.js +257 -0
  169. package/static/assets/layout-DEXfKzaS.js +1 -0
  170. package/static/assets/linear-CLO--ryk.js +1 -0
  171. package/static/assets/map-Czzmt4hB.js +1 -0
  172. package/static/assets/mindmap-definition-LN4V7U3C-BvW3EbxX.js +96 -0
  173. package/static/assets/ordinal-Cboi1Yqb.js +1 -0
  174. package/static/assets/pegDiagram-2B236MQR-BHCgqrrM.js +1 -0
  175. package/static/assets/pieDiagram-ENE6RG2P-DVmCQ5FA.js +39 -0
  176. package/static/assets/quadrantDiagram-ABIIQ3AL-B3e5KR52.js +7 -0
  177. package/static/assets/railroadDiagram-RFXS5EU6-Csv5ysLc.js +1 -0
  178. package/static/assets/requirementDiagram-TGXJPOKE-DOMVzvnB.js +84 -0
  179. package/static/assets/sankeyDiagram-HTMAVEWB-B1dcTOvy.js +40 -0
  180. package/static/assets/sequenceDiagram-DBY2YBRQ-BY414yeO.js +162 -0
  181. package/static/assets/sizeCapture-X5ZJPWSS-CuJfrfBN.js +1 -0
  182. package/static/assets/stateDiagram-2N3HPSRC-FX4rJkzV.js +1 -0
  183. package/static/assets/stateDiagram-v2-6OUMAXLB-BVufbO_H.js +1 -0
  184. package/static/assets/swimlanes-5IMT3BWC-Sfy58mmv.js +2 -0
  185. package/static/assets/swimlanesDiagram-G3AALYLV-wDCDw08H.js +8 -0
  186. package/static/assets/timeline-definition-FHXFAJF6-CmV7by8p.js +120 -0
  187. package/static/assets/vennDiagram-L72KCM5P-FqIyFZFt.js +34 -0
  188. package/static/assets/wardleyDiagram-EHGQE667-BZ06O45i.js +78 -0
  189. package/static/assets/xychartDiagram-FW5EYKEG-BOkffR06.js +7 -0
  190. package/static/index.html +24 -0
@@ -0,0 +1,495 @@
1
+ # HTTP Client Patterns — OkHttp Wiring
2
+
3
+ This reference describes the canonical OkHttp wiring the generated spec must produce.
4
+ The SDK uses **one shared `OkHttpClient`** for the entire library lifetime; every
5
+ service routes through that client; every cross-cutting concern is implemented as an
6
+ `Interceptor`.
7
+
8
+ ---
9
+
10
+ ## Why a Single Shared `OkHttpClient`
11
+
12
+ OkHttp's `OkHttpClient` is **expensive to create** (it owns a connection pool, a
13
+ dispatcher, and a thread pool) and **cheap to share** (it is fully thread-safe). The
14
+ SDK MUST:
15
+
16
+ - Build exactly one `OkHttpClient` per `{{ClientName}}` instance
17
+ - Hand the same instance to every module's service
18
+ - Expose a `close()` method on the facade that shuts down the dispatcher and evicts the
19
+ pool
20
+
21
+ > **Anti-pattern:** Creating a new `OkHttpClient.Builder().build()` per service or per
22
+ > request. This leaks file descriptors and hammers the remote API with new connections.
23
+
24
+ ---
25
+
26
+ ## Interceptor Chain
27
+
28
+ Every request flows through this ordered chain:
29
+
30
+ ```
31
+ [application code]
32
+
33
+
34
+ [CorrelationIdInterceptor] ← adds X-Correlation-Id if absent
35
+
36
+
37
+ [AuthInterceptor] ← injects Authorization or X-API-Key (conditional)
38
+
39
+
40
+ [RetryInterceptor] ← strategic retry on 502/503/504 + IOException
41
+
42
+
43
+ [LoggingInterceptor] ← redacted req/res logging via SLF4J (conditional)
44
+
45
+
46
+ [OkHttp dispatcher → network]
47
+ ```
48
+
49
+ The order matters:
50
+
51
+ 1. **Correlation ID first** — so the same ID propagates through retries and is logged.
52
+ 2. **Auth before retry** — if a refresh happens, retry sees the new token.
53
+ 3. **Retry before logging** — so logging sees the final attempt's wire data, not every
54
+ attempt.
55
+
56
+ ---
57
+
58
+ ## Interceptor Implementations
59
+
60
+ ### CorrelationIdInterceptor
61
+
62
+ ```java
63
+ package {{BASE_PACKAGE}}.http;
64
+
65
+ import okhttp3.Interceptor;
66
+ import okhttp3.Request;
67
+ import okhttp3.Response;
68
+
69
+ import java.io.IOException;
70
+ import java.util.UUID;
71
+
72
+ final class CorrelationIdInterceptor implements Interceptor {
73
+
74
+ static final String HEADER = "X-Correlation-Id";
75
+
76
+ @Override
77
+ public Response intercept(Chain chain) throws IOException {
78
+ Request original = chain.request();
79
+ if (original.header(HEADER) != null) {
80
+ return chain.proceed(original);
81
+ }
82
+ Request withId = original.newBuilder()
83
+ .header(HEADER, UUID.randomUUID().toString())
84
+ .build();
85
+ return chain.proceed(withId);
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### AuthInterceptor (Bearer)
91
+
92
+ ```java
93
+ package {{BASE_PACKAGE}}.auth;
94
+
95
+ import okhttp3.Interceptor;
96
+ import okhttp3.Request;
97
+ import okhttp3.Response;
98
+
99
+ import java.io.IOException;
100
+
101
+ public final class AuthInterceptor implements Interceptor {
102
+
103
+ private final BearerCredentialProvider provider;
104
+
105
+ public AuthInterceptor(BearerCredentialProvider provider) {
106
+ this.provider = provider;
107
+ }
108
+
109
+ @Override
110
+ public Response intercept(Chain chain) throws IOException {
111
+ Request request = applyToken(chain.request());
112
+ Response response = chain.proceed(request);
113
+ if (response.code() != 401) {
114
+ return response;
115
+ }
116
+ // 401 → refresh once, replay once.
117
+ response.close();
118
+ provider.refresh();
119
+ Request retry = applyToken(chain.request());
120
+ return chain.proceed(retry);
121
+ }
122
+
123
+ private Request applyToken(Request request) {
124
+ String token = provider.token();
125
+ if (token == null || token.isEmpty()) return request;
126
+ return request.newBuilder()
127
+ .header("Authorization", "Bearer " + token)
128
+ .build();
129
+ }
130
+ }
131
+ ```
132
+
133
+ ### AuthInterceptor (API Key)
134
+
135
+ ```java
136
+ public final class ApiKeyInterceptor implements Interceptor {
137
+
138
+ private final String headerName;
139
+ private final String value;
140
+
141
+ public ApiKeyInterceptor(String headerName, String value) {
142
+ this.headerName = headerName;
143
+ this.value = value;
144
+ }
145
+
146
+ @Override
147
+ public Response intercept(Chain chain) throws IOException {
148
+ Request req = chain.request().newBuilder()
149
+ .header(headerName, value)
150
+ .build();
151
+ return chain.proceed(req);
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### AuthInterceptor (HTTP Basic)
157
+
158
+ ```java
159
+ import okhttp3.Credentials;
160
+
161
+ public final class BasicAuthInterceptor implements Interceptor {
162
+
163
+ private final String credential;
164
+
165
+ public BasicAuthInterceptor(String username, String password) {
166
+ this.credential = Credentials.basic(username, password);
167
+ }
168
+
169
+ @Override
170
+ public Response intercept(Chain chain) throws IOException {
171
+ Request req = chain.request().newBuilder()
172
+ .header("Authorization", credential)
173
+ .build();
174
+ return chain.proceed(req);
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### mTLS — `SSLSocketFactory` Configuration
180
+
181
+ ```java
182
+ package {{BASE_PACKAGE}}.auth;
183
+
184
+ import okhttp3.OkHttpClient;
185
+
186
+ import javax.net.ssl.KeyManagerFactory;
187
+ import javax.net.ssl.SSLContext;
188
+ import javax.net.ssl.TrustManagerFactory;
189
+ import javax.net.ssl.X509TrustManager;
190
+ import java.io.InputStream;
191
+ import java.nio.file.Files;
192
+ import java.nio.file.Path;
193
+ import java.security.KeyStore;
194
+
195
+ public final class MTlsConfigurer {
196
+
197
+ private MTlsConfigurer() {}
198
+
199
+ public static OkHttpClient.Builder configure(
200
+ OkHttpClient.Builder builder,
201
+ Path keystorePath, char[] keystorePassword,
202
+ Path truststorePath, char[] truststorePassword) {
203
+
204
+ try (InputStream ksIn = Files.newInputStream(keystorePath);
205
+ InputStream tsIn = Files.newInputStream(truststorePath)) {
206
+
207
+ KeyStore keyStore = KeyStore.getInstance("PKCS12");
208
+ keyStore.load(ksIn, keystorePassword);
209
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(
210
+ KeyManagerFactory.getDefaultAlgorithm());
211
+ kmf.init(keyStore, keystorePassword);
212
+
213
+ KeyStore trustStore = KeyStore.getInstance("PKCS12");
214
+ trustStore.load(tsIn, truststorePassword);
215
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
216
+ TrustManagerFactory.getDefaultAlgorithm());
217
+ tmf.init(trustStore);
218
+
219
+ X509TrustManager tm = (X509TrustManager) tmf.getTrustManagers()[0];
220
+
221
+ SSLContext ctx = SSLContext.getInstance("TLS");
222
+ ctx.init(kmf.getKeyManagers(), new javax.net.ssl.TrustManager[]{tm}, null);
223
+
224
+ return builder.sslSocketFactory(ctx.getSocketFactory(), tm);
225
+ } catch (Exception e) {
226
+ throw new IllegalStateException("mTLS configuration failed", e);
227
+ }
228
+ }
229
+ }
230
+ ```
231
+
232
+ ### RetryInterceptor
233
+
234
+ ```java
235
+ package {{BASE_PACKAGE}}.http;
236
+
237
+ import okhttp3.Interceptor;
238
+ import okhttp3.Request;
239
+ import okhttp3.Response;
240
+
241
+ import java.io.IOException;
242
+
243
+ final class RetryInterceptor implements Interceptor {
244
+
245
+ private final RetryStrategy strategy;
246
+
247
+ RetryInterceptor(RetryStrategy strategy) {
248
+ this.strategy = strategy;
249
+ }
250
+
251
+ @Override
252
+ public Response intercept(Chain chain) throws IOException {
253
+ Request request = chain.request();
254
+ int attempt = 0;
255
+ IOException lastError = null;
256
+
257
+ while (true) {
258
+ Response response = null;
259
+ IOException error = null;
260
+ try {
261
+ response = chain.proceed(request);
262
+ } catch (IOException e) {
263
+ error = e;
264
+ }
265
+
266
+ RetryStrategy.Decision decision = strategy.evaluate(attempt, response, error);
267
+ if (!decision.retry) {
268
+ if (error != null) throw error;
269
+ return response;
270
+ }
271
+
272
+ if (response != null) response.close();
273
+ lastError = error;
274
+ attempt++;
275
+
276
+ try {
277
+ Thread.sleep(decision.delayMillis);
278
+ } catch (InterruptedException ie) {
279
+ Thread.currentThread().interrupt();
280
+ if (lastError != null) throw new IOException("Interrupted while retrying", lastError);
281
+ throw new IOException("Interrupted while retrying");
282
+ }
283
+ }
284
+ }
285
+ }
286
+ ```
287
+
288
+ ### LoggingInterceptor (SLF4J, with redaction)
289
+
290
+ ```java
291
+ package {{BASE_PACKAGE}}.http;
292
+
293
+ import okhttp3.Interceptor;
294
+ import okhttp3.Request;
295
+ import okhttp3.Response;
296
+ import org.slf4j.Logger;
297
+ import org.slf4j.LoggerFactory;
298
+
299
+ import java.io.IOException;
300
+
301
+ final class LoggingInterceptor implements Interceptor {
302
+
303
+ private static final Logger log = LoggerFactory.getLogger("{{BASE_PACKAGE}}.http");
304
+
305
+ @Override
306
+ public Response intercept(Chain chain) throws IOException {
307
+ Request req = chain.request();
308
+ if (log.isDebugEnabled()) {
309
+ log.debug("--> {} {} (auth={})",
310
+ req.method(), req.url(),
311
+ req.header("Authorization") == null ? "none" : "Bearer ***");
312
+ }
313
+ long t0 = System.nanoTime();
314
+ Response resp = chain.proceed(req);
315
+ if (log.isDebugEnabled()) {
316
+ long ms = (System.nanoTime() - t0) / 1_000_000L;
317
+ log.debug("<-- {} {} ({} ms)", resp.code(), req.url(), ms);
318
+ }
319
+ return resp;
320
+ }
321
+ }
322
+ ```
323
+
324
+ > The `LoggingInterceptor` is registered ONLY when SLF4J is on the consumer's
325
+ > classpath (see `Slf4jPresence` in `references/spec-template.md`). The interceptor
326
+ > never logs the request or response BODY — bodies often contain credentials or PII
327
+ > and OkHttp's `consume`-once contract makes safe body logging non-trivial.
328
+
329
+ ---
330
+
331
+ ## Per-Service Call Pattern
332
+
333
+ Every service method follows this template:
334
+
335
+ ```java
336
+ public OrderDto getById(String id) {
337
+ HttpUrl url = HttpUrl.parse(config.baseUrl())
338
+ .newBuilder()
339
+ .addPathSegments("orders/" + id)
340
+ .build();
341
+
342
+ Request req = new Request.Builder()
343
+ .url(url)
344
+ .header("Accept", "application/json")
345
+ .get()
346
+ .build();
347
+
348
+ try (Response resp = http.newCall(req).execute()) {
349
+ if (resp.code() == 404) {
350
+ throw new OrdersException.NotFound(404, body(resp), "GET", url.toString());
351
+ }
352
+ if (!resp.isSuccessful()) {
353
+ throw new OrdersException(resp.code(), body(resp), "GET", url.toString());
354
+ }
355
+ @SuppressWarnings("unchecked")
356
+ Map<String, Object> map = (Map<String, Object>) Json.parse(body(resp));
357
+ return OrderDto.fromJsonMap(map);
358
+ } catch (IOException e) {
359
+ throw new SdkClientException("GET " + url + " failed", e);
360
+ }
361
+ }
362
+
363
+ private static String body(Response resp) throws IOException {
364
+ return resp.body() != null ? resp.body().string() : "";
365
+ }
366
+ ```
367
+
368
+ Notes:
369
+
370
+ - `try (Response resp = ...)` is mandatory — OkHttp `Response` holds connection
371
+ resources that MUST be closed.
372
+ - `resp.body().string()` consumes the body and closes the stream — call it once.
373
+ - Path segments use `addPathSegments("orders/" + id)` so `id` is URL-encoded by
374
+ OkHttp. NEVER concatenate raw IDs into the URL string.
375
+ - Query parameters use `addQueryParameter("status", status.wireValue())`.
376
+
377
+ ---
378
+
379
+ ## Async Surface (CompletableFuture)
380
+
381
+ If Async API = yes, every sync method has a `*Async` variant:
382
+
383
+ ```java
384
+ public CompletableFuture<OrderDto> getByIdAsync(String id) {
385
+ Request req = /* same builder as the sync version */;
386
+ CompletableFuture<OrderDto> future = new CompletableFuture<>();
387
+ http.newCall(req).enqueue(new Callback() {
388
+ @Override
389
+ public void onFailure(Call call, IOException e) {
390
+ future.completeExceptionally(new SdkClientException("GET " + req.url() + " failed", e));
391
+ }
392
+ @Override
393
+ public void onResponse(Call call, Response resp) {
394
+ try (Response r = resp) {
395
+ if (!r.isSuccessful()) {
396
+ future.completeExceptionally(new OrdersException(r.code(), body(r), "GET", req.url().toString()));
397
+ return;
398
+ }
399
+ @SuppressWarnings("unchecked")
400
+ Map<String, Object> map = (Map<String, Object>) Json.parse(body(r));
401
+ future.complete(OrderDto.fromJsonMap(map));
402
+ } catch (Exception e) {
403
+ future.completeExceptionally(e);
404
+ }
405
+ }
406
+ });
407
+ return future;
408
+ }
409
+ ```
410
+
411
+ The sync wrapper is a one-liner over the async one when Async = all:
412
+
413
+ ```java
414
+ public OrderDto getById(String id) {
415
+ try {
416
+ return getByIdAsync(id).join();
417
+ } catch (CompletionException ce) {
418
+ Throwable cause = ce.getCause();
419
+ if (cause instanceof RuntimeException) throw (RuntimeException) cause;
420
+ throw new SdkClientException("getById failed", cause);
421
+ }
422
+ }
423
+ ```
424
+
425
+ OkHttp's dispatcher already manages a thread pool — the SDK does NOT spin up its own.
426
+
427
+ ---
428
+
429
+ ## WebSocket [CONDITIONAL]
430
+
431
+ OkHttp on JDK 8 supports WebSocket via `OkHttpClient#newWebSocket`:
432
+
433
+ ```java
434
+ public Subscription subscribe(String topic, EventListener listener) {
435
+ Request req = new Request.Builder()
436
+ .url(config.baseUrl() + "/ws")
437
+ .header("Authorization", "Bearer " + token())
438
+ .build();
439
+ WebSocket ws = http.newWebSocket(req, new WebSocketListener() {
440
+ @Override public void onMessage(WebSocket s, String text) { listener.onEvent(text); }
441
+ @Override public void onFailure(WebSocket s, Throwable t, Response r) { listener.onError(t); }
442
+ @Override public void onClosed(WebSocket s, int code, String reason) { listener.onClosed(code, reason); }
443
+ });
444
+ return () -> ws.close(1000, "client closed");
445
+ }
446
+ ```
447
+
448
+ The public `Subscription` interface is a single-method functional interface:
449
+
450
+ ```java
451
+ public interface Subscription extends AutoCloseable {
452
+ @Override void close();
453
+ }
454
+ ```
455
+
456
+ The JDK 11 overlay MAY substitute `java.net.http.HttpClient.newWebSocketBuilder()`
457
+ for performance — but the public surface is identical, so consumers see no difference.
458
+
459
+ ---
460
+
461
+ ## Server-Sent Events (SSE) [CONDITIONAL]
462
+
463
+ Requires `okhttp-sse` (also a Square artifact, same group). If SSE is selected, add:
464
+
465
+ ```xml
466
+ <dependency>
467
+ <groupId>com.squareup.okhttp3</groupId>
468
+ <artifactId>okhttp-sse</artifactId>
469
+ <version>${okhttp.version}</version>
470
+ </dependency>
471
+ ```
472
+
473
+ …and relocate `okhttp3.sse` along with `okhttp3` in the Shade plugin (it's the same
474
+ package prefix, so no extra rule is needed).
475
+
476
+ ```java
477
+ EventSources.createFactory(http).newEventSource(req, listener);
478
+ ```
479
+
480
+ ---
481
+
482
+ ## Configuration Knobs Surface
483
+
484
+ The `Config` class exposes (immutable, all `Duration`-typed):
485
+
486
+ - `baseUrl` — required
487
+ - `connectTimeout`, `readTimeout`, `writeTimeout` — default 30s each
488
+ - `callTimeout` — default 0 (off; use the per-stage timeouts)
489
+ - `maxIdleConnections` — default 10
490
+ - `keepAliveDuration` — default 5 min
491
+ - `retryStrategy` — defaults to `ExponentialBackoffRetryStrategy.defaults()`
492
+ - `credentialProvider` — null if Auth = none
493
+
494
+ Every knob is a Builder method on `{{ClientName}}.Builder`. Validation
495
+ (e.g., `baseUrl != null`) happens in `build()`.