@undefineds.co/xpod 0.3.31 → 0.3.33

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 (218) hide show
  1. package/dist/api/auth/AuthContext.d.ts +3 -2
  2. package/dist/api/auth/AuthContext.js +2 -1
  3. package/dist/api/auth/AuthContext.js.map +1 -1
  4. package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +2 -12
  5. package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -4
  6. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  7. package/dist/api/auth/ServiceTokenAuthenticator.d.ts +2 -2
  8. package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -1
  9. package/dist/api/chatkit/pod-store.d.ts +3 -0
  10. package/dist/api/chatkit/pod-store.js +93 -59
  11. package/dist/api/chatkit/pod-store.js.map +1 -1
  12. package/dist/api/chatkit/schema.d.ts +5 -6
  13. package/dist/api/container/business-token.d.ts +1 -1
  14. package/dist/api/container/business-token.js +5 -1
  15. package/dist/api/container/business-token.js.map +1 -1
  16. package/dist/api/container/common.js +14 -10
  17. package/dist/api/container/common.js.map +1 -1
  18. package/dist/api/container/routes.js +16 -3
  19. package/dist/api/container/routes.js.map +1 -1
  20. package/dist/api/container/types.d.ts +2 -4
  21. package/dist/api/container/types.js.map +1 -1
  22. package/dist/api/handlers/ChatHandler.d.ts +1 -1
  23. package/dist/api/handlers/ChatHandler.js +1 -1
  24. package/dist/api/handlers/ChatHandler.js.map +1 -1
  25. package/dist/api/handlers/EdgeNodeSignalHandler.js +3 -1
  26. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
  27. package/dist/api/handlers/PodManagementHandler.d.ts +2 -0
  28. package/dist/api/handlers/PodManagementHandler.js +114 -12
  29. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  30. package/dist/api/handlers/ProvisionHandler.d.ts +27 -0
  31. package/dist/api/handlers/ProvisionHandler.js +339 -32
  32. package/dist/api/handlers/ProvisionHandler.js.map +1 -1
  33. package/dist/api/handlers/QuotaHandler.js +0 -12
  34. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  35. package/dist/api/handlers/index.d.ts +0 -1
  36. package/dist/api/handlers/index.js +0 -1
  37. package/dist/api/handlers/index.js.map +1 -1
  38. package/dist/api/matrix/PodMatrixStore.js +26 -21
  39. package/dist/api/matrix/PodMatrixStore.js.map +1 -1
  40. package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
  41. package/dist/api/runs/schema.d.ts +5 -7
  42. package/dist/api/runs/store.js +6 -4
  43. package/dist/api/runs/store.js.map +1 -1
  44. package/dist/api/runtime.js +3 -3
  45. package/dist/api/runtime.js.map +1 -1
  46. package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
  47. package/dist/api/tasks/schema.d.ts +17 -13
  48. package/dist/api/tasks/schema.js +7 -2
  49. package/dist/api/tasks/schema.js.map +1 -1
  50. package/dist/api/tasks/store.js +1 -2
  51. package/dist/api/tasks/store.js.map +1 -1
  52. package/dist/components/context.jsonld +12 -0
  53. package/dist/edge/EdgeNodeAgent.d.ts +1 -1
  54. package/dist/edge/EdgeNodeAgent.js +1 -1
  55. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  56. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -0
  57. package/dist/edge/EdgeNodeDnsCoordinator.js +9 -3
  58. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  59. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +4 -0
  60. package/dist/edge/EdgeNodeHealthProbeService.d.ts +3 -0
  61. package/dist/edge/EdgeNodeHealthProbeService.js +22 -2
  62. package/dist/edge/EdgeNodeHealthProbeService.js.map +1 -1
  63. package/dist/edge/EdgeNodeHealthProbeService.jsonld +12 -0
  64. package/dist/http/ClusterIngressRouter.js +6 -3
  65. package/dist/http/ClusterIngressRouter.js.map +1 -1
  66. package/dist/http/ClusterWebSocketConfigurator.js +6 -2
  67. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  68. package/dist/http/EdgeNodeDirectDebugHttpHandler.d.ts +2 -0
  69. package/dist/http/EdgeNodeDirectDebugHttpHandler.js +18 -3
  70. package/dist/http/EdgeNodeDirectDebugHttpHandler.js.map +1 -1
  71. package/dist/http/EdgeNodeDirectDebugHttpHandler.jsonld +8 -0
  72. package/dist/http/EdgeNodeProxyHttpHandler.js +6 -2
  73. package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
  74. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +2 -2
  75. package/dist/http/cluster/PodMigrationHttpHandler.js +2 -2
  76. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  77. package/dist/http/quota/QuotaAdminHttpHandler.js +27 -21
  78. package/dist/http/quota/QuotaAdminHttpHandler.js.map +1 -1
  79. package/dist/http/search/SearchHttpHandler.js +2 -2
  80. package/dist/http/search/SearchHttpHandler.js.map +1 -1
  81. package/dist/identity/drizzle/AccountRepository.d.ts +4 -22
  82. package/dist/identity/drizzle/AccountRepository.js +9 -113
  83. package/dist/identity/drizzle/AccountRepository.js.map +1 -1
  84. package/dist/identity/drizzle/AccountRoleRepository.d.ts +5 -5
  85. package/dist/identity/drizzle/AccountRoleRepository.js +204 -97
  86. package/dist/identity/drizzle/AccountRoleRepository.js.map +1 -1
  87. package/dist/identity/drizzle/DdnsRepository.d.ts +5 -20
  88. package/dist/identity/drizzle/DdnsRepository.js +13 -49
  89. package/dist/identity/drizzle/DdnsRepository.js.map +1 -1
  90. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +13 -6
  91. package/dist/identity/drizzle/EdgeNodeRepository.js +167 -66
  92. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  93. package/dist/identity/drizzle/PodLookupRepository.d.ts +7 -36
  94. package/dist/identity/drizzle/PodLookupRepository.js +103 -126
  95. package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
  96. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +13 -1
  97. package/dist/identity/drizzle/ServiceTokenRepository.js +7 -0
  98. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
  99. package/dist/identity/drizzle/db.d.ts +2 -1
  100. package/dist/identity/drizzle/db.js +173 -297
  101. package/dist/identity/drizzle/db.js.map +1 -1
  102. package/dist/identity/drizzle/schema.pg.d.ts +3 -11
  103. package/dist/identity/drizzle/schema.pg.js +10 -45
  104. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  105. package/dist/identity/drizzle/schema.sqlite.d.ts +88 -531
  106. package/dist/identity/drizzle/schema.sqlite.js +13 -46
  107. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  108. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +3 -0
  109. package/dist/identity/oidc/ScopedPickWebIdHandler.js +18 -6
  110. package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -1
  111. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +22 -0
  112. package/dist/provision/ProvisionCodeCodec.js +10 -1
  113. package/dist/provision/ProvisionCodeCodec.js.map +1 -1
  114. package/dist/provision/ProvisionPodCreator.d.ts +8 -2
  115. package/dist/provision/ProvisionPodCreator.js +134 -41
  116. package/dist/provision/ProvisionPodCreator.js.map +1 -1
  117. package/dist/provision/ProvisionPodCreator.jsonld +38 -3
  118. package/dist/quota/DrizzleQuotaService.d.ts +0 -4
  119. package/dist/quota/DrizzleQuotaService.js +1 -21
  120. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  121. package/dist/quota/DrizzleQuotaService.jsonld +0 -16
  122. package/dist/quota/NoopQuotaService.d.ts +0 -4
  123. package/dist/quota/NoopQuotaService.js +0 -8
  124. package/dist/quota/NoopQuotaService.js.map +1 -1
  125. package/dist/quota/NoopQuotaService.jsonld +0 -16
  126. package/dist/quota/QuotaService.d.ts +0 -4
  127. package/dist/quota/QuotaService.js.map +1 -1
  128. package/dist/quota/QuotaService.jsonld +0 -16
  129. package/dist/service/EdgeNodeSignalClient.d.ts +0 -2
  130. package/dist/service/EdgeNodeSignalClient.js +0 -4
  131. package/dist/service/EdgeNodeSignalClient.js.map +1 -1
  132. package/dist/service/PodMigrationService.d.ts +2 -2
  133. package/dist/service/PodMigrationService.js +4 -4
  134. package/dist/service/PodMigrationService.js.map +1 -1
  135. package/dist/setup/LocalSetupServiceTokenRepository.d.ts +22 -0
  136. package/dist/setup/LocalSetupServiceTokenRepository.js +68 -0
  137. package/dist/setup/LocalSetupServiceTokenRepository.js.map +1 -0
  138. package/dist/storage/quota/PerAccountQuotaStrategy.js +2 -2
  139. package/dist/storage/quota/PerAccountQuotaStrategy.js.map +1 -1
  140. package/dist/storage/quota/UsageRepository.d.ts +10 -32
  141. package/dist/storage/quota/UsageRepository.js +84 -281
  142. package/dist/storage/quota/UsageRepository.js.map +1 -1
  143. package/dist/storage/vector/VectorIndexingListener.js +2 -2
  144. package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
  145. package/dist/subdomain/SubdomainService.d.ts +1 -1
  146. package/dist/subdomain/SubdomainService.js +1 -1
  147. package/dist/subdomain/SubdomainService.js.map +1 -1
  148. package/dist/subdomain/SubdomainService.jsonld +1 -1
  149. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts +21 -0
  150. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts.map +1 -0
  151. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js +85 -0
  152. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js.map +1 -0
  153. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts +10 -0
  154. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts.map +1 -0
  155. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js +365 -0
  156. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js.map +1 -0
  157. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts +1 -0
  158. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts.map +1 -1
  159. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js +3 -1
  160. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js.map +1 -1
  161. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.d.ts.map +1 -1
  162. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js +5 -1
  163. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js.map +1 -1
  164. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts +2 -0
  165. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts.map +1 -1
  166. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js +2 -1
  167. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js.map +1 -1
  168. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts +18 -0
  169. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts.map +1 -1
  170. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js +234 -10
  171. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js.map +1 -1
  172. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts +13 -0
  173. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts.map +1 -1
  174. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js +19 -0
  175. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js.map +1 -1
  176. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts +21 -0
  177. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts.map +1 -0
  178. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js +78 -0
  179. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js.map +1 -0
  180. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts +10 -0
  181. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts.map +1 -0
  182. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js +362 -0
  183. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js.map +1 -0
  184. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts +1 -0
  185. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts.map +1 -1
  186. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js +1 -0
  187. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js.map +1 -1
  188. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.d.ts.map +1 -1
  189. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js +5 -1
  190. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js.map +1 -1
  191. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts +2 -0
  192. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts.map +1 -1
  193. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js +1 -0
  194. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js.map +1 -1
  195. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts +18 -0
  196. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts.map +1 -1
  197. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js +225 -10
  198. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js.map +1 -1
  199. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts +13 -0
  200. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts.map +1 -1
  201. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js +19 -0
  202. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js.map +1 -1
  203. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts +5 -4
  204. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts.map +1 -1
  205. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js +4 -3
  206. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js.map +1 -1
  207. package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts +5 -4
  208. package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts.map +1 -1
  209. package/node_modules/@undefineds.co/drizzle-solid/dist/index.js +20 -3
  210. package/node_modules/@undefineds.co/drizzle-solid/dist/index.js.map +1 -1
  211. package/node_modules/@undefineds.co/drizzle-solid/package.json +1 -1
  212. package/package.json +3 -3
  213. package/dist/api/handlers/ApiKeyHandler.d.ts +0 -15
  214. package/dist/api/handlers/ApiKeyHandler.js +0 -153
  215. package/dist/api/handlers/ApiKeyHandler.js.map +0 -1
  216. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +0 -51
  217. package/dist/api/store/DrizzleClientCredentialsStore.js +0 -115
  218. package/dist/api/store/DrizzleClientCredentialsStore.js.map +0 -1
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Authenticated caller context.
5
5
  * - Solid Token: user provides Bearer or DPoP token
