@tier0/sdk-v2 0.9.9 → 0.10.0

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 (250) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/LICENSE +21 -21
  3. package/README.md +165 -27
  4. package/dist/cjs/client.d.ts +79 -3
  5. package/dist/cjs/client.js +4 -6
  6. package/dist/cjs/client.js.map +1 -1
  7. package/dist/cjs/cloud-server.d.ts +33 -26
  8. package/dist/cjs/cloud-server.js +102 -100
  9. package/dist/cjs/cloud-server.js.map +1 -1
  10. package/dist/cjs/cloud-transport.d.ts +15 -20
  11. package/dist/cjs/cloud-transport.js +87 -68
  12. package/dist/cjs/cloud-transport.js.map +1 -1
  13. package/dist/cjs/connection-diagnostics.d.ts +2 -0
  14. package/dist/cjs/connection-diagnostics.js +20 -0
  15. package/dist/cjs/connection-diagnostics.js.map +1 -0
  16. package/dist/cjs/data/bootstrap.js +3 -4
  17. package/dist/cjs/data/bootstrap.js.map +1 -1
  18. package/dist/cjs/data/call.d.ts +1 -3
  19. package/dist/cjs/data/call.js +8 -12
  20. package/dist/cjs/data/call.js.map +1 -1
  21. package/dist/cjs/data/client.d.ts +8 -7
  22. package/dist/cjs/data/client.js +24 -11
  23. package/dist/cjs/data/client.js.map +1 -1
  24. package/dist/cjs/data/collection.d.ts +3 -5
  25. package/dist/cjs/data/collection.js +3 -4
  26. package/dist/cjs/data/collection.js.map +1 -1
  27. package/dist/cjs/data/context.d.ts +5 -11
  28. package/dist/cjs/data/context.js +21 -36
  29. package/dist/cjs/data/context.js.map +1 -1
  30. package/dist/cjs/data/error.d.ts +1 -1
  31. package/dist/cjs/data/error.js +3 -3
  32. package/dist/cjs/data/error.js.map +1 -1
  33. package/dist/cjs/data/index.d.ts +5 -3
  34. package/dist/cjs/data/index.js +5 -5
  35. package/dist/cjs/data/index.js.map +1 -1
  36. package/dist/cjs/data/relay.d.ts +51 -0
  37. package/dist/cjs/data/relay.js +371 -0
  38. package/dist/cjs/data/relay.js.map +1 -0
  39. package/dist/cjs/data/subscribe.d.ts +22 -38
  40. package/dist/cjs/data/subscribe.js +22 -28
  41. package/dist/cjs/data/subscribe.js.map +1 -1
  42. package/dist/cjs/event-stream.d.ts +28 -0
  43. package/dist/cjs/event-stream.js +222 -0
  44. package/dist/cjs/event-stream.js.map +1 -0
  45. package/dist/cjs/mq/client.d.ts +32 -1
  46. package/dist/cjs/mq/client.js +404 -69
  47. package/dist/cjs/mq/client.js.map +1 -1
  48. package/dist/cjs/mq/index.d.ts +1 -0
  49. package/dist/cjs/mq/index.js +3 -1
  50. package/dist/cjs/mq/index.js.map +1 -1
  51. package/dist/cjs/mq/topic.d.ts +29 -0
  52. package/dist/cjs/mq/topic.js +48 -0
  53. package/dist/cjs/mq/topic.js.map +1 -0
  54. package/dist/cjs/mq/types.d.ts +21 -1
  55. package/dist/cjs/mq/types.js.map +1 -1
  56. package/dist/cjs/openapi/api.generated.d.ts +20 -0
  57. package/dist/cjs/openapi/api.generated.js +11 -0
  58. package/dist/cjs/openapi/api.generated.js.map +1 -1
  59. package/dist/cjs/openapi/client.d.ts +46 -0
  60. package/dist/cjs/openapi/client.js +161 -12
  61. package/dist/cjs/openapi/client.js.map +1 -1
  62. package/dist/cjs/openapi/codecs.generated.d.ts +74 -0
  63. package/dist/cjs/openapi/codecs.generated.js +1 -1
  64. package/dist/cjs/openapi/codecs.generated.js.map +1 -1
  65. package/dist/cjs/openapi/types.generated.d.ts +205 -1
  66. package/dist/cjs/openapi/types.generated.js.map +1 -1
  67. package/dist/cjs/page-runtime.d.ts +48 -0
  68. package/dist/cjs/page-runtime.js +74 -0
  69. package/dist/cjs/page-runtime.js.map +1 -0
  70. package/dist/cjs/platform-proxy.d.ts +17 -0
  71. package/dist/cjs/platform-proxy.js +52 -0
  72. package/dist/cjs/platform-proxy.js.map +1 -0
  73. package/dist/cjs/runtime-context.d.ts +2 -1
  74. package/dist/cjs/runtime-context.js +6 -2
  75. package/dist/cjs/runtime-context.js.map +1 -1
  76. package/dist/cjs/runtime-env.js.map +1 -1
  77. package/dist/cjs/source.d.ts +19 -1
  78. package/dist/cjs/source.js +9 -3
  79. package/dist/cjs/source.js.map +1 -1
  80. package/dist/cjs/stream.js +3 -2
  81. package/dist/cjs/stream.js.map +1 -1
  82. package/dist/cjs/streams/contract.generated.d.ts +7 -1
  83. package/dist/cjs/streams/contract.generated.js.map +1 -1
  84. package/dist/cjs/streams/messages.js +1 -10
  85. package/dist/cjs/streams/messages.js.map +1 -1
  86. package/dist/cjs/streams/requests.d.ts +3 -0
  87. package/dist/cjs/streams/requests.js +5 -2
  88. package/dist/cjs/streams/requests.js.map +1 -1
  89. package/dist/cjs/streams/transport.d.ts +1 -13
  90. package/dist/cjs/streams/transport.js +2 -18
  91. package/dist/cjs/streams/transport.js.map +1 -1
  92. package/dist/cjs/uns-v2/client.d.ts +1 -6
  93. package/dist/cjs/uns-v2/client.js +33 -8
  94. package/dist/cjs/uns-v2/client.js.map +1 -1
  95. package/dist/cjs/uns-v2/data-client.d.ts +5 -2
  96. package/dist/cjs/uns-v2/data-client.js +7 -4
  97. package/dist/cjs/uns-v2/data-client.js.map +1 -1
  98. package/dist/cjs/uns-v2/generated.d.ts +6783 -4655
  99. package/dist/cjs/uns-v2/generated.js +221 -65
  100. package/dist/cjs/uns-v2/generated.js.map +1 -1
  101. package/dist/cjs/uns-v2/sse.d.ts +7 -1
  102. package/dist/cjs/uns-v2/sse.js +12 -2
  103. package/dist/cjs/uns-v2/sse.js.map +1 -1
  104. package/dist/esm/client.d.ts +79 -3
  105. package/dist/esm/client.js +5 -7
  106. package/dist/esm/client.js.map +1 -1
  107. package/dist/esm/cloud-server.d.ts +33 -26
  108. package/dist/esm/cloud-server.js +99 -97
  109. package/dist/esm/cloud-server.js.map +1 -1
  110. package/dist/esm/cloud-transport.d.ts +15 -20
  111. package/dist/esm/cloud-transport.js +86 -67
  112. package/dist/esm/cloud-transport.js.map +1 -1
  113. package/dist/esm/connection-diagnostics.d.ts +2 -0
  114. package/dist/esm/connection-diagnostics.js +17 -0
  115. package/dist/esm/connection-diagnostics.js.map +1 -0
  116. package/dist/esm/data/bootstrap.js +3 -4
  117. package/dist/esm/data/bootstrap.js.map +1 -1
  118. package/dist/esm/data/call.d.ts +1 -3
  119. package/dist/esm/data/call.js +9 -13
  120. package/dist/esm/data/call.js.map +1 -1
  121. package/dist/esm/data/client.d.ts +8 -7
  122. package/dist/esm/data/client.js +22 -9
  123. package/dist/esm/data/client.js.map +1 -1
  124. package/dist/esm/data/collection.d.ts +3 -5
  125. package/dist/esm/data/collection.js +3 -4
  126. package/dist/esm/data/collection.js.map +1 -1
  127. package/dist/esm/data/context.d.ts +5 -11
  128. package/dist/esm/data/context.js +19 -33
  129. package/dist/esm/data/context.js.map +1 -1
  130. package/dist/esm/data/error.d.ts +1 -1
  131. package/dist/esm/data/error.js +3 -3
  132. package/dist/esm/data/error.js.map +1 -1
  133. package/dist/esm/data/index.d.ts +5 -3
  134. package/dist/esm/data/index.js +3 -2
  135. package/dist/esm/data/index.js.map +1 -1
  136. package/dist/esm/data/relay.d.ts +51 -0
  137. package/dist/esm/data/relay.js +368 -0
  138. package/dist/esm/data/relay.js.map +1 -0
  139. package/dist/esm/data/subscribe.d.ts +22 -38
  140. package/dist/esm/data/subscribe.js +22 -27
  141. package/dist/esm/data/subscribe.js.map +1 -1
  142. package/dist/esm/event-stream.d.ts +28 -0
  143. package/dist/esm/event-stream.js +217 -0
  144. package/dist/esm/event-stream.js.map +1 -0
  145. package/dist/esm/mq/client.d.ts +32 -1
  146. package/dist/esm/mq/client.js +404 -69
  147. package/dist/esm/mq/client.js.map +1 -1
  148. package/dist/esm/mq/index.d.ts +1 -0
  149. package/dist/esm/mq/index.js +1 -0
  150. package/dist/esm/mq/index.js.map +1 -1
  151. package/dist/esm/mq/topic.d.ts +29 -0
  152. package/dist/esm/mq/topic.js +44 -0
  153. package/dist/esm/mq/topic.js.map +1 -0
  154. package/dist/esm/mq/types.d.ts +21 -1
  155. package/dist/esm/mq/types.js.map +1 -1
  156. package/dist/esm/openapi/api.generated.d.ts +20 -0
  157. package/dist/esm/openapi/api.generated.js +11 -0
  158. package/dist/esm/openapi/api.generated.js.map +1 -1
  159. package/dist/esm/openapi/client.d.ts +46 -0
  160. package/dist/esm/openapi/client.js +160 -12
  161. package/dist/esm/openapi/client.js.map +1 -1
  162. package/dist/esm/openapi/codecs.generated.d.ts +74 -0
  163. package/dist/esm/openapi/codecs.generated.js +1 -1
  164. package/dist/esm/openapi/codecs.generated.js.map +1 -1
  165. package/dist/esm/openapi/types.generated.d.ts +205 -1
  166. package/dist/esm/openapi/types.generated.js.map +1 -1
  167. package/dist/esm/page-runtime.d.ts +48 -0
  168. package/dist/esm/page-runtime.js +65 -0
  169. package/dist/esm/page-runtime.js.map +1 -0
  170. package/dist/esm/platform-proxy.d.ts +17 -0
  171. package/dist/esm/platform-proxy.js +47 -0
  172. package/dist/esm/platform-proxy.js.map +1 -0
  173. package/dist/esm/runtime-context.d.ts +2 -1
  174. package/dist/esm/runtime-context.js +6 -2
  175. package/dist/esm/runtime-context.js.map +1 -1
  176. package/dist/esm/runtime-env.js.map +1 -1
  177. package/dist/esm/source.d.ts +19 -1
  178. package/dist/esm/source.js +10 -4
  179. package/dist/esm/source.js.map +1 -1
  180. package/dist/esm/stream.js +4 -3
  181. package/dist/esm/stream.js.map +1 -1
  182. package/dist/esm/streams/contract.generated.d.ts +7 -1
  183. package/dist/esm/streams/contract.generated.js.map +1 -1
  184. package/dist/esm/streams/messages.js +1 -10
  185. package/dist/esm/streams/messages.js.map +1 -1
  186. package/dist/esm/streams/requests.d.ts +3 -0
  187. package/dist/esm/streams/requests.js +5 -2
  188. package/dist/esm/streams/requests.js.map +1 -1
  189. package/dist/esm/streams/transport.d.ts +1 -13
  190. package/dist/esm/streams/transport.js +1 -17
  191. package/dist/esm/streams/transport.js.map +1 -1
  192. package/dist/esm/uns-v2/client.d.ts +1 -6
  193. package/dist/esm/uns-v2/client.js +33 -8
  194. package/dist/esm/uns-v2/client.js.map +1 -1
  195. package/dist/esm/uns-v2/data-client.d.ts +5 -2
  196. package/dist/esm/uns-v2/data-client.js +8 -5
  197. package/dist/esm/uns-v2/data-client.js.map +1 -1
  198. package/dist/esm/uns-v2/generated.d.ts +6783 -4655
  199. package/dist/esm/uns-v2/generated.js +221 -65
  200. package/dist/esm/uns-v2/generated.js.map +1 -1
  201. package/dist/esm/uns-v2/sse.d.ts +7 -1
  202. package/dist/esm/uns-v2/sse.js +12 -2
  203. package/dist/esm/uns-v2/sse.js.map +1 -1
  204. package/package.json +25 -12
  205. package/skills/tier0-sdk-v2/SKILL.md +13 -5
  206. package/skills/tier0-sdk-v2/references/integration.md +14 -24
  207. package/skills/tier0-sdk-v2/references/local-connection.md +61 -0
  208. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/SKILL.md +11 -5
  209. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/consistency.md +8 -12
  210. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/errors.md +24 -5
  211. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/modeling.md +3 -1
  212. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/read-write.md +46 -13
  213. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/schema-evolution.md +2 -0
  214. package/skills/tier0-sdk-v2/tier0-sdk-v2-members/SKILL.md +2 -2
  215. package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/app-members.md +5 -1
  216. package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/SKILL.md +25 -0
  217. package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/references/quickstart.md +1 -1
  218. package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/SKILL.md +3 -3
  219. package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/send.md +6 -6
  220. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +4 -4
  221. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/changes.md +2 -2
  222. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +26 -36
  223. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/delete.md +9 -23
  224. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/protocols.md +12 -29
  225. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/read.md +4 -5
  226. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +5 -5
  227. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +3 -3
  228. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +23 -9
  229. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/deploy.md +14 -12
  230. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/http-server.md +4 -4
  231. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/read.md +4 -3
  232. package/skills/tier0-sdk-v2/tier0-sdk-v2-streams/SKILL.md +12 -12
  233. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md +3 -2
  234. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/create.md +2 -2
  235. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/delete.md +47 -20
  236. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/namespace.md +3 -3
  237. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/read.md +11 -6
  238. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/restore.md +12 -13
  239. package/dist/cjs/app-identity-contract.generated.d.ts +0 -22
  240. package/dist/cjs/app-identity-contract.generated.js +0 -51
  241. package/dist/cjs/app-identity-contract.generated.js.map +0 -1
  242. package/dist/cjs/runtime.d.ts +0 -13
  243. package/dist/cjs/runtime.js +0 -51
  244. package/dist/cjs/runtime.js.map +0 -1
  245. package/dist/esm/app-identity-contract.generated.d.ts +0 -22
  246. package/dist/esm/app-identity-contract.generated.js +0 -48
  247. package/dist/esm/app-identity-contract.generated.js.map +0 -1
  248. package/dist/esm/runtime.d.ts +0 -13
  249. package/dist/esm/runtime.js +0 -46
  250. package/dist/esm/runtime.js.map +0 -1
@@ -8,7 +8,7 @@ import type { CloudTransportConfig } from './cloud-transport.js';
8
8
  export interface Tier0ClientConfig extends ClientConfig, CloudTransportConfig {
9
9
  }
10
10
  export type Tier0Client = ReturnType<typeof createClient>;
11
- /** 现役服务端和数据客户端保留独立配置;浏览器交互仅使用受信宿主。 */
11
+ /** 每个实例持有独立配置;带 Key 的客户端只在服务端使用。 */
12
12
  export declare function createClient(config?: Tier0ClientConfig): Readonly<{
13
13
  streams: {
14
14
  requests: StreamRequestsClient;
@@ -59,6 +59,8 @@ export declare function createClient(config?: Tier0ClientConfig): Readonly<{
59
59
  send: (body: import("./index.js").components["schemas"]["SdknotificationsSendRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
60
60
  createdAt: string;
61
61
  messageId: string;
62
+ recipientName?: string;
63
+ recipientUserId: string;
62
64
  status: string;
63
65
  }>;
64
66
  get: (body: import("./index.js").components["schemas"]["SdknotificationsGetRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -68,9 +70,17 @@ export declare function createClient(config?: Tier0ClientConfig): Readonly<{
68
70
  errorCode?: string;
69
71
  message?: string;
70
72
  messageId: string;
73
+ recipientName?: string;
74
+ recipientUserId: string;
71
75
  status: string;
72
76
  type: string;
73
77
  }>;
78
+ list: (body?: import("./index.js").components["schemas"]["SdknotificationsListRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
79
+ list: import("./index.js").components["schemas"]["NotificationListItem"][];
80
+ page: number | bigint;
81
+ size: number | bigint;
82
+ total: number | bigint;
83
+ }>;
74
84
  };
75
85
  mqttAuth: {
76
86
  create: (body: import("./index.js").components["schemas"]["SdkmqttAuthCreateRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -210,7 +220,6 @@ export declare function createClient(config?: Tier0ClientConfig): Readonly<{
210
220
  files: FilesClient;
211
221
  capabilities: CapabilitiesClient;
212
222
  source: Readonly<{
213
- delete: (request: import("./index.js").CloudSourceDeleteReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDeleteResponse>;
214
223
  validate: (request: import("./index.js").UnsV2SourceValidateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceValidateResponse>;
215
224
  probe: (request: import("./index.js").UnsV2SourceProbeReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceProbeResponse>;
216
225
  discover: (request: import("./index.js").CloudSourceDiscoverReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDiscoverResponse>;
@@ -225,11 +234,30 @@ export declare function createClient(config?: Tier0ClientConfig): Readonly<{
225
234
  observations: Readonly<{
226
235
  get: (request: import("./index.js").CloudSourceObservationsGetReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceObservationsGetResponse>;
227
236
  }>;
237
+ resources: Readonly<{
238
+ catalog: (request: import("./index.js").CloudSourceResourceCatalogReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceResourceCatalogResponse>;
239
+ preview: (request: import("./index.js").CloudSourceResourceReadReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceResourceReadResponse>;
240
+ scan: (request: import("./index.js").CloudSourceResourceScanReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceResourceScanResponse>;
241
+ }>;
242
+ devices: Readonly<{
243
+ list: (request: import("./index.js").CloudSourceDevicesListReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDevicesListResponse>;
244
+ }>;
228
245
  documents: Readonly<{
229
246
  list: (request: import("./index.js").CloudSourceDocumentListReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentListResponse>;
230
247
  get: (request: import("./index.js").CloudSourceDocumentGetReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentGetResponse>;
231
248
  create: (request: import("./index.js").CloudSourceDocumentCreateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentCreateResponse>;
232
249
  update: (request: import("./index.js").CloudSourceDocumentUpdateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentUpdateResponse>;
250
+ delete: (request: import("./index.js").UnsV2SourceDocumentDeleteReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceDocumentDeleteResponse>;
251
+ credentials: Readonly<{
252
+ update: (request: import("./index.js").UnsV2SourceNativeCredentialsUpdateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceNativeCredentialsUpdateResponse>;
253
+ }>;
254
+ state: Readonly<{
255
+ update: (request: import("./index.js").CloudEdgeSourceStateUpdateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudEdgeSourceStateUpdateResponse>;
256
+ }>;
257
+ oauth: Readonly<{
258
+ start: (request: import("./index.js").UnsV2SourceNativeOAuthStartReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceNativeOAuthStartResponse>;
259
+ complete: (request: import("./index.js").UnsV2SourceNativeOAuthCompleteReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceNativeOAuthCompleteResponse>;
260
+ }>;
233
261
  }>;
234
262
  }>;
235
263
  stream: Readonly<{
@@ -335,6 +363,8 @@ export declare function createClient(config?: Tier0ClientConfig): Readonly<{
335
363
  send: (body: import("./index.js").components["schemas"]["SdknotificationsSendRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
336
364
  createdAt: string;
337
365
  messageId: string;
366
+ recipientName?: string;
367
+ recipientUserId: string;
338
368
  status: string;
339
369
  }>;
340
370
  get: (body: import("./index.js").components["schemas"]["SdknotificationsGetRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -344,9 +374,17 @@ export declare function createClient(config?: Tier0ClientConfig): Readonly<{
344
374
  errorCode?: string;
345
375
  message?: string;
346
376
  messageId: string;
377
+ recipientName?: string;
378
+ recipientUserId: string;
347
379
  status: string;
348
380
  type: string;
349
381
  }>;
382
+ list: (body?: import("./index.js").components["schemas"]["SdknotificationsListRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
383
+ list: import("./index.js").components["schemas"]["NotificationListItem"][];
384
+ page: number | bigint;
385
+ size: number | bigint;
386
+ total: number | bigint;
387
+ }>;
350
388
  };
351
389
  members: {
352
390
  listWorkspace: (body?: import("./index.js").components["schemas"]["SdkmembersListWorkspaceRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -570,6 +608,8 @@ export declare const client: Readonly<{
570
608
  send: (body: import("./index.js").components["schemas"]["SdknotificationsSendRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
571
609
  createdAt: string;
572
610
  messageId: string;
611
+ recipientName?: string;
612
+ recipientUserId: string;
573
613
  status: string;
574
614
  }>;
575
615
  get: (body: import("./index.js").components["schemas"]["SdknotificationsGetRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -579,9 +619,17 @@ export declare const client: Readonly<{
579
619
  errorCode?: string;
580
620
  message?: string;
581
621
  messageId: string;
622
+ recipientName?: string;
623
+ recipientUserId: string;
582
624
  status: string;
583
625
  type: string;
584
626
  }>;
627
+ list: (body?: import("./index.js").components["schemas"]["SdknotificationsListRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
628
+ list: import("./index.js").components["schemas"]["NotificationListItem"][];
629
+ page: number | bigint;
630
+ size: number | bigint;
631
+ total: number | bigint;
632
+ }>;
585
633
  };
586
634
  mqttAuth: {
587
635
  create: (body: import("./index.js").components["schemas"]["SdkmqttAuthCreateRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -721,7 +769,6 @@ export declare const client: Readonly<{
721
769
  files: FilesClient;
722
770
  capabilities: CapabilitiesClient;
723
771
  source: Readonly<{
724
- delete: (request: import("./index.js").CloudSourceDeleteReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDeleteResponse>;
725
772
  validate: (request: import("./index.js").UnsV2SourceValidateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceValidateResponse>;
726
773
  probe: (request: import("./index.js").UnsV2SourceProbeReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceProbeResponse>;
727
774
  discover: (request: import("./index.js").CloudSourceDiscoverReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDiscoverResponse>;
@@ -736,11 +783,30 @@ export declare const client: Readonly<{
736
783
  observations: Readonly<{
737
784
  get: (request: import("./index.js").CloudSourceObservationsGetReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceObservationsGetResponse>;
738
785
  }>;
786
+ resources: Readonly<{
787
+ catalog: (request: import("./index.js").CloudSourceResourceCatalogReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceResourceCatalogResponse>;
788
+ preview: (request: import("./index.js").CloudSourceResourceReadReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceResourceReadResponse>;
789
+ scan: (request: import("./index.js").CloudSourceResourceScanReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceResourceScanResponse>;
790
+ }>;
791
+ devices: Readonly<{
792
+ list: (request: import("./index.js").CloudSourceDevicesListReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDevicesListResponse>;
793
+ }>;
739
794
  documents: Readonly<{
740
795
  list: (request: import("./index.js").CloudSourceDocumentListReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentListResponse>;
741
796
  get: (request: import("./index.js").CloudSourceDocumentGetReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentGetResponse>;
742
797
  create: (request: import("./index.js").CloudSourceDocumentCreateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentCreateResponse>;
743
798
  update: (request: import("./index.js").CloudSourceDocumentUpdateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudSourceDocumentUpdateResponse>;
799
+ delete: (request: import("./index.js").UnsV2SourceDocumentDeleteReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceDocumentDeleteResponse>;
800
+ credentials: Readonly<{
801
+ update: (request: import("./index.js").UnsV2SourceNativeCredentialsUpdateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceNativeCredentialsUpdateResponse>;
802
+ }>;
803
+ state: Readonly<{
804
+ update: (request: import("./index.js").CloudEdgeSourceStateUpdateReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").CloudEdgeSourceStateUpdateResponse>;
805
+ }>;
806
+ oauth: Readonly<{
807
+ start: (request: import("./index.js").UnsV2SourceNativeOAuthStartReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceNativeOAuthStartResponse>;
808
+ complete: (request: import("./index.js").UnsV2SourceNativeOAuthCompleteReq, options?: import("./openapi/client.js").RequestOptions) => Promise<import("./index.js").UnsV2SourceNativeOAuthCompleteResponse>;
809
+ }>;
744
810
  }>;
745
811
  }>;
746
812
  stream: Readonly<{
@@ -846,6 +912,8 @@ export declare const client: Readonly<{
846
912
  send: (body: import("./index.js").components["schemas"]["SdknotificationsSendRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
847
913
  createdAt: string;
848
914
  messageId: string;
915
+ recipientName?: string;
916
+ recipientUserId: string;
849
917
  status: string;
850
918
  }>;
851
919
  get: (body: import("./index.js").components["schemas"]["SdknotificationsGetRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -855,9 +923,17 @@ export declare const client: Readonly<{
855
923
  errorCode?: string;
856
924
  message?: string;
857
925
  messageId: string;
926
+ recipientName?: string;
927
+ recipientUserId: string;
858
928
  status: string;
859
929
  type: string;
860
930
  }>;
931
+ list: (body?: import("./index.js").components["schemas"]["SdknotificationsListRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
932
+ list: import("./index.js").components["schemas"]["NotificationListItem"][];
933
+ page: number | bigint;
934
+ size: number | bigint;
935
+ total: number | bigint;
936
+ }>;
861
937
  };
862
938
  members: {
863
939
  listWorkspace: (body?: import("./index.js").components["schemas"]["SdkmembersListWorkspaceRequest"], options?: import("./openapi/client.js").RequestOptions) => Promise<{
@@ -14,9 +14,7 @@ const source_js_1 = require("./source.js");
14
14
  const stream_js_1 = require("./stream.js");
15
15
  const capabilities_js_2 = require("./capabilities.js");
16
16
  const files_js_1 = require("./files.js");
17
- /** Use a fresh instance per incoming request when supplying employee data delegation. */
18
- function assemble(resolve, snapshot) {
19
- const http = resolve();
17
+ function assemble(resolve, snapshot, http = resolve()) {
20
18
  const api = (0, api_generated_js_1.createOpenAPI)(http);
21
19
  const transport = new transport_js_1.StreamTransport(resolve, snapshot);
22
20
  const messages = new messages_js_1.StreamMessagesClient(transport);
@@ -37,9 +35,9 @@ function assemble(resolve, snapshot) {
37
35
  api,
38
36
  });
39
37
  }
40
- /** 现役服务端和数据客户端保留独立配置;浏览器交互仅使用受信宿主。 */
38
+ /** 每个实例持有独立配置;带 Key 的客户端只在服务端使用。 */
41
39
  function createClient(config = {}) {
42
- const snapshot = Object.freeze({ ...config });
40
+ const snapshot = Object.freeze((0, client_js_1.snapshotClientConfig)(config));
43
41
  const http = new client_js_1.HttpClient(snapshot);
44
42
  return assemble(() => http, snapshot);
45
43
  }
@@ -52,5 +50,5 @@ const defaultHttp = new Proxy(new client_js_1.HttpClient(), {
52
50
  },
53
51
  });
54
52
  /** App 默认交互客户端在调用时解析宿主,无需在浏览器配置密钥。 */
55
- exports.client = assemble(() => defaultHttp, {});
53
+ exports.client = assemble(client_js_1.getClient, {}, defaultHttp);
56
54
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":";;;AAyCA,oCAIC;AA7CD,uDAA6D;AAC7D,uDAA6D;AAC7D,yDAAyD;AACzD,+DAAqE;AACrE,mDAA+E;AAC/E,iEAA2D;AAC3D,kDAAuD;AACvD,4DAA4D;AAC5D,2CAA+C;AAC/C,2CAA+C;AAC/C,uDAAuD;AACvD,yCAAyC;AAIzC,yFAAyF;AACzF,SAAS,QAAQ,CAAC,OAAyB,EAAE,QAA2B;IACtE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,IAAA,gCAAa,EAAC,IAAI,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,8BAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,kCAAoB,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,IAAA,6BAAiB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,kCAAoB,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,0CAAwB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;QACnI,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,KAAK,EAAE,IAAI,sBAAW,CAAC,IAAI,CAAC;QAC5B,YAAY,EAAE,IAAI,oCAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC;QACvD,MAAM,EAAE,IAAA,4BAAgB,EAAC,GAAG,CAAC;QAC7B,MAAM,EAAE,IAAA,4BAAgB,EAAC,GAAG,CAAC;QAC7B,GAAG,EAAE,IAAA,kCAAiB,EAAC,GAAG,CAAC;QAC3B,GAAG;KACJ,CAAC,CAAC;AACL,CAAC;AAGD,sCAAsC;AACtC,SAAgB,YAAY,CAAC,SAA4B,EAAE;IACzD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,IAAI,sBAAU,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,6CAA6C;AAC7C,MAAM,WAAW,GAAG,IAAI,KAAK,CAAC,IAAI,sBAAU,EAAE,EAAE;IAC9C,GAAG,CAAC,OAAO,EAAE,GAAG;QACd,MAAM,OAAO,GAAG,IAAA,qBAAS,GAAE,CAAC;QAC5B,MAAM,KAAK,GAAY,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACjD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,CAAC;CACF,CAAC,CAAC;AACH,sCAAsC;AACzB,QAAA,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC","sourcesContent":["import { StreamRequestsClient } from './streams/requests.js';\nimport { StreamMessagesClient } from './streams/messages.js';\nimport { StreamTransport } from './streams/transport.js';\nimport { StreamCapabilitiesClient } from './streams/capabilities.js';\nimport { getClient, HttpClient, type ClientConfig } from './openapi/client.js';\nimport { createOpenAPI } from './openapi/api.generated.js';\nimport { createUnsV2Client } from './uns-v2/client.js';\nimport { bindUnsDataClient } from './uns-v2/data-client.js';\nimport { bindSourceClient } from './source.js';\nimport { bindStreamClient } from './stream.js';\nimport { CapabilitiesClient } from './capabilities.js';\nimport { FilesClient } from './files.js';\nimport type { CloudTransportConfig } from './cloud-transport.js';\n\nexport interface Tier0ClientConfig extends ClientConfig, CloudTransportConfig {}\n/** Use a fresh instance per incoming request when supplying employee data delegation. */\nfunction assemble(resolve: () => HttpClient, snapshot: Tier0ClientConfig) {\n const http = resolve();\n const api = createOpenAPI(http);\n const transport = new StreamTransport(resolve, snapshot);\n const messages = new StreamMessagesClient(transport);\n const raw = createUnsV2Client(resolve, snapshot);\n return Object.freeze({\n streams: { requests: new StreamRequestsClient(transport), messages, capabilities: new StreamCapabilitiesClient(resolve, snapshot) },\n dispose: () => messages.dispose(),\n system: api.system,\n members: api.members,\n notifications: api.notifications,\n mqttAuth: api.mqttAuth,\n agent: api.agent,\n files: new FilesClient(http),\n capabilities: new CapabilitiesClient(resolve, snapshot),\n source: bindSourceClient(raw),\n stream: bindStreamClient(raw),\n uns: bindUnsDataClient(raw),\n api,\n });\n}\nexport type Tier0Client = ReturnType<typeof createClient>;\n\n/** 现役服务端和数据客户端保留独立配置;浏览器交互仅使用受信宿主。 */\nexport function createClient(config: Tier0ClientConfig = {}) {\n const snapshot = Object.freeze({ ...config });\n const http = new HttpClient(snapshot);\n return assemble(() => http, snapshot);\n}\n\n// 全局兼容入口也在调用时读取 configureClient,不固化模块导入时的配置。\nconst defaultHttp = new Proxy(new HttpClient(), {\n get(_target, key) {\n const current = getClient();\n const value: unknown = Reflect.get(current, key);\n return typeof value === 'function' ? value.bind(current) : value;\n },\n});\n/** App 默认交互客户端在调用时解析宿主,无需在浏览器配置密钥。 */\nexport const client = assemble(() => defaultHttp, {});\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":";;;AAuCA,oCAIC;AA3CD,uDAA6D;AAC7D,uDAA6D;AAC7D,yDAAyD;AACzD,+DAAqE;AACrE,mDAAqG;AACrG,iEAA2D;AAC3D,kDAAuD;AACvD,4DAA4D;AAC5D,2CAA+C;AAC/C,2CAA+C;AAC/C,uDAAuD;AACvD,yCAAyC;AAIzC,SAAS,QAAQ,CAAC,OAAyB,EAAE,QAA2B,EAAE,IAAI,GAAG,OAAO,EAAE;IACxF,MAAM,GAAG,GAAG,IAAA,gCAAa,EAAC,IAAI,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,8BAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,kCAAoB,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,IAAA,6BAAiB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,kCAAoB,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,0CAAwB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;QACnI,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,KAAK,EAAE,IAAI,sBAAW,CAAC,IAAI,CAAC;QAC5B,YAAY,EAAE,IAAI,oCAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC;QACvD,MAAM,EAAE,IAAA,4BAAgB,EAAC,GAAG,CAAC;QAC7B,MAAM,EAAE,IAAA,4BAAgB,EAAC,GAAG,CAAC;QAC7B,GAAG,EAAE,IAAA,kCAAiB,EAAC,GAAG,CAAC;QAC3B,GAAG;KACJ,CAAC,CAAC;AACL,CAAC;AAGD,oCAAoC;AACpC,SAAgB,YAAY,CAAC,SAA4B,EAAE;IACzD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAA,gCAAoB,EAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,IAAI,sBAAU,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,6CAA6C;AAC7C,MAAM,WAAW,GAAG,IAAI,KAAK,CAAC,IAAI,sBAAU,EAAE,EAAE;IAC9C,GAAG,CAAC,OAAO,EAAE,GAAG;QACd,MAAM,OAAO,GAAG,IAAA,qBAAS,GAAE,CAAC;QAC5B,MAAM,KAAK,GAAY,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACjD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,CAAC;CACF,CAAC,CAAC;AACH,sCAAsC;AACzB,QAAA,MAAM,GAAG,QAAQ,CAAC,qBAAS,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC","sourcesContent":["import { StreamRequestsClient } from './streams/requests.js';\nimport { StreamMessagesClient } from './streams/messages.js';\nimport { StreamTransport } from './streams/transport.js';\nimport { StreamCapabilitiesClient } from './streams/capabilities.js';\nimport { getClient, HttpClient, snapshotClientConfig, type ClientConfig } from './openapi/client.js';\nimport { createOpenAPI } from './openapi/api.generated.js';\nimport { createUnsV2Client } from './uns-v2/client.js';\nimport { bindUnsDataClient } from './uns-v2/data-client.js';\nimport { bindSourceClient } from './source.js';\nimport { bindStreamClient } from './stream.js';\nimport { CapabilitiesClient } from './capabilities.js';\nimport { FilesClient } from './files.js';\nimport type { CloudTransportConfig } from './cloud-transport.js';\n\nexport interface Tier0ClientConfig extends ClientConfig, CloudTransportConfig {}\nfunction assemble(resolve: () => HttpClient, snapshot: Tier0ClientConfig, http = resolve()) {\n const api = createOpenAPI(http);\n const transport = new StreamTransport(resolve, snapshot);\n const messages = new StreamMessagesClient(transport);\n const raw = createUnsV2Client(resolve, snapshot);\n return Object.freeze({\n streams: { requests: new StreamRequestsClient(transport), messages, capabilities: new StreamCapabilitiesClient(resolve, snapshot) },\n dispose: () => messages.dispose(),\n system: api.system,\n members: api.members,\n notifications: api.notifications,\n mqttAuth: api.mqttAuth,\n agent: api.agent,\n files: new FilesClient(http),\n capabilities: new CapabilitiesClient(resolve, snapshot),\n source: bindSourceClient(raw),\n stream: bindStreamClient(raw),\n uns: bindUnsDataClient(raw),\n api,\n });\n}\nexport type Tier0Client = ReturnType<typeof createClient>;\n\n/** 每个实例持有独立配置;带 Key 的客户端只在服务端使用。 */\nexport function createClient(config: Tier0ClientConfig = {}) {\n const snapshot = Object.freeze(snapshotClientConfig(config));\n const http = new HttpClient(snapshot);\n return assemble(() => http, snapshot);\n}\n\n// 全局兼容入口也在调用时读取 configureClient,不固化模块导入时的配置。\nconst defaultHttp = new Proxy(new HttpClient(), {\n get(_target, key) {\n const current = getClient();\n const value: unknown = Reflect.get(current, key);\n return typeof value === 'function' ? value.bind(current) : value;\n },\n});\n/** App 默认交互客户端在调用时解析宿主,无需在浏览器配置密钥。 */\nexport const client = assemble(getClient, {}, defaultHttp);\n"]}
@@ -1,31 +1,38 @@
1
- export declare const APP_REQUEST_IDENTITY_HEADER: "X-Tier0-App-Identity";
2
- export declare class AppRequestIdentityError extends Error {
3
- readonly code: 'APP_IDENTITY_INVALID' | 'APP_IDENTITY_CONFIGURATION_INVALID';
4
- constructor(code: 'APP_IDENTITY_INVALID' | 'APP_IDENTITY_CONFIGURATION_INVALID');
1
+ /** Set by the front door on every request it forwards to the App, after stripping any `X-Tier0-*` the client sent. */
2
+ export declare const VISITOR_HEADER = "X-Tier0-Visitor";
3
+ export type VisitorErrorCode = 'VISITOR_HEADER_INVALID' | 'VISITOR_CONFIGURATION_INVALID';
4
+ export declare class VisitorError extends Error {
5
+ readonly code: VisitorErrorCode;
6
+ constructor(code: VisitorErrorCode);
5
7
  }
6
- export interface VerifiedCloudAppUser {
7
- readonly kind: 'gateway-user';
8
- readonly userID: string;
8
+ /** The visitor of a request, from `X-Tier0-Visitor`. */
9
+ export interface Visitor {
10
+ readonly subType: 'employee' | 'machine';
11
+ /** Employee user ID, or the call token ID of a machine visitor. */
12
+ readonly subject: string;
13
+ /** Grant of an employee's access; empty for a machine visitor. */
14
+ readonly grant: string;
9
15
  readonly workspaceID: string;
10
16
  readonly appID: string;
11
- readonly roleKeys: readonly string[];
12
- readonly requestID: string;
13
- readonly issuedAt: number;
14
- readonly expiresAt: number;
15
- readonly verificationKeyID: string;
17
+ readonly runtime: 'deployed' | 'preview';
18
+ /** Roles of this visitor in the App; in Preview, the roles selected in "view as". */
19
+ readonly appRoles: readonly string[];
20
+ /** Only in Preview's "view as". */
21
+ readonly activeRole?: string;
16
22
  }
17
- export interface CloudAppIdentityAuthority {
18
- appID: string;
19
- workspaceID: string;
20
- /** Pinned server configuration, never a key or URL taken from the request. */
21
- publicKeys: unknown;
23
+ export interface ParseVisitorOptions {
24
+ /** The App the header must name. Defaults to `TIER0_APP_ID`. */
25
+ appID?: string;
22
26
  }
23
- export interface CloudAppIdentityRequest {
24
- assertion: string | undefined;
25
- method: string;
26
- requestURI: string;
27
- /** Exact bytes received from the gateway, before JSON parsing or normalization. */
28
- body: Uint8Array;
29
- }
30
- /** Verifies request provenance, not business authorization or delegated UNS permissions. */
31
- export declare function createCloudAppRequestVerifier(authority: CloudAppIdentityAuthority): (request: CloudAppIdentityRequest) => VerifiedCloudAppUser;
27
+ /**
28
+ * Parses `X-Tier0-Visitor`: the unpadded base64url (RFC 4648 §5) of a UTF-8
29
+ * JSON object of at most 8192 bytes. The header is not signed; the front door
30
+ * is the only way into the App and replaces whatever the client sent. Parsing
31
+ * is strict: a byte order mark, a duplicate key, a lone UTF-16 surrogate
32
+ * (e.g. `"\ud800"`), an unknown or missing field, a wrong type or length, a `ws` that
33
+ * is not a positive decimal ID without sign or leading zero, an employee
34
+ * without a grant or a machine visitor with one, or an `app` other than this
35
+ * App's throws `VISITOR_HEADER_INVALID`. Without an App ID
36
+ * (`TIER0_APP_ID` unset) it throws `VISITOR_CONFIGURATION_INVALID`.
37
+ */
38
+ export declare function parseVisitorHeader(value: string | null | undefined, options?: ParseVisitorOptions): Visitor;
@@ -1,114 +1,116 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AppRequestIdentityError = exports.APP_REQUEST_IDENTITY_HEADER = void 0;
4
- exports.createCloudAppRequestVerifier = createCloudAppRequestVerifier;
5
- // Server-only entry point. Browser HTTP clients remain independent of node:crypto.
6
- const node_crypto_1 = require("node:crypto");
7
- const app_identity_contract_generated_js_1 = require("./app-identity-contract.generated.js");
8
- exports.APP_REQUEST_IDENTITY_HEADER = app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.header;
9
- class AppRequestIdentityError extends Error {
3
+ exports.VisitorError = exports.VISITOR_HEADER = void 0;
4
+ exports.parseVisitorHeader = parseVisitorHeader;
5
+ // Server-only entry point: the App's view of the request it is serving.
6
+ const runtime_env_js_1 = require("./runtime-env.js");
7
+ const maxID = BigInt('9223372036854775807');
8
+ /** A positive decimal int64 without sign or leading zero. */
9
+ const validID = (value) => typeof value === 'string' && /^[1-9]\d{0,18}$/.test(value) && BigInt(value) <= maxID;
10
+ const isObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
11
+ /** Set by the front door on every request it forwards to the App, after stripping any `X-Tier0-*` the client sent. */
12
+ exports.VISITOR_HEADER = 'X-Tier0-Visitor';
13
+ /** Limit of the JSON before encoding. */
14
+ const VISITOR_MAX_JSON_BYTES = 8192;
15
+ /** Unpadded base64url of `VISITOR_MAX_JSON_BYTES`. */
16
+ const VISITOR_MAX_HEADER_LENGTH = Math.ceil((VISITOR_MAX_JSON_BYTES * 4) / 3);
17
+ const VISITOR_MAX_STRING_BYTES = 128;
18
+ const VISITOR_FIELDS = new Set(['ws', 'app', 'runtime', 'sub_type', 'sub', 'grant', 'app_roles', 'active_role']);
19
+ class VisitorError extends Error {
10
20
  code;
11
21
  constructor(code) {
12
22
  super(code);
13
23
  this.code = code;
14
- this.name = 'AppRequestIdentityError';
24
+ this.name = 'VisitorError';
15
25
  }
16
26
  }
17
- exports.AppRequestIdentityError = AppRequestIdentityError;
18
- const invalid = () => new AppRequestIdentityError('APP_IDENTITY_INVALID');
19
- const invalidConfig = () => new AppRequestIdentityError('APP_IDENTITY_CONFIGURATION_INVALID');
20
- const appPattern = new RegExp(app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.appIDPattern);
21
- const kidPattern = new RegExp(app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.keyIDPattern);
22
- const methodPattern = new RegExp(app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.methodPattern);
23
- const maxID = BigInt('9223372036854775807');
24
- const validID = (value) => typeof value === 'string' && /^[1-9]\d{0,18}$/.test(value) && BigInt(value) <= maxID;
25
- const isObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
26
- const exactKeys = (value, keys) => Object.keys(value).length === keys.length && Object.keys(value).every((key) => keys.includes(key));
27
- const validString = (value, maxBytes) => typeof value === 'string' && value.length > 0 && Buffer.byteLength(value) <= maxBytes &&
28
- Buffer.from(value).toString('utf8') === value && !/[\u0000-\u001f\u007f-\u009f]/.test(value);
29
- const decode = (value) => {
30
- if (!/^[A-Za-z0-9_-]+$/.test(value))
31
- throw invalid();
32
- const bytes = Buffer.from(value, 'base64url');
33
- if (bytes.toString('base64url') !== value)
34
- throw invalid();
35
- return bytes;
36
- };
37
- /** Verifies request provenance, not business authorization or delegated UNS permissions. */
38
- function createCloudAppRequestVerifier(authority) {
39
- if (!isObject(authority) || typeof authority.appID !== 'string' || !appPattern.test(authority.appID) || !validID(authority.workspaceID))
40
- throw invalidConfig();
41
- const appID = authority.appID;
42
- const workspaceID = authority.workspaceID;
43
- const keys = new Map();
44
- try {
45
- let raw = authority.publicKeys;
46
- if (typeof raw === 'string') {
47
- if (Buffer.byteLength(raw) > app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxTokenBytes * app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxKeys)
48
- throw invalidConfig();
49
- raw = JSON.parse(raw);
50
- }
51
- if (!isObject(raw) || !exactKeys(raw, ['keys']) || !Array.isArray(raw.keys) ||
52
- raw.keys.length === 0 || raw.keys.length > app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxKeys)
53
- throw invalidConfig();
54
- for (const key of raw.keys) {
55
- if (!isObject(key) || !exactKeys(key, app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.publicKeyFields) || key.kty !== 'OKP' ||
56
- key.crv !== 'Ed25519' || typeof key.kid !== 'string' || !kidPattern.test(key.kid) ||
57
- keys.has(key.kid) || typeof key.x !== 'string' || decode(key.x).length !== 32)
58
- throw invalidConfig();
59
- keys.set(key.kid, (0, node_crypto_1.createPublicKey)({ key: { kty: 'OKP', crv: 'Ed25519', x: key.x }, format: 'jwk' }));
27
+ exports.VisitorError = VisitorError;
28
+ /** A UTF-16 surrogate without its pair, as JSON escapes like "\ud800" can produce. */
29
+ const LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
30
+ /**
31
+ * Raw key tokens of the top-level object, for spotting duplicates
32
+ * (`JSON.parse` keeps the last silently). Values of the visitor are strings
33
+ * and arrays of strings, so only depth 1 holds keys.
34
+ */
35
+ function topLevelKeys(json) {
36
+ const keys = [];
37
+ let depth = 0;
38
+ for (let i = 0; i < json.length; i += 1) {
39
+ const char = json[i];
40
+ if (char === '{' || char === '[')
41
+ depth += 1;
42
+ else if (char === '}' || char === ']')
43
+ depth -= 1;
44
+ else if (char === '"') {
45
+ const start = i;
46
+ for (i += 1; i < json.length && json[i] !== '"'; i += 1)
47
+ if (json[i] === '\\')
48
+ i += 1;
49
+ let next = i + 1;
50
+ while (next < json.length && /\s/.test(json[next]))
51
+ next += 1;
52
+ if (depth === 1 && json[next] === ':')
53
+ keys.push(json.slice(start, i + 1));
60
54
  }
61
55
  }
56
+ return keys;
57
+ }
58
+ const bytes = (value) => Buffer.byteLength(value, 'utf8');
59
+ const sized = (value, min, max) => typeof value === 'string' && !LONE_SURROGATE.test(value) && bytes(value) >= min && bytes(value) <= max;
60
+ /**
61
+ * Parses `X-Tier0-Visitor`: the unpadded base64url (RFC 4648 §5) of a UTF-8
62
+ * JSON object of at most 8192 bytes. The header is not signed; the front door
63
+ * is the only way into the App and replaces whatever the client sent. Parsing
64
+ * is strict: a byte order mark, a duplicate key, a lone UTF-16 surrogate
65
+ * (e.g. `"\ud800"`), an unknown or missing field, a wrong type or length, a `ws` that
66
+ * is not a positive decimal ID without sign or leading zero, an employee
67
+ * without a grant or a machine visitor with one, or an `app` other than this
68
+ * App's throws `VISITOR_HEADER_INVALID`. Without an App ID
69
+ * (`TIER0_APP_ID` unset) it throws `VISITOR_CONFIGURATION_INVALID`.
70
+ */
71
+ function parseVisitorHeader(value, options = {}) {
72
+ const appID = options.appID ?? (0, runtime_env_js_1.getEnvVar)('TIER0_APP_ID')?.trim();
73
+ if (!appID)
74
+ throw new VisitorError('VISITOR_CONFIGURATION_INVALID');
75
+ const fail = () => new VisitorError('VISITOR_HEADER_INVALID');
76
+ if (typeof value !== 'string' || value.length === 0 || value.length > VISITOR_MAX_HEADER_LENGTH || !/^[A-Za-z0-9_-]+$/.test(value))
77
+ throw fail();
78
+ const raw = Buffer.from(value, 'base64url');
79
+ // Only the canonical encoding: no padding, no stray trailing bits.
80
+ if (raw.length > VISITOR_MAX_JSON_BYTES || raw.toString('base64url') !== value)
81
+ throw fail();
82
+ // A UTF-8 byte order mark is not part of the contract (TextDecoder would drop it silently).
83
+ if (raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf)
84
+ throw fail();
85
+ let claims;
86
+ let json;
87
+ try {
88
+ json = new TextDecoder('utf-8', { fatal: true }).decode(raw);
89
+ claims = JSON.parse(json);
90
+ }
62
91
  catch {
63
- throw invalidConfig();
92
+ throw fail();
64
93
  }
65
- return (request) => {
66
- try {
67
- if (typeof request.assertion !== 'string' || Buffer.byteLength(request.assertion) > app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxTokenBytes ||
68
- !(request.body instanceof Uint8Array) || request.body.byteLength > app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxBodyBytes ||
69
- !methodPattern.test(request.method) || !validString(request.requestURI, app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxURIBytes) ||
70
- !request.requestURI.startsWith('/') || request.requestURI.startsWith('//'))
71
- throw invalid();
72
- const parts = request.assertion.split('.');
73
- if (parts.length !== 3)
74
- throw invalid();
75
- const header = JSON.parse(decode(parts[0]).toString('utf8'));
76
- if (!isObject(header) || !exactKeys(header, app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.requiredHeaderFields) ||
77
- header.alg !== app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.algorithm || header.typ !== app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.type ||
78
- typeof header.kid !== 'string' || !kidPattern.test(header.kid))
79
- throw invalid();
80
- const key = keys.get(header.kid);
81
- const signature = decode(parts[2]);
82
- if (!key || signature.length !== 64 ||
83
- !(0, node_crypto_1.verify)(null, Buffer.from(parts[0] + '.' + parts[1], 'ascii'), key, signature))
84
- throw invalid();
85
- const claims = JSON.parse(decode(parts[1]).toString('utf8'));
86
- if (!isObject(claims) || !exactKeys(claims, app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.requiredClaims) ||
87
- claims.ver !== app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.version || claims.iss !== app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.issuer || claims.aud !== app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.audience ||
88
- !validID(claims.sub) || claims.workspaceID !== workspaceID || claims.appID !== appID ||
89
- claims.method !== request.method || claims.requestURI !== request.requestURI ||
90
- typeof claims.bodySHA256 !== 'string' || !/^[a-f0-9]{64}$/.test(claims.bodySHA256) ||
91
- claims.bodySHA256 !== (0, node_crypto_1.createHash)('sha256').update(request.body).digest('hex') ||
92
- typeof claims.iat !== 'number' || !Number.isSafeInteger(claims.iat) || claims.iat <= 0 ||
93
- typeof claims.exp !== 'number' || !Number.isSafeInteger(claims.exp) || claims.exp <= claims.iat ||
94
- claims.exp - claims.iat > app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxTTLSeconds ||
95
- typeof claims.jti !== 'string' || !/^[a-f0-9]{32}$/.test(claims.jti) ||
96
- !Array.isArray(claims.roles) || claims.roles.length > app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxRoles ||
97
- claims.roles.some((role) => !validString(role, app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.maxRoleBytes) || role.trim() !== role) ||
98
- new Set(claims.roles).size !== claims.roles.length)
99
- throw invalid();
100
- const now = Math.floor(Date.now() / 1000);
101
- if (claims.iat > now + app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.clockSkewSeconds || now >= claims.exp + app_identity_contract_generated_js_1.APP_REQUEST_IDENTITY_CONTRACT.clockSkewSeconds)
102
- throw invalid();
103
- return Object.freeze({
104
- kind: 'gateway-user', userID: claims.sub, workspaceID, appID,
105
- roleKeys: Object.freeze([...claims.roles]), requestID: claims.jti,
106
- issuedAt: claims.iat, expiresAt: claims.exp, verificationKeyID: header.kid,
107
- });
108
- }
109
- catch {
110
- throw invalid();
111
- }
112
- };
94
+ if (!isObject(claims) || Object.keys(claims).some((key) => !VISITOR_FIELDS.has(key)))
95
+ throw fail();
96
+ // Every key at most once, each spelling decoded ("\u0077s" is "ws").
97
+ const keys = topLevelKeys(json).map((token) => JSON.parse(token));
98
+ if (new Set(keys).size !== keys.length)
99
+ throw fail();
100
+ const { ws, app, runtime, sub_type: subType, sub, grant, app_roles: appRoles, active_role: activeRole } = claims;
101
+ if (!validID(ws) || app !== appID ||
102
+ (runtime !== 'deployed' && runtime !== 'preview') ||
103
+ (subType !== 'employee' && subType !== 'machine') ||
104
+ !sized(sub, 1, VISITOR_MAX_STRING_BYTES) ||
105
+ // An employee's access always has a grant; a machine visitor has none.
106
+ typeof grant !== 'string' || (subType === 'employee' ? !sized(grant, 1, VISITOR_MAX_STRING_BYTES) : grant !== '') ||
107
+ !Array.isArray(appRoles) || appRoles.some((role) => !sized(role, 1, VISITOR_MAX_STRING_BYTES)) ||
108
+ (activeRole !== undefined && !sized(activeRole, 1, VISITOR_MAX_STRING_BYTES)))
109
+ throw fail();
110
+ return Object.freeze({
111
+ subType, subject: sub, grant, workspaceID: ws, appID, runtime,
112
+ appRoles: Object.freeze([...new Set(appRoles)]),
113
+ ...(activeRole === undefined ? {} : { activeRole }),
114
+ });
113
115
  }
114
116
  //# sourceMappingURL=cloud-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-server.js","sourceRoot":"","sources":["../../src/cloud-server.ts"],"names":[],"mappings":"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","sourcesContent":["// Server-only entry point. Browser HTTP clients remain independent of node:crypto.\nimport { createHash, createPublicKey, verify, type KeyObject } from 'node:crypto';\nimport { APP_REQUEST_IDENTITY_CONTRACT as contract } from './app-identity-contract.generated.js';\n\nexport const APP_REQUEST_IDENTITY_HEADER = contract.header;\n\nexport class AppRequestIdentityError extends Error {\n constructor(public readonly code: 'APP_IDENTITY_INVALID' | 'APP_IDENTITY_CONFIGURATION_INVALID') {\n super(code);\n this.name = 'AppRequestIdentityError';\n }\n}\n\nexport interface VerifiedCloudAppUser {\n readonly kind: 'gateway-user';\n readonly userID: string;\n readonly workspaceID: string;\n readonly appID: string;\n readonly roleKeys: readonly string[];\n readonly requestID: string;\n readonly issuedAt: number;\n readonly expiresAt: number;\n readonly verificationKeyID: string;\n}\n\nexport interface CloudAppIdentityAuthority {\n appID: string;\n workspaceID: string;\n /** Pinned server configuration, never a key or URL taken from the request. */\n publicKeys: unknown;\n}\n\nexport interface CloudAppIdentityRequest {\n assertion: string | undefined;\n method: string;\n requestURI: string;\n /** Exact bytes received from the gateway, before JSON parsing or normalization. */\n body: Uint8Array;\n}\n\nconst invalid = () => new AppRequestIdentityError('APP_IDENTITY_INVALID');\nconst invalidConfig = () => new AppRequestIdentityError('APP_IDENTITY_CONFIGURATION_INVALID');\nconst appPattern = new RegExp(contract.appIDPattern);\nconst kidPattern = new RegExp(contract.keyIDPattern);\nconst methodPattern = new RegExp(contract.methodPattern);\nconst maxID = BigInt('9223372036854775807');\nconst validID = (value: unknown): value is string =>\n typeof value === 'string' && /^[1-9]\\d{0,18}$/.test(value) && BigInt(value) <= maxID;\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n !!value && typeof value === 'object' && !Array.isArray(value);\nconst exactKeys = (value: Record<string, unknown>, keys: readonly string[]) =>\n Object.keys(value).length === keys.length && Object.keys(value).every((key) => keys.includes(key));\nconst validString = (value: unknown, maxBytes: number): value is string =>\n typeof value === 'string' && value.length > 0 && Buffer.byteLength(value) <= maxBytes &&\n Buffer.from(value).toString('utf8') === value && !/[\\u0000-\\u001f\\u007f-\\u009f]/.test(value);\nconst decode = (value: string) => {\n if (!/^[A-Za-z0-9_-]+$/.test(value)) throw invalid();\n const bytes = Buffer.from(value, 'base64url');\n if (bytes.toString('base64url') !== value) throw invalid();\n return bytes;\n};\n\n/** Verifies request provenance, not business authorization or delegated UNS permissions. */\nexport function createCloudAppRequestVerifier(authority: CloudAppIdentityAuthority) {\n if (!isObject(authority) || typeof authority.appID !== 'string' || !appPattern.test(authority.appID) || !validID(authority.workspaceID)) throw invalidConfig();\n const appID = authority.appID;\n const workspaceID = authority.workspaceID;\n const keys = new Map<string, KeyObject>();\n try {\n let raw = authority.publicKeys;\n if (typeof raw === 'string') {\n if (Buffer.byteLength(raw) > contract.maxTokenBytes * contract.maxKeys) throw invalidConfig();\n raw = JSON.parse(raw);\n }\n if (!isObject(raw) || !exactKeys(raw, ['keys']) || !Array.isArray(raw.keys) ||\n raw.keys.length === 0 || raw.keys.length > contract.maxKeys) throw invalidConfig();\n for (const key of raw.keys) {\n if (!isObject(key) || !exactKeys(key, contract.publicKeyFields) || key.kty !== 'OKP' ||\n key.crv !== 'Ed25519' || typeof key.kid !== 'string' || !kidPattern.test(key.kid) ||\n keys.has(key.kid) || typeof key.x !== 'string' || decode(key.x).length !== 32) throw invalidConfig();\n keys.set(key.kid, createPublicKey({ key: { kty: 'OKP', crv: 'Ed25519', x: key.x }, format: 'jwk' }));\n }\n } catch { throw invalidConfig(); }\n\n return (request: CloudAppIdentityRequest): VerifiedCloudAppUser => {\n try {\n if (typeof request.assertion !== 'string' || Buffer.byteLength(request.assertion) > contract.maxTokenBytes ||\n !(request.body instanceof Uint8Array) || request.body.byteLength > contract.maxBodyBytes ||\n !methodPattern.test(request.method) || !validString(request.requestURI, contract.maxURIBytes) ||\n !request.requestURI.startsWith('/') || request.requestURI.startsWith('//')) throw invalid();\n const parts = request.assertion.split('.');\n if (parts.length !== 3) throw invalid();\n const header: unknown = JSON.parse(decode(parts[0]).toString('utf8'));\n if (!isObject(header) || !exactKeys(header, contract.requiredHeaderFields) ||\n header.alg !== contract.algorithm || header.typ !== contract.type ||\n typeof header.kid !== 'string' || !kidPattern.test(header.kid)) throw invalid();\n const key = keys.get(header.kid);\n const signature = decode(parts[2]);\n if (!key || signature.length !== 64 ||\n !verify(null, Buffer.from(parts[0] + '.' + parts[1], 'ascii'), key, signature)) throw invalid();\n const claims: unknown = JSON.parse(decode(parts[1]).toString('utf8'));\n if (!isObject(claims) || !exactKeys(claims, contract.requiredClaims) ||\n claims.ver !== contract.version || claims.iss !== contract.issuer || claims.aud !== contract.audience ||\n !validID(claims.sub) || claims.workspaceID !== workspaceID || claims.appID !== appID ||\n claims.method !== request.method || claims.requestURI !== request.requestURI ||\n typeof claims.bodySHA256 !== 'string' || !/^[a-f0-9]{64}$/.test(claims.bodySHA256) ||\n claims.bodySHA256 !== createHash('sha256').update(request.body).digest('hex') ||\n typeof claims.iat !== 'number' || !Number.isSafeInteger(claims.iat) || claims.iat <= 0 ||\n typeof claims.exp !== 'number' || !Number.isSafeInteger(claims.exp) || claims.exp <= claims.iat ||\n claims.exp - claims.iat > contract.maxTTLSeconds ||\n typeof claims.jti !== 'string' || !/^[a-f0-9]{32}$/.test(claims.jti) ||\n !Array.isArray(claims.roles) || claims.roles.length > contract.maxRoles ||\n claims.roles.some((role) => !validString(role, contract.maxRoleBytes) || role.trim() !== role) ||\n new Set(claims.roles).size !== claims.roles.length) throw invalid();\n const now = Math.floor(Date.now() / 1000);\n if (claims.iat > now + contract.clockSkewSeconds || now >= claims.exp + contract.clockSkewSeconds) throw invalid();\n return Object.freeze({\n kind: 'gateway-user' as const, userID: claims.sub, workspaceID, appID,\n roleKeys: Object.freeze([...claims.roles] as string[]), requestID: claims.jti,\n issuedAt: claims.iat, expiresAt: claims.exp, verificationKeyID: header.kid,\n });\n } catch { throw invalid(); }\n };\n}\n"]}
1
+ {"version":3,"file":"cloud-server.js","sourceRoot":"","sources":["../../src/cloud-server.ts"],"names":[],"mappings":"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","sourcesContent":["// Server-only entry point: the App's view of the request it is serving.\nimport { getEnvVar } from './runtime-env.js';\n\nconst maxID = BigInt('9223372036854775807');\n/** A positive decimal int64 without sign or leading zero. */\nconst validID = (value: unknown): value is string =>\n typeof value === 'string' && /^[1-9]\\d{0,18}$/.test(value) && BigInt(value) <= maxID;\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n !!value && typeof value === 'object' && !Array.isArray(value);\n\n/** Set by the front door on every request it forwards to the App, after stripping any `X-Tier0-*` the client sent. */\nexport const VISITOR_HEADER = 'X-Tier0-Visitor';\n\n/** Limit of the JSON before encoding. */\nconst VISITOR_MAX_JSON_BYTES = 8192;\n/** Unpadded base64url of `VISITOR_MAX_JSON_BYTES`. */\nconst VISITOR_MAX_HEADER_LENGTH = Math.ceil((VISITOR_MAX_JSON_BYTES * 4) / 3);\nconst VISITOR_MAX_STRING_BYTES = 128;\nconst VISITOR_FIELDS: ReadonlySet<string> = new Set(['ws', 'app', 'runtime', 'sub_type', 'sub', 'grant', 'app_roles', 'active_role']);\n\nexport type VisitorErrorCode = 'VISITOR_HEADER_INVALID' | 'VISITOR_CONFIGURATION_INVALID';\n\nexport class VisitorError extends Error {\n constructor(public readonly code: VisitorErrorCode) {\n super(code);\n this.name = 'VisitorError';\n }\n}\n\n/** The visitor of a request, from `X-Tier0-Visitor`. */\nexport interface Visitor {\n readonly subType: 'employee' | 'machine';\n /** Employee user ID, or the call token ID of a machine visitor. */\n readonly subject: string;\n /** Grant of an employee's access; empty for a machine visitor. */\n readonly grant: string;\n readonly workspaceID: string;\n readonly appID: string;\n readonly runtime: 'deployed' | 'preview';\n /** Roles of this visitor in the App; in Preview, the roles selected in \"view as\". */\n readonly appRoles: readonly string[];\n /** Only in Preview's \"view as\". */\n readonly activeRole?: string;\n}\n\nexport interface ParseVisitorOptions {\n /** The App the header must name. Defaults to `TIER0_APP_ID`. */\n appID?: string;\n}\n\n/** A UTF-16 surrogate without its pair, as JSON escapes like \"\\ud800\" can produce. */\nconst LONE_SURROGATE = /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/;\n\n/**\n * Raw key tokens of the top-level object, for spotting duplicates\n * (`JSON.parse` keeps the last silently). Values of the visitor are strings\n * and arrays of strings, so only depth 1 holds keys.\n */\nfunction topLevelKeys(json: string): string[] {\n const keys: string[] = [];\n let depth = 0;\n for (let i = 0; i < json.length; i += 1) {\n const char = json[i];\n if (char === '{' || char === '[') depth += 1;\n else if (char === '}' || char === ']') depth -= 1;\n else if (char === '\"') {\n const start = i;\n for (i += 1; i < json.length && json[i] !== '\"'; i += 1) if (json[i] === '\\\\') i += 1;\n let next = i + 1;\n while (next < json.length && /\\s/.test(json[next])) next += 1;\n if (depth === 1 && json[next] === ':') keys.push(json.slice(start, i + 1));\n }\n }\n return keys;\n}\n\nconst bytes = (value: string) => Buffer.byteLength(value, 'utf8');\nconst sized = (value: unknown, min: number, max: number): value is string =>\n typeof value === 'string' && !LONE_SURROGATE.test(value) && bytes(value) >= min && bytes(value) <= max;\n\n/**\n * Parses `X-Tier0-Visitor`: the unpadded base64url (RFC 4648 §5) of a UTF-8\n * JSON object of at most 8192 bytes. The header is not signed; the front door\n * is the only way into the App and replaces whatever the client sent. Parsing\n * is strict: a byte order mark, a duplicate key, a lone UTF-16 surrogate\n * (e.g. `\"\\ud800\"`), an unknown or missing field, a wrong type or length, a `ws` that\n * is not a positive decimal ID without sign or leading zero, an employee\n * without a grant or a machine visitor with one, or an `app` other than this\n * App's throws `VISITOR_HEADER_INVALID`. Without an App ID\n * (`TIER0_APP_ID` unset) it throws `VISITOR_CONFIGURATION_INVALID`.\n */\nexport function parseVisitorHeader(value: string | null | undefined, options: ParseVisitorOptions = {}): Visitor {\n const appID = options.appID ?? getEnvVar('TIER0_APP_ID')?.trim();\n if (!appID) throw new VisitorError('VISITOR_CONFIGURATION_INVALID');\n const fail = () => new VisitorError('VISITOR_HEADER_INVALID');\n if (typeof value !== 'string' || value.length === 0 || value.length > VISITOR_MAX_HEADER_LENGTH || !/^[A-Za-z0-9_-]+$/.test(value)) throw fail();\n const raw = Buffer.from(value, 'base64url');\n // Only the canonical encoding: no padding, no stray trailing bits.\n if (raw.length > VISITOR_MAX_JSON_BYTES || raw.toString('base64url') !== value) throw fail();\n // A UTF-8 byte order mark is not part of the contract (TextDecoder would drop it silently).\n if (raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf) throw fail();\n let claims: unknown;\n let json: string;\n try {\n json = new TextDecoder('utf-8', { fatal: true }).decode(raw);\n claims = JSON.parse(json);\n } catch {\n throw fail();\n }\n if (!isObject(claims) || Object.keys(claims).some((key) => !VISITOR_FIELDS.has(key))) throw fail();\n // Every key at most once, each spelling decoded (\"\\u0077s\" is \"ws\").\n const keys = topLevelKeys(json).map((token) => JSON.parse(token) as string);\n if (new Set(keys).size !== keys.length) throw fail();\n const { ws, app, runtime, sub_type: subType, sub, grant, app_roles: appRoles, active_role: activeRole } = claims;\n if (!validID(ws) || app !== appID ||\n (runtime !== 'deployed' && runtime !== 'preview') ||\n (subType !== 'employee' && subType !== 'machine') ||\n !sized(sub, 1, VISITOR_MAX_STRING_BYTES) ||\n // An employee's access always has a grant; a machine visitor has none.\n typeof grant !== 'string' || (subType === 'employee' ? !sized(grant, 1, VISITOR_MAX_STRING_BYTES) : grant !== '') ||\n !Array.isArray(appRoles) || appRoles.some((role) => !sized(role, 1, VISITOR_MAX_STRING_BYTES)) ||\n (activeRole !== undefined && !sized(activeRole, 1, VISITOR_MAX_STRING_BYTES))) throw fail();\n return Object.freeze({\n subType, subject: sub, grant, workspaceID: ws, appID, runtime,\n appRoles: Object.freeze([...new Set(appRoles as string[])]),\n ...(activeRole === undefined ? {} : { activeRole }),\n });\n}\n"]}