6
- * - API Key: third-party provides client_id, API Server exchanges for token
6
+ * - CSS client credentials: third-party provides client_id/client_secret,
7
+ * API Server exchanges them for a Solid token
7
8
  * - Node Token: edge node provides node API key
8
9
  */
9
10
  export interface SolidAuthContext {
@@ -16,7 +17,7 @@ export interface SolidAuthContext {
16
17
  accessToken?: string;
17
18
  tokenType?: 'Bearer' | 'DPoP';
18
19
  dpopProof?: string;
19
- /** Whether this was authenticated via API Key (client credentials) */
20
+ /** Whether this was authenticated via the sk-* client credentials wrapper */
20
21
  viaApiKey?: boolean;
21
22
  }
22
23
  export interface NodeAuthContext {
@@ -4,7 +4,8 @@
4
4
  *
5
5
  * Authenticated caller context.
6
6
  * - Solid Token: user provides Bearer or DPoP token
7
- * - API Key: third-party provides client_id, API Server exchanges for token
7
+ * - CSS client credentials: third-party provides client_id/client_secret,
8
+ * API Server exchanges them for a Solid token
8
9
  * - Node Token: edge node provides node API key
9
10
  */
10
11
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +1 @@
1
- {"version":3,"file":"AuthContext.js","sourceRoot":"","sources":["../../../src/api/auth/AuthContext.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AA+BH,kCAEC;AAED,gCAEC;AAKD,4BAEC;AAKD,wCAEC;AAKD,oCAQC;AAED,8BAEC;AAED,sCAEC;AAKD,4BAEC;AAhDD,SAAgB,WAAW,CAAC,GAAgB;IAC1C,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC;AAC9B,CAAC;AAED,SAAgB,UAAU,CAAC,GAAgB;IACzC,OAAO,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,GAAgB;IACvC,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,GAAgB;IAC7C,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,GAAgB;IAC3C,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,SAAS,CAAC;IACvB,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACxB,OAAO,GAAG,CAAC,SAAS,CAAC;IACvB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,SAAS,CAAC,GAAgB;IACxC,OAAO,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC;AAED,SAAgB,aAAa,CAAC,GAAgB;IAC5C,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,GAAgB,EAAE,KAAa;IACtD,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["/**\n * Authentication context representing the authenticated caller\n * \n * Authenticated caller context.\n * - Solid Token: user provides Bearer or DPoP token\n * - API Key: third-party provides client_id, API Server exchanges for token\n * - Node Token: edge node provides node API key\n */\n\nexport interface SolidAuthContext {\n type: 'solid';\n webId: string;\n accountId?: string;\n clientId?: string;\n clientSecret?: string; // For client credentials auth\n displayName?: string;\n accessToken?: string;\n tokenType?: 'Bearer' | 'DPoP';\n dpopProof?: string;\n /** Whether this was authenticated via API Key (client credentials) */\n viaApiKey?: boolean;\n}\n\nexport interface NodeAuthContext {\n type: 'node';\n nodeId: string;\n accountId?: string;\n}\n\nexport interface ServiceAuthContext {\n type: 'service';\n serviceType: 'local' | 'business' | 'cloud' | 'compute';\n serviceId: string;\n scopes: string[];\n}\n\nexport type AuthContext = SolidAuthContext | NodeAuthContext | ServiceAuthContext;\n\nexport function isSolidAuth(ctx: AuthContext): ctx is SolidAuthContext {\n return ctx.type === 'solid';\n}\n\nexport function isNodeAuth(ctx: AuthContext): ctx is NodeAuthContext {\n return ctx.type === 'node';\n}\n\n/**\n * Get webId from auth context\n */\nexport function getWebId(ctx: AuthContext): string | undefined {\n return ctx.type === 'solid' ? ctx.webId : undefined;\n}\n\n/**\n * Get display name from auth context\n */\nexport function getDisplayName(ctx: AuthContext): string | undefined {\n return ctx.type === 'solid' ? ctx.displayName : undefined;\n}\n\n/**\n * Get accountId from auth context (if available)\n */\nexport function getAccountId(ctx: AuthContext): string | undefined {\n if (ctx.type === 'solid') {\n return ctx.accountId;\n }\n if (ctx.type === 'node') {\n return ctx.accountId;\n }\n return undefined;\n}\n\nexport function getNodeId(ctx: AuthContext): string | undefined {\n return ctx.type === 'node' ? ctx.nodeId : undefined;\n}\n\nexport function isServiceAuth(ctx: AuthContext): ctx is ServiceAuthContext {\n return ctx.type === 'service';\n}\n\n/**\n * Check if a service auth context has the required scope\n */\nexport function hasScope(ctx: AuthContext, scope: string): boolean {\n return ctx.type === 'service' && ctx.scopes.includes(scope);\n}\n"]}
1
+ {"version":3,"file":"AuthContext.js","sourceRoot":"","sources":["../../../src/api/auth/AuthContext.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AA+BH,kCAEC;AAED,gCAEC;AAKD,4BAEC;AAKD,wCAEC;AAKD,oCAQC;AAED,8BAEC;AAED,sCAEC;AAKD,4BAEC;AAhDD,SAAgB,WAAW,CAAC,GAAgB;IAC1C,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC;AAC9B,CAAC;AAED,SAAgB,UAAU,CAAC,GAAgB;IACzC,OAAO,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,GAAgB;IACvC,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,GAAgB;IAC7C,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,GAAgB;IAC3C,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,SAAS,CAAC;IACvB,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACxB,OAAO,GAAG,CAAC,SAAS,CAAC;IACvB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,SAAS,CAAC,GAAgB;IACxC,OAAO,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC;AAED,SAAgB,aAAa,CAAC,GAAgB;IAC5C,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,GAAgB,EAAE,KAAa;IACtD,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["/**\n * Authentication context representing the authenticated caller\n * \n * Authenticated caller context.\n * - Solid Token: user provides Bearer or DPoP token\n * - CSS client credentials: third-party provides client_id/client_secret,\n * API Server exchanges them for a Solid token\n * - Node Token: edge node provides node API key\n */\n\nexport interface SolidAuthContext {\n type: 'solid';\n webId: string;\n accountId?: string;\n clientId?: string;\n clientSecret?: string; // For client credentials auth\n displayName?: string;\n accessToken?: string;\n tokenType?: 'Bearer' | 'DPoP';\n dpopProof?: string;\n /** Whether this was authenticated via the sk-* client credentials wrapper */\n viaApiKey?: boolean;\n}\n\nexport interface NodeAuthContext {\n type: 'node';\n nodeId: string;\n accountId?: string;\n}\n\nexport interface ServiceAuthContext {\n type: 'service';\n serviceType: 'local' | 'business' | 'cloud' | 'compute';\n serviceId: string;\n scopes: string[];\n}\n\nexport type AuthContext = SolidAuthContext | NodeAuthContext | ServiceAuthContext;\n\nexport function isSolidAuth(ctx: AuthContext): ctx is SolidAuthContext {\n return ctx.type === 'solid';\n}\n\nexport function isNodeAuth(ctx: AuthContext): ctx is NodeAuthContext {\n return ctx.type === 'node';\n}\n\n/**\n * Get webId from auth context\n */\nexport function getWebId(ctx: AuthContext): string | undefined {\n return ctx.type === 'solid' ? ctx.webId : undefined;\n}\n\n/**\n * Get display name from auth context\n */\nexport function getDisplayName(ctx: AuthContext): string | undefined {\n return ctx.type === 'solid' ? ctx.displayName : undefined;\n}\n\n/**\n * Get accountId from auth context (if available)\n */\nexport function getAccountId(ctx: AuthContext): string | undefined {\n if (ctx.type === 'solid') {\n return ctx.accountId;\n }\n if (ctx.type === 'node') {\n return ctx.accountId;\n }\n return undefined;\n}\n\nexport function getNodeId(ctx: AuthContext): string | undefined {\n return ctx.type === 'node' ? ctx.nodeId : undefined;\n}\n\nexport function isServiceAuth(ctx: AuthContext): ctx is ServiceAuthContext {\n return ctx.type === 'service';\n}\n\n/**\n * Check if a service auth context has the required scope\n */\nexport function hasScope(ctx: AuthContext, scope: string): boolean {\n return ctx.type === 'service' && ctx.scopes.includes(scope);\n}\n"]}
@@ -20,12 +20,12 @@ export interface ClientCredentialsAuthenticatorOptions {
20
20
  tokenEndpoint: string;
21
21
  }
22
22
  /**
23
- * Authenticator for API Keys in sk-xxx format.
23
+ * Authenticator for CSS client credentials in sk-xxx transport format.
24
24
  *
25
25
  * Format: sk-base64(client_id:client_secret)
26
26
  *
27
27
  * This authenticator:
28
- * 1. Decodes the API Key to get client_id and client_secret
28
+ * 1. Decodes the transport token to get client_id and client_secret
29
29
  * 2. Exchanges them for a Solid Token via CSS token endpoint
30
30
  * 3. Extracts webId from the token response
31
31
  * 4. Returns a SolidAuthContext
@@ -44,13 +44,3 @@ export declare class ClientCredentialsAuthenticator implements Authenticator {
44
44
  private extractWebIdFromJwt;
45
45
  private isJwt;
46
46
  }
47
- export interface ClientCredentialsRecord {
48
- clientId: string;
49
- webId: string;
50
- accountId: string;
51
- displayName?: string;
52
- createdAt: Date;
53
- }
54
- export interface ClientCredentialsStore {
55
- findByClientId(clientId: string): Promise<ClientCredentialsRecord | undefined>;
56
- }
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ClientCredentialsAuthenticator = void 0;
4
4
  const global_logger_factory_1 = require("global-logger-factory");
5
5
  /**
6
- * Authenticator for API Keys in sk-xxx format.
6
+ * Authenticator for CSS client credentials in sk-xxx transport format.
7
7
  *
8
8
  * Format: sk-base64(client_id:client_secret)
9
9
  *
10
10
  * This authenticator:
11
- * 1. Decodes the API Key to get client_id and client_secret
11
+ * 1. Decodes the transport token to get client_id and client_secret
12
12
  * 2. Exchanges them for a Solid Token via CSS token endpoint
13
13
  * 3. Extracts webId from the token response
14
14
  * 4. Returns a SolidAuthContext
@@ -24,7 +24,7 @@ class ClientCredentialsAuthenticator {
24
24
  if (!auth?.startsWith('Bearer ')) {
25
25
  return false;
26
26
  }
27
- // If there's a DPoP header, it's a Solid Token, not an API Key
27
+ // If there's a DPoP header, it's a Solid Token, not a client credentials wrapper
28
28
  if (request.headers.dpop) {
29
29
  return false;
30
30
  }
@@ -67,7 +67,7 @@ class ClientCredentialsAuthenticator {
67
67
  }
68
68
  }
69
69
  else {
70
- // Non sk- format not supported without database lookup
70
+ // Non sk- format is intentionally unsupported; Xpod does not keep an API key mirror table.
71
71
  return { success: false, error: 'Invalid API Key format: must start with sk-' };
72
72
  }
73
73
  // Check cache first
@@ -1 +1 @@
1
- {"version":3,"file":"ClientCredentialsAuthenticator.js","sourceRoot":"","sources":["../../../src/api/auth/ClientCredentialsAuthenticator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { Authenticator, AuthResult } from './Authenticator';\nimport type { SolidAuthContext } from './AuthContext';\n\n/**\n * Interface for token cache\n */\nexport interface TokenCache {\n get(clientId: string): Promise<{\n token: string;\n tokenType?: 'Bearer' | 'DPoP';\n webId: string;\n expiresAt: Date;\n } | undefined>;\n set(\n clientId: string,\n token: string,\n webId: string,\n expiresAt: Date,\n tokenType?: 'Bearer' | 'DPoP',\n ): Promise<void>;\n}\n\nexport interface ClientCredentialsAuthenticatorOptions {\n tokenCache?: TokenCache;\n /**\n * CSS token endpoint URL\n */\n tokenEndpoint: string;\n}\n\n/**\n * Authenticator for API Keys in sk-xxx format.\n * \n * Format: sk-base64(client_id:client_secret)\n * \n * This authenticator:\n * 1. Decodes the API Key to get client_id and client_secret\n * 2. Exchanges them for a Solid Token via CSS token endpoint\n * 3. Extracts webId from the token response\n * 4. Returns a SolidAuthContext\n */\nexport class ClientCredentialsAuthenticator implements Authenticator {\n private readonly logger = getLoggerFor(this);\n private readonly tokenCache?: TokenCache;\n private readonly tokenEndpoint: string;\n\n public constructor(options: ClientCredentialsAuthenticatorOptions) {\n this.tokenCache = options.tokenCache;\n this.tokenEndpoint = options.tokenEndpoint;\n }\n\n public canAuthenticate(request: IncomingMessage): boolean {\n const auth = request.headers.authorization;\n if (!auth?.startsWith('Bearer ')) {\n return false;\n }\n // If there's a DPoP header, it's a Solid Token, not an API Key\n if (request.headers.dpop) {\n return false;\n }\n const token = auth.slice(7).trim();\n if (!token) {\n return false;\n }\n // Only handle sk-xxx format or non-JWT tokens\n return token.startsWith('sk-') || !this.isJwt(token);\n }\n\n public async authenticate(request: IncomingMessage): Promise<AuthResult> {\n const authorization = request.headers.authorization;\n if (!authorization?.startsWith('Bearer ')) {\n return { success: false, error: 'Missing Bearer token' };\n }\n\n const token = authorization.slice(7).trim();\n if (!token) {\n return { success: false, error: 'Empty API Key' };\n }\n\n try {\n let clientId: string;\n let clientSecret: string;\n\n // Parse sk-xxx format (base64 encoded client_id:client_secret)\n if (token.startsWith('sk-')) {\n const base64 = token.slice(3);\n try {\n const decoded = Buffer.from(base64, 'base64').toString('utf-8');\n const colonIndex = decoded.indexOf(':');\n if (colonIndex === -1) {\n return { success: false, error: 'Invalid API Key format: missing colon separator' };\n }\n clientId = decoded.slice(0, colonIndex);\n clientSecret = decoded.slice(colonIndex + 1);\n \n if (!clientId || !clientSecret) {\n return { success: false, error: 'Invalid API Key format: empty client_id or client_secret' };\n }\n } catch {\n return { success: false, error: 'Invalid API Key encoding' };\n }\n } else {\n // Non sk- format not supported without database lookup\n return { success: false, error: 'Invalid API Key format: must start with sk-' };\n }\n\n // Check cache first\n if (this.tokenCache) {\n const cached = await this.tokenCache.get(clientId);\n if (cached && cached.expiresAt > new Date()) {\n this.logger.debug(`Using cached token for ${clientId.slice(0, 8)}...`);\n return {\n success: true,\n context: {\n type: 'solid',\n webId: cached.webId,\n accountId: cached.webId,\n clientId,\n clientSecret,\n accessToken: cached.token,\n tokenType: cached.tokenType ?? 'Bearer',\n viaApiKey: true,\n },\n };\n }\n }\n\n // Exchange for token at CSS endpoint\n this.logger.debug(`Exchanging client credentials at ${this.tokenEndpoint}`);\n const tokenResult = await this.exchangeForToken(clientId, clientSecret);\n this.logger.debug(`Token exchange result: success=${tokenResult.success}, webId=${tokenResult.webId}, error=${tokenResult.error}`);\n \n if (!tokenResult.success || !tokenResult.webId || !tokenResult.token) {\n return { success: false, error: tokenResult.error || 'Token exchange failed' };\n }\n\n // Cache the token\n if (this.tokenCache && tokenResult.expiresAt) {\n await this.tokenCache.set(\n clientId,\n tokenResult.token!,\n tokenResult.webId,\n tokenResult.expiresAt,\n tokenResult.tokenType,\n );\n }\n\n const context: SolidAuthContext = {\n type: 'solid',\n webId: tokenResult.webId,\n accountId: tokenResult.webId,\n clientId,\n clientSecret,\n accessToken: tokenResult.token,\n tokenType: tokenResult.tokenType ?? 'Bearer',\n viaApiKey: true,\n };\n\n this.logger.debug(`Authenticated API Key for webId: ${tokenResult.webId}`);\n return { success: true, context };\n } catch (error) {\n this.logger.error(`API Key authentication error: ${error}`);\n return { success: false, error: 'Authentication failed' };\n }\n }\n\n private async exchangeForToken(clientId: string, clientSecret: string): Promise<{\n success: boolean;\n token?: string;\n tokenType?: 'Bearer' | 'DPoP';\n webId?: string;\n expiresAt?: Date;\n error?: string;\n }> {\n // 开发模式:跳过 CSS token exchange\n if (process.env.NODE_ENV === 'development') {\n this.logger.warn(`[DEV] Skipping token exchange for ${clientId.slice(0, 8)}...`);\n return {\n success: true,\n token: `dev-token-${clientId}`,\n expiresAt: new Date(Date.now() + 3600000),\n };\n }\n\n try {\n const response = await fetch(this.tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: clientId,\n client_secret: clientSecret,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n this.logger.warn(`Token exchange failed: ${response.status} ${error}`);\n return { success: false, error: `Token exchange failed: ${response.status}` };\n }\n\n const data = await response.json() as {\n access_token: string;\n expires_in?: number;\n token_type: string;\n webid?: string; // CSS returns webid in response\n };\n\n // Extract webId from token response or decode from JWT\n let webId = data.webid;\n if (!webId && data.access_token) {\n webId = this.extractWebIdFromJwt(data.access_token);\n }\n\n if (!webId) {\n return { success: false, error: 'Could not determine webId from token response' };\n }\n\n const expiresAt = data.expires_in\n ? new Date(Date.now() + data.expires_in * 1000 - 60000) // 1 min buffer\n : new Date(Date.now() + 3600000); // Default 1 hour\n\n return {\n success: true,\n token: data.access_token,\n tokenType: data.token_type?.toUpperCase() === 'DPOP' ? 'DPoP' : 'Bearer',\n webId,\n expiresAt,\n };\n } catch (error) {\n this.logger.error(`Token exchange error: ${error}`);\n return { success: false, error: 'Token exchange failed' };\n }\n }\n\n /**\n * Extract webId from JWT access token\n */\n private extractWebIdFromJwt(jwt: string): string | undefined {\n try {\n const parts = jwt.split('.');\n if (parts.length !== 3) {\n return undefined;\n }\n const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString('utf-8'));\n return payload.webid || payload.webId || payload.sub;\n } catch {\n return undefined;\n }\n }\n\n private isJwt(token: string): boolean {\n return /^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(token);\n }\n}\n\n// Re-export for backwards compatibility (these are no longer needed but keep for other code)\nexport interface ClientCredentialsRecord {\n clientId: string;\n webId: string;\n accountId: string;\n displayName?: string;\n createdAt: Date;\n}\n\nexport interface ClientCredentialsStore {\n findByClientId(clientId: string): Promise<ClientCredentialsRecord | undefined>;\n}\n"]}
1
+ {"version":3,"file":"ClientCredentialsAuthenticator.js","sourceRoot":"","sources":["../../../src/api/auth/ClientCredentialsAuthenticator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { Authenticator, AuthResult } from './Authenticator';\nimport type { SolidAuthContext } from './AuthContext';\n\n/**\n * Interface for token cache\n */\nexport interface TokenCache {\n get(clientId: string): Promise<{\n token: string;\n tokenType?: 'Bearer' | 'DPoP';\n webId: string;\n expiresAt: Date;\n } | undefined>;\n set(\n clientId: string,\n token: string,\n webId: string,\n expiresAt: Date,\n tokenType?: 'Bearer' | 'DPoP',\n ): Promise<void>;\n}\n\nexport interface ClientCredentialsAuthenticatorOptions {\n tokenCache?: TokenCache;\n /**\n * CSS token endpoint URL\n */\n tokenEndpoint: string;\n}\n\n/**\n * Authenticator for CSS client credentials in sk-xxx transport format.\n * \n * Format: sk-base64(client_id:client_secret)\n * \n * This authenticator:\n * 1. Decodes the transport token to get client_id and client_secret\n * 2. Exchanges them for a Solid Token via CSS token endpoint\n * 3. Extracts webId from the token response\n * 4. Returns a SolidAuthContext\n */\nexport class ClientCredentialsAuthenticator implements Authenticator {\n private readonly logger = getLoggerFor(this);\n private readonly tokenCache?: TokenCache;\n private readonly tokenEndpoint: string;\n\n public constructor(options: ClientCredentialsAuthenticatorOptions) {\n this.tokenCache = options.tokenCache;\n this.tokenEndpoint = options.tokenEndpoint;\n }\n\n public canAuthenticate(request: IncomingMessage): boolean {\n const auth = request.headers.authorization;\n if (!auth?.startsWith('Bearer ')) {\n return false;\n }\n // If there's a DPoP header, it's a Solid Token, not a client credentials wrapper\n if (request.headers.dpop) {\n return false;\n }\n const token = auth.slice(7).trim();\n if (!token) {\n return false;\n }\n // Only handle sk-xxx format or non-JWT tokens\n return token.startsWith('sk-') || !this.isJwt(token);\n }\n\n public async authenticate(request: IncomingMessage): Promise<AuthResult> {\n const authorization = request.headers.authorization;\n if (!authorization?.startsWith('Bearer ')) {\n return { success: false, error: 'Missing Bearer token' };\n }\n\n const token = authorization.slice(7).trim();\n if (!token) {\n return { success: false, error: 'Empty API Key' };\n }\n\n try {\n let clientId: string;\n let clientSecret: string;\n\n // Parse sk-xxx format (base64 encoded client_id:client_secret)\n if (token.startsWith('sk-')) {\n const base64 = token.slice(3);\n try {\n const decoded = Buffer.from(base64, 'base64').toString('utf-8');\n const colonIndex = decoded.indexOf(':');\n if (colonIndex === -1) {\n return { success: false, error: 'Invalid API Key format: missing colon separator' };\n }\n clientId = decoded.slice(0, colonIndex);\n clientSecret = decoded.slice(colonIndex + 1);\n \n if (!clientId || !clientSecret) {\n return { success: false, error: 'Invalid API Key format: empty client_id or client_secret' };\n }\n } catch {\n return { success: false, error: 'Invalid API Key encoding' };\n }\n } else {\n // Non sk- format is intentionally unsupported; Xpod does not keep an API key mirror table.\n return { success: false, error: 'Invalid API Key format: must start with sk-' };\n }\n\n // Check cache first\n if (this.tokenCache) {\n const cached = await this.tokenCache.get(clientId);\n if (cached && cached.expiresAt > new Date()) {\n this.logger.debug(`Using cached token for ${clientId.slice(0, 8)}...`);\n return {\n success: true,\n context: {\n type: 'solid',\n webId: cached.webId,\n accountId: cached.webId,\n clientId,\n clientSecret,\n accessToken: cached.token,\n tokenType: cached.tokenType ?? 'Bearer',\n viaApiKey: true,\n },\n };\n }\n }\n\n // Exchange for token at CSS endpoint\n this.logger.debug(`Exchanging client credentials at ${this.tokenEndpoint}`);\n const tokenResult = await this.exchangeForToken(clientId, clientSecret);\n this.logger.debug(`Token exchange result: success=${tokenResult.success}, webId=${tokenResult.webId}, error=${tokenResult.error}`);\n \n if (!tokenResult.success || !tokenResult.webId || !tokenResult.token) {\n return { success: false, error: tokenResult.error || 'Token exchange failed' };\n }\n\n // Cache the token\n if (this.tokenCache && tokenResult.expiresAt) {\n await this.tokenCache.set(\n clientId,\n tokenResult.token!,\n tokenResult.webId,\n tokenResult.expiresAt,\n tokenResult.tokenType,\n );\n }\n\n const context: SolidAuthContext = {\n type: 'solid',\n webId: tokenResult.webId,\n accountId: tokenResult.webId,\n clientId,\n clientSecret,\n accessToken: tokenResult.token,\n tokenType: tokenResult.tokenType ?? 'Bearer',\n viaApiKey: true,\n };\n\n this.logger.debug(`Authenticated API Key for webId: ${tokenResult.webId}`);\n return { success: true, context };\n } catch (error) {\n this.logger.error(`API Key authentication error: ${error}`);\n return { success: false, error: 'Authentication failed' };\n }\n }\n\n private async exchangeForToken(clientId: string, clientSecret: string): Promise<{\n success: boolean;\n token?: string;\n tokenType?: 'Bearer' | 'DPoP';\n webId?: string;\n expiresAt?: Date;\n error?: string;\n }> {\n // 开发模式:跳过 CSS token exchange\n if (process.env.NODE_ENV === 'development') {\n this.logger.warn(`[DEV] Skipping token exchange for ${clientId.slice(0, 8)}...`);\n return {\n success: true,\n token: `dev-token-${clientId}`,\n expiresAt: new Date(Date.now() + 3600000),\n };\n }\n\n try {\n const response = await fetch(this.tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: clientId,\n client_secret: clientSecret,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n this.logger.warn(`Token exchange failed: ${response.status} ${error}`);\n return { success: false, error: `Token exchange failed: ${response.status}` };\n }\n\n const data = await response.json() as {\n access_token: string;\n expires_in?: number;\n token_type: string;\n webid?: string; // CSS returns webid in response\n };\n\n // Extract webId from token response or decode from JWT\n let webId = data.webid;\n if (!webId && data.access_token) {\n webId = this.extractWebIdFromJwt(data.access_token);\n }\n\n if (!webId) {\n return { success: false, error: 'Could not determine webId from token response' };\n }\n\n const expiresAt = data.expires_in\n ? new Date(Date.now() + data.expires_in * 1000 - 60000) // 1 min buffer\n : new Date(Date.now() + 3600000); // Default 1 hour\n\n return {\n success: true,\n token: data.access_token,\n tokenType: data.token_type?.toUpperCase() === 'DPOP' ? 'DPoP' : 'Bearer',\n webId,\n expiresAt,\n };\n } catch (error) {\n this.logger.error(`Token exchange error: ${error}`);\n return { success: false, error: 'Token exchange failed' };\n }\n }\n\n /**\n * Extract webId from JWT access token\n */\n private extractWebIdFromJwt(jwt: string): string | undefined {\n try {\n const parts = jwt.split('.');\n if (parts.length !== 3) {\n return undefined;\n }\n const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString('utf-8'));\n return payload.webid || payload.webId || payload.sub;\n } catch {\n return undefined;\n }\n }\n\n private isJwt(token: string): boolean {\n return /^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(token);\n }\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  import type { IncomingMessage } from 'node:http';
2
2
  import type { Authenticator, AuthResult } from './Authenticator';
3
- import type { ServiceTokenRepository } from '../../identity/drizzle/ServiceTokenRepository';
3
+ import type { ServiceTokenRepositoryPort } from '../../identity/drizzle/ServiceTokenRepository';
4
4
  export interface ServiceTokenAuthenticatorOptions {
5
- repository: ServiceTokenRepository;
5
+ repository: ServiceTokenRepositoryPort;
6
6
  }
7
7
  /**
8
8
  * Authenticator for service tokens (Business, Local SP, Cloud, Compute).
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceTokenAuthenticator.js","sourceRoot":"","sources":["../../../src/api/auth/ServiceTokenAuthenticator.ts"],"names":[],"mappings":";;;AACA,iEAAqD;AAQrD;;;;GAIG;AACH,MAAa,yBAAyB;IAIpC,YAAmB,OAAyC;QAH3C,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAI3C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;IACjC,CAAC;IAEM,eAAe,CAAC,OAAwB;QAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QAC3C,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,mCAAmC;QACnC,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,YAAY,CAAC,OAAwB;QAChD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,aAAc,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;YAC5D,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YAEtF,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,KAAK,EAAE,CAAC,CAAC;YACnE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;QACpE,CAAC;IACH,CAAC;CACF;AA5CD,8DA4CC","sourcesContent":["import type { IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { Authenticator, AuthResult } from './Authenticator';\nimport type { ServiceTokenRepository } from '../../identity/drizzle/ServiceTokenRepository';\n\nexport interface ServiceTokenAuthenticatorOptions {\n repository: ServiceTokenRepository;\n}\n\n/**\n * Authenticator for service tokens (Business, Local SP, Cloud, Compute).\n *\n * Format: Bearer svc-xxx\n */\nexport class ServiceTokenAuthenticator implements Authenticator {\n private readonly logger = getLoggerFor(this);\n private readonly repo: ServiceTokenRepository;\n\n public constructor(options: ServiceTokenAuthenticatorOptions) {\n this.repo = options.repository;\n }\n\n public canAuthenticate(request: IncomingMessage): boolean {\n const auth = request.headers.authorization;\n if (!auth?.startsWith('Bearer ')) {\n return false;\n }\n const token = auth.slice(7).trim();\n // Service tokens start with 'svc-'\n return token.startsWith('svc-');\n }\n\n public async authenticate(request: IncomingMessage): Promise<AuthResult> {\n const auth = request.headers.authorization!;\n const token = auth.slice(7).trim();\n\n try {\n const record = await this.repo.verifyToken(token);\n if (!record) {\n return { success: false, error: 'Invalid service token' };\n }\n\n this.logger.debug(`Authenticated service: ${record.serviceType}:${record.serviceId}`);\n\n return {\n success: true,\n context: {\n type: 'service',\n serviceType: record.serviceType,\n serviceId: record.serviceId,\n scopes: record.scopes,\n },\n };\n } catch (error) {\n this.logger.error(`Service token authentication failed: ${error}`);\n return { success: false, error: 'Internal authentication error' };\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ServiceTokenAuthenticator.js","sourceRoot":"","sources":["../../../src/api/auth/ServiceTokenAuthenticator.ts"],"names":[],"mappings":";;;AACA,iEAAqD;AAQrD;;;;GAIG;AACH,MAAa,yBAAyB;IAIpC,YAAmB,OAAyC;QAH3C,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAI3C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;IACjC,CAAC;IAEM,eAAe,CAAC,OAAwB;QAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QAC3C,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,mCAAmC;QACnC,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,YAAY,CAAC,OAAwB;QAChD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,aAAc,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;YAC5D,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YAEtF,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,KAAK,EAAE,CAAC,CAAC;YACnE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;QACpE,CAAC;IACH,CAAC;CACF;AA5CD,8DA4CC","sourcesContent":["import type { IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { Authenticator, AuthResult } from './Authenticator';\nimport type { ServiceTokenRepositoryPort } from '../../identity/drizzle/ServiceTokenRepository';\n\nexport interface ServiceTokenAuthenticatorOptions {\n repository: ServiceTokenRepositoryPort;\n}\n\n/**\n * Authenticator for service tokens (Business, Local SP, Cloud, Compute).\n *\n * Format: Bearer svc-xxx\n */\nexport class ServiceTokenAuthenticator implements Authenticator {\n private readonly logger = getLoggerFor(this);\n private readonly repo: ServiceTokenRepositoryPort;\n\n public constructor(options: ServiceTokenAuthenticatorOptions) {\n this.repo = options.repository;\n }\n\n public canAuthenticate(request: IncomingMessage): boolean {\n const auth = request.headers.authorization;\n if (!auth?.startsWith('Bearer ')) {\n return false;\n }\n const token = auth.slice(7).trim();\n // Service tokens start with 'svc-'\n return token.startsWith('svc-');\n }\n\n public async authenticate(request: IncomingMessage): Promise<AuthResult> {\n const auth = request.headers.authorization!;\n const token = auth.slice(7).trim();\n\n try {\n const record = await this.repo.verifyToken(token);\n if (!record) {\n return { success: false, error: 'Invalid service token' };\n }\n\n this.logger.debug(`Authenticated service: ${record.serviceType}:${record.serviceId}`);\n\n return {\n success: true,\n context: {\n type: 'service',\n serviceType: record.serviceType,\n serviceId: record.serviceId,\n scopes: record.scopes,\n },\n };\n } catch (error) {\n this.logger.error(`Service token authentication failed: ${error}`);\n return { success: false, error: 'Internal authentication error' };\n }\n }\n}\n"]}
@@ -61,6 +61,9 @@ export declare class PodChatKitStore implements ChatKitStore<StoreContext>, RunS
61
61
  private isoToTimestamp;
62
62
  private parseJsonObject;
63
63
  private jsonObjectOrNull;
64
+ private getXpodMetadata;
65
+ private withXpodMetadata;
66
+ private withoutXpodMetadata;
64
67
  private withTaskAuthBindingMetadata;
65
68
  private parseTaskAuthBinding;
66
69
  private isBaseRelativeDataResourceId;
@@ -316,9 +316,12 @@ class PodChatKitStore {
316
316
  * ChatKit 边界继续暴露 metadata.chat_id;内部同一值叫 surface_id。
317
317
  */
318
318
  threadRecordToMetadata(record, chatResourceMap) {
319
- const commandKind = record.commandKind === 'task' ? 'task' : 'chat';
320
- const surfaceId = record.surfaceId || this.resolveChatSurfaceFromResource(record.chat, chatResourceMap, PodChatKitStore.DEFAULT_CHAT_ID);
321
319
  const extra = this.parseJsonObject(record.metadata);
320
+ const commandKind = record.commandKind === 'task' || extra?.commandKind === 'task' ? 'task' : 'chat';
321
+ const surfaceId = record.surfaceId
322
+ || (typeof extra?.surface_id === 'string' ? extra.surface_id : undefined)
323
+ || (typeof extra?.chat_id === 'string' ? extra.chat_id : undefined)
324
+ || this.resolveChatSurfaceFromResource(record.chat, chatResourceMap, PodChatKitStore.DEFAULT_CHAT_ID);
322
325
  return {
323
326
  id: record.id,
324
327
  title: record.title || undefined,
@@ -368,6 +371,29 @@ class PodChatKitStore {
368
371
  jsonObjectOrNull(value) {
369
372
  return value && Object.keys(value).length > 0 ? value : null;
370
373
  }
374
+ getXpodMetadata(metadata) {
375
+ const value = metadata?.xpod;
376
+ return value && typeof value === 'object' && !Array.isArray(value)
377
+ ? value
378
+ : undefined;
379
+ }
380
+ withXpodMetadata(metadata, xpod) {
381
+ return {
382
+ ...(metadata ?? {}),
383
+ xpod: {
384
+ ...(this.getXpodMetadata(metadata) ?? {}),
385
+ ...xpod,
386
+ },
387
+ };
388
+ }
389
+ withoutXpodMetadata(metadata) {
390
+ if (!metadata) {
391
+ return undefined;
392
+ }
393
+ const result = { ...metadata };
394
+ delete result.xpod;
395
+ return Object.keys(result).length > 0 ? result : undefined;
396
+ }
371
397
  withTaskAuthBindingMetadata(metadata, authBinding) {
372
398
  if (!authBinding) {
373
399
  return metadata;
@@ -487,13 +513,15 @@ class PodChatKitStore {
487
513
  return resource;
488
514
  }
489
515
  runRecordToData(record) {
516
+ const metadata = this.parseJsonObject(record.metadata);
517
+ const xpod = this.getXpodMetadata(metadata);
490
518
  return {
491
519
  id: record.id || '',
492
- surfaceId: record.surfaceId || 'default',
520
+ surfaceId: record.surfaceId || (typeof xpod?.surfaceId === 'string' ? xpod.surfaceId : 'default'),
493
521
  task: record.task || undefined,
494
522
  thread: record.thread || '',
495
523
  workspace: record.workspace || '',
496
- commandKind: record.commandKind === 'task' ? 'task' : 'chat',
524
+ commandKind: record.commandKind === 'task' || xpod?.commandKind === 'task' ? 'task' : 'chat',
497
525
  status: (record.status || 'queued'),
498
526
  runner: record.runner || '',
499
527
  prompt: record.prompt || undefined,
@@ -503,7 +531,7 @@ class PodChatKitStore {
503
531
  heartbeatAt: this.isoToTimestamp(record.heartbeatAt),
504
532
  cancelRequestedAt: this.isoToTimestamp(record.cancelRequestedAt),
505
533
  error: record.error || undefined,
506
- metadata: this.parseJsonObject(record.metadata),
534
+ metadata,
507
535
  createdAt: this.isoToTimestamp(record.createdAt) ?? (0, types_1.nowTimestamp)(),
508
536
  startedAt: this.isoToTimestamp(record.startedAt),
509
537
  completedAt: this.isoToTimestamp(record.completedAt),
@@ -511,36 +539,42 @@ class PodChatKitStore {
511
539
  };
512
540
  }
513
541
  runStepRecordToData(record) {
542
+ const payload = this.parseJsonObject(record.payload) ?? this.parseJsonObject(record.data);
543
+ const xpod = this.getXpodMetadata(payload);
514
544
  return {
515
545
  id: record.id || '',
516
- commandKind: record.commandKind === 'task' ? 'task' : 'chat',
517
- surfaceId: record.surfaceId || 'default',
518
- runId: record.runId || '',
546
+ commandKind: record.commandKind === 'task' || xpod?.commandKind === 'task' ? 'task' : 'chat',
547
+ surfaceId: record.surfaceId || (typeof xpod?.surfaceId === 'string' ? xpod.surfaceId : 'default'),
548
+ runId: record.runId || (typeof xpod?.runId === 'string' ? xpod.runId : ''),
519
549
  run: record.run || '',
520
- type: record.type || 'runtime.event',
550
+ type: record.type || record.stepType || 'runtime.event',
521
551
  message: record.message || undefined,
522
- data: this.parseJsonObject(record.data),
552
+ data: this.withoutXpodMetadata(payload),
523
553
  createdAt: this.isoToTimestamp(record.createdAt) ?? (0, types_1.nowTimestamp)(),
524
554
  };
525
555
  }
526
556
  taskRecordToData(record) {
557
+ const metadata = this.parseJsonObject(record.metadata);
558
+ const xpod = this.getXpodMetadata(metadata);
527
559
  return {
528
560
  id: record.id || '',
529
- surfaceId: record.surfaceId || 'default',
561
+ surfaceId: record.surfaceId || (typeof xpod?.surfaceId === 'string' ? xpod.surfaceId : 'default'),
530
562
  title: record.title || undefined,
531
563
  prompt: record.prompt || '',
532
564
  thread: record.thread || '',
533
565
  workspace: record.workspace || '',
534
- runner: record.runner || '',
566
+ runner: record.runner || (typeof xpod?.runner === 'string' ? xpod.runner : ''),
535
567
  status: (record.status || 'active'),
536
- triggerKind: (record.triggerKind || 'once'),
537
- cron: record.cron || undefined,
538
- intervalSeconds: typeof record.intervalSeconds === 'number' ? record.intervalSeconds : undefined,
539
- eventName: record.eventName || undefined,
540
- nextRunAt: this.isoToTimestamp(record.nextRunAt),
541
- lastRunAt: this.isoToTimestamp(record.lastRunAt),
542
- authBinding: this.parseTaskAuthBinding(this.parseJsonObject(record.metadata)?.authBinding),
543
- metadata: this.parseJsonObject(record.metadata),
568
+ triggerKind: (record.triggerKind || xpod?.triggerKind || 'once'),
569
+ cron: record.cron || (typeof xpod?.cron === 'string' ? xpod.cron : undefined),
570
+ intervalSeconds: typeof record.intervalSeconds === 'number'
571
+ ? record.intervalSeconds
572
+ : (typeof xpod?.intervalSeconds === 'number' ? xpod.intervalSeconds : undefined),
573
+ eventName: record.eventName || (typeof xpod?.eventName === 'string' ? xpod.eventName : undefined),
574
+ nextRunAt: this.isoToTimestamp(record.nextRunAt) ?? (typeof xpod?.nextRunAt === 'number' ? xpod.nextRunAt : undefined),
575
+ lastRunAt: this.isoToTimestamp(record.lastRunAt) ?? (typeof xpod?.lastRunAt === 'number' ? xpod.lastRunAt : undefined),
576
+ authBinding: this.parseTaskAuthBinding(metadata?.authBinding),
577
+ metadata,
544
578
  createdAt: this.isoToTimestamp(record.createdAt) ?? (0, types_1.nowTimestamp)(),
545
579
  updatedAt: this.isoToTimestamp(record.updatedAt) ?? (0, types_1.nowTimestamp)(),
546
580
  };
@@ -876,12 +910,7 @@ class PodChatKitStore {
876
910
  surface_id: surfaceId,
877
911
  chat_id: surfaceId,
878
912
  };
879
- // Persist extended metadata except fields that are derived from first-class columns.
880
- const metadataToPersist = { ...(thread.metadata ?? {}) };
881
- delete metadataToPersist.chat_id;
882
- delete metadataToPersist.commandKind;
883
- delete metadataToPersist.surface_id;
884
- const metadataObject = this.jsonObjectOrNull(metadataToPersist);
913
+ const metadataObject = this.jsonObjectOrNull(thread.metadata);
885
914
  if (commandKind === 'chat') {
886
915
  await this.ensureChat(surfaceId, context);
887
916
  }
@@ -898,9 +927,8 @@ class PodChatKitStore {
898
927
  if (existing) {
899
928
  // Update
900
929
  await db.updateByIri(schema_1.Thread, threadResource, {
901
- commandKind,
902
- surfaceId,
903
930
  chat: commandKind === 'chat' ? this.buildChatResourceId(surfaceId) : null,
931
+ task: commandKind === 'task' ? (0, store_2.buildTaskResourceId)(`index.ttl#${surfaceId}`) : null,
904
932
  title: thread.title || null,
905
933
  status: this.statusToString(thread.status),
906
934
  workspace: thread.workspace || null,
@@ -912,9 +940,8 @@ class PodChatKitStore {
912
940
  // Insert
913
941
  await db.insert(schema_1.Thread).values({
914
942
  id: threadResourceId,
915
- commandKind,
916
- surfaceId,
917
943
  chat: commandKind === 'chat' ? this.buildChatResourceId(surfaceId) : null,
944
+ task: commandKind === 'task' ? (0, store_2.buildTaskResourceId)(`index.ttl#${surfaceId}`) : null,
918
945
  title: thread.title || null,
919
946
  status: this.statusToString(thread.status),
920
947
  workspace: thread.workspace || null,
@@ -1094,8 +1121,6 @@ class PodChatKitStore {
1094
1121
  }
1095
1122
  const messageRecord = {
1096
1123
  id: itemResourceId,
1097
- commandKind: resolvedThread.commandKind,
1098
- surfaceId: resolvedThread.surfaceId,
1099
1124
  chat: resolvedThread.commandKind === 'chat' ? this.buildChatResourceId(resolvedThread.surfaceId) : null,
1100
1125
  thread: resolvedThread.thread,
1101
1126
  maker: role === schema_1.MessageRole.USER ? webId : null,
@@ -1104,7 +1129,12 @@ class PodChatKitStore {
1104
1129
  status,
1105
1130
  toolName,
1106
1131
  toolCallId,
1107
- metadata: this.jsonObjectOrNull(metadata ?? undefined),
1132
+ metadata: this.jsonObjectOrNull({
1133
+ ...(metadata ?? {}),
1134
+ commandKind: resolvedThread.commandKind,
1135
+ surface_id: resolvedThread.surfaceId,
1136
+ chat_id: resolvedThread.surfaceId,
1137
+ }),
1108
1138
  createdAt: new Date(item.created_at * 1000).toISOString(),
1109
1139
  };
1110
1140
  await db.insert(schema_1.Message).values(messageRecord);
@@ -1302,12 +1332,14 @@ WHERE { ${deletePatterns.join(' ')} }
1302
1332
  }
1303
1333
  run.id = (0, store_1.buildRunResourceId)(run);
1304
1334
  const existing = await db.findById(schema_2.Run, run.id);
1305
- const values = {
1335
+ const metadata = this.withXpodMetadata(run.metadata, {
1336
+ commandKind: run.commandKind,
1306
1337
  surfaceId: run.surfaceId,
1338
+ });
1339
+ const values = {
1307
1340
  task: run.task || null,
1308
1341
  thread: run.thread,
1309
1342
  workspace: run.workspace,
1310
- commandKind: run.commandKind,
1311
1343
  status: run.status,
1312
1344
  runner: run.runner || null,
1313
1345
  prompt: run.prompt || null,
@@ -1317,7 +1349,7 @@ WHERE { ${deletePatterns.join(' ')} }
1317
1349
  heartbeatAt: this.timestampToIso(run.heartbeatAt),
1318
1350
  cancelRequestedAt: this.timestampToIso(run.cancelRequestedAt),
1319
1351
  error: run.error || null,
1320
- metadata: this.jsonObjectOrNull(run.metadata),
1352
+ metadata: this.jsonObjectOrNull(metadata),
1321
1353
  createdAt: this.timestampToIso(run.createdAt) ?? new Date().toISOString(),
1322
1354
  startedAt: this.timestampToIso(run.startedAt),
1323
1355
  completedAt: this.timestampToIso(run.completedAt),
@@ -1358,9 +1390,6 @@ WHERE { ${deletePatterns.join(' ')} }
1358
1390
  if (options.workspace) {
1359
1391
  conditions.push((0, drizzle_solid_1.eq)(schema_2.Run.workspace, options.workspace));
1360
1392
  }
1361
- if (options.commandKind) {
1362
- conditions.push((0, drizzle_solid_1.eq)(schema_2.Run.commandKind, options.commandKind));
1363
- }
1364
1393
  if (options.status) {
1365
1394
  conditions.push((0, drizzle_solid_1.eq)(schema_2.Run.status, options.status));
1366
1395
  }
@@ -1368,10 +1397,13 @@ WHERE { ${deletePatterns.join(' ')} }
1368
1397
  const records = conditions.length > 0
1369
1398
  ? await query.where((0, drizzle_solid_1.and)(...conditions))
1370
1399
  : await query;
1371
- return records
1372
- .map((record) => this.runRecordToData(record))
1400
+ let runs = records.map((record) => this.runRecordToData(record));
1401
+ if (options.commandKind) {
1402
+ runs = runs.filter((run) => run.commandKind === options.commandKind);
1403
+ }
1404
+ return runs
1373
1405
  .sort((a, b) => b.createdAt - a.createdAt || b.id.localeCompare(a.id))
1374
- .slice(0, options.limit ?? records.length);
1406
+ .slice(0, options.limit ?? runs.length);
1375
1407
  }
1376
1408
  async appendRunStep(event, context) {
1377
1409
  const db = await this.getDb(context);
@@ -1384,13 +1416,14 @@ WHERE { ${deletePatterns.join(' ')} }
1384
1416
  event.id = (0, store_1.buildRunStepResourceId)(event);
1385
1417
  await db.insert(schema_2.RunStep).values({
1386
1418
  id: event.id,
1387
- commandKind: event.commandKind,
1388
- surfaceId: event.surfaceId,
1389
- runId: event.runId,
1390
1419
  run: event.run,
1391
- type: event.type,
1420
+ stepType: event.type,
1392
1421
  message: event.message || null,
1393
- data: this.jsonObjectOrNull(event.data),
1422
+ payload: this.jsonObjectOrNull(this.withXpodMetadata(event.data, {
1423
+ commandKind: event.commandKind,
1424
+ surfaceId: event.surfaceId,
1425
+ runId: event.runId,
1426
+ })),
1394
1427
  createdAt: this.timestampToIso(event.createdAt) ?? new Date().toISOString(),
1395
1428
  });
1396
1429
  }
@@ -1402,8 +1435,7 @@ WHERE { ${deletePatterns.join(' ')} }
1402
1435
  if (!(0, store_1.isRunResourceId)(runId)) {
1403
1436
  throw new Error(`loadRunSteps requires a base-relative Run id: ${runId}`);
1404
1437
  }
1405
- // runId is a local query field; RunStep.run remains the semantic RDF relation.
1406
- const records = await db.select().from(schema_2.RunStep).where((0, drizzle_solid_1.eq)(schema_2.RunStep.runId, runId));
1438
+ const records = await db.select().from(schema_2.RunStep).where((0, drizzle_solid_1.eq)(schema_2.RunStep.run, this.resolveDataResource(runId, context)));
1407
1439
  return records
1408
1440
  .map((record) => this.runStepRecordToData(record))
1409
1441
  .sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id));
@@ -1431,21 +1463,23 @@ WHERE { ${deletePatterns.join(' ')} }
1431
1463
  }
1432
1464
  task.id = (0, store_2.buildTaskResourceId)(task.id);
1433
1465
  const existing = await db.findById(schema_3.Task, task.id);
1434
- const values = {
1466
+ const metadata = this.withXpodMetadata(this.withTaskAuthBindingMetadata(task.metadata, task.authBinding), {
1435
1467
  surfaceId: task.surfaceId,
1468
+ runner: task.runner,
1469
+ triggerKind: task.triggerKind,
1470
+ cron: task.cron ?? null,
1471
+ intervalSeconds: task.intervalSeconds ?? null,
1472
+ eventName: task.eventName ?? null,
1473
+ nextRunAt: task.nextRunAt ?? null,
1474
+ lastRunAt: task.lastRunAt ?? null,
1475
+ });
1476
+ const values = {
1436
1477
  title: task.title || null,
1478
+ instruction: task.prompt,
1437
1479
  prompt: task.prompt,
1438
- thread: task.thread,
1439
1480
  workspace: task.workspace,
1440
- runner: task.runner,
1441
1481
  status: task.status,
1442
- triggerKind: task.triggerKind,
1443
- cron: task.cron || null,
1444
- intervalSeconds: task.intervalSeconds ?? null,
1445
- eventName: task.eventName || null,
1446
- nextRunAt: this.timestampToIso(task.nextRunAt),
1447
- lastRunAt: this.timestampToIso(task.lastRunAt),
1448
- metadata: this.jsonObjectOrNull(this.withTaskAuthBindingMetadata(task.metadata, task.authBinding)),
1482
+ metadata: this.jsonObjectOrNull(metadata),
1449
1483
  createdAt: this.timestampToIso(task.createdAt) ?? new Date().toISOString(),
1450
1484
  updatedAt: this.timestampToIso(task.updatedAt) ?? new Date().toISOString(),
1451
1485
  };