@tailor-platform/sdk 2.4.0 → 2.6.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 (252) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/bin/tailor.mjs +3 -2
  3. package/dist/aigateway-DsWDjzk4.mjs +2 -0
  4. package/dist/{aigateway-DR4Kwuik.mjs.map → aigateway-DsWDjzk4.mjs.map} +1 -1
  5. package/dist/application-CNeOcaLc.mjs +1 -0
  6. package/dist/application-CmXOqTaK.mjs +192 -0
  7. package/dist/application-CmXOqTaK.mjs.map +1 -0
  8. package/dist/assert-WeXvmG4j.mjs +2 -0
  9. package/dist/{assert-DBxo8jPo.mjs.map → assert-WeXvmG4j.mjs.map} +1 -1
  10. package/dist/authconnection-CynFBIv8.mjs +2 -0
  11. package/dist/{authconnection-CZvi9ANm.mjs.map → authconnection-CynFBIv8.mjs.map} +1 -1
  12. package/dist/brand-C8nMKhJC.mjs +2 -0
  13. package/dist/{brand-Eo4pLXPJ.mjs.map → brand-C8nMKhJC.mjs.map} +1 -1
  14. package/dist/cli/commands/api/index.d.mts +1 -1
  15. package/dist/cli/commands/deploy/deploy.d.mts +2 -2
  16. package/dist/cli/commands/deploy/deployment-target.d.mts +2 -0
  17. package/dist/cli/commands/deploy/event-subscriptions.d.mts +3 -0
  18. package/dist/cli/commands/deploy/tailordb/apply.d.mts +3 -0
  19. package/dist/cli/commands/deploy/tailordb/index.d.mts +3 -10
  20. package/dist/cli/commands/deploy/tailordb/migration-validation.d.mts +5 -0
  21. package/dist/cli/commands/deploy/tailordb/plan.d.mts +8 -0
  22. package/dist/cli/commands/executor/jobs.d.mts +1 -1
  23. package/dist/cli/commands/executor/trigger.d.mts +1 -1
  24. package/dist/cli/commands/generate/seed/bundler.d.mts +2 -2
  25. package/dist/cli/commands/show.d.mts +1 -1
  26. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +11 -11
  27. package/dist/cli/commands/tailordb/migrate/generate.d.mts +4 -0
  28. package/dist/cli/commands/tailordb/migrate/rename-detection.d.mts +1 -1
  29. package/dist/cli/commands/tailordb/migrate/snapshot-comparison.d.mts +43 -0
  30. package/dist/cli/commands/tailordb/migrate/snapshot-files.d.mts +62 -0
  31. package/dist/cli/commands/tailordb/migrate/snapshot-local.d.mts +12 -0
  32. package/dist/cli/commands/tailordb/migrate/snapshot-migrations.d.mts +12 -0
  33. package/dist/cli/commands/tailordb/migrate/snapshot-remote.d.mts +1 -0
  34. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +3 -1
  35. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +5 -117
  36. package/dist/cli/commands/workflow/start.d.mts +1 -1
  37. package/dist/cli/commands/workspace/list.d.mts +1 -1
  38. package/dist/cli/lib.d.mts +12 -4
  39. package/dist/cli/lib.mjs +1 -9
  40. package/dist/cli/lib.mjs.map +1 -1
  41. package/dist/cli/main.d.mts +2 -0
  42. package/dist/cli/main.mjs +1170 -7754
  43. package/dist/cli/main.mjs.map +1 -1
  44. package/dist/cli/shared/args.d.mts +65 -1
  45. package/dist/cli/shared/command.d.mts +11 -0
  46. package/dist/cli/shared/context.d.mts +1 -1
  47. package/dist/cli/shared/logger.d.mts +64 -0
  48. package/dist/cli/shared/script-executor.d.mts +1 -1
  49. package/dist/cli/shared/seed-chunker.d.mts +5 -5
  50. package/dist/completion/zsh-worker.zsh +82 -9
  51. package/dist/configure/config/index.d.mts +1 -1
  52. package/dist/configure/config/types.d.mts +2 -2
  53. package/dist/configure/index.d.mts +48 -12
  54. package/dist/configure/index.mjs +1 -1267
  55. package/dist/configure/index.mjs.map +1 -1
  56. package/dist/configure/services/auth/types.d.mts +1 -1
  57. package/dist/configure/services/idp/types.d.mts +1 -1
  58. package/dist/configure/services/tailordb/schema.d.mts +22 -8
  59. package/dist/configure/services/tailordb/types.d.mts +2 -2
  60. package/dist/configure/services/workflow/execution-policy.d.mts +3 -3
  61. package/dist/configure/services/workflow/job.d.mts +12 -2
  62. package/dist/configure/types/field.types.d.mts +1 -1
  63. package/dist/configure/types/permission-operand.types.d.mts +1 -1
  64. package/dist/context-D0QjfxzD.mjs +2 -0
  65. package/dist/{context-DYQVYWqZ.mjs.map → context-D0QjfxzD.mjs.map} +1 -1
  66. package/dist/crashreport-BN28xp5B.mjs +42 -0
  67. package/dist/{crashreport-Q0pDAlrj.mjs.map → crashreport-BN28xp5B.mjs.map} +1 -1
  68. package/dist/crashreport-By23O2k-.mjs +1 -0
  69. package/dist/errors-DLsQ_-ol.mjs +2 -0
  70. package/dist/errors-DLsQ_-ol.mjs.map +1 -0
  71. package/dist/es-builtins-n3wBv4Sv.mjs +2 -0
  72. package/dist/es-builtins-n3wBv4Sv.mjs.map +1 -0
  73. package/dist/file-COPYfju_.mjs +2 -0
  74. package/dist/file-COPYfju_.mjs.map +1 -0
  75. package/dist/globals-CMHSnj4w.mjs +2 -0
  76. package/dist/{globals-B2nlxBrz.mjs.map → globals-CMHSnj4w.mjs.map} +1 -1
  77. package/dist/iconv-DlFMt2gW.mjs +2 -0
  78. package/dist/{iconv-QWaZh0TT.mjs.map → iconv-DlFMt2gW.mjs.map} +1 -1
  79. package/dist/idp-G_ojPBB5.mjs +2 -0
  80. package/dist/{idp-RA_swu-h.mjs.map → idp-G_ojPBB5.mjs.map} +1 -1
  81. package/dist/interceptor-DQg3cR_9.mjs +2 -0
  82. package/dist/{interceptor-e33JtsC-.mjs.map → interceptor-DQg3cR_9.mjs.map} +1 -1
  83. package/dist/kysely/index.mjs +1 -32
  84. package/dist/kysely/index.mjs.map +1 -1
  85. package/dist/kysely-type-BTi3BMtL.mjs +43 -0
  86. package/dist/kysely-type-BTi3BMtL.mjs.map +1 -0
  87. package/dist/logger-CCjs1DuH.mjs +9 -0
  88. package/dist/logger-CCjs1DuH.mjs.map +1 -0
  89. package/dist/logger-DP2BjQ93.mjs +2 -0
  90. package/dist/{logger-BtX0suGY.mjs.map → logger-DP2BjQ93.mjs.map} +1 -1
  91. package/dist/multiline-EyzjEwn9.mjs +3 -0
  92. package/dist/{multiline-sfHpTZZK.mjs.map → multiline-EyzjEwn9.mjs.map} +1 -1
  93. package/dist/node-builtins-oBl7EbyV.mjs +2 -0
  94. package/dist/{node-builtins-CmaL2Cbq.mjs.map → node-builtins-oBl7EbyV.mjs.map} +1 -1
  95. package/dist/package-json-C690ceex.mjs +2 -0
  96. package/dist/{package-json-8b0O9TlX.mjs.map → package-json-C690ceex.mjs.map} +1 -1
  97. package/dist/package-json-CmqhDJ__.mjs +1 -0
  98. package/dist/parser/service/tailordb/type-source.d.mts +5 -5
  99. package/dist/parser/service/tailordb/types.d.mts +4 -4
  100. package/dist/platform-serialize-DkiTdHOt.mjs +2 -0
  101. package/dist/{platform-serialize-RoRtBS0v.mjs.map → platform-serialize-DkiTdHOt.mjs.map} +1 -1
  102. package/dist/plugin/builtin/enum-constants/index.mjs +5 -114
  103. package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
  104. package/dist/plugin/builtin/file-utils/index.mjs +22 -104
  105. package/dist/plugin/builtin/file-utils/index.mjs.map +1 -1
  106. package/dist/plugin/builtin/kysely-type/index.d.mts +8 -1
  107. package/dist/plugin/builtin/kysely-type/index.mjs +1 -275
  108. package/dist/plugin/builtin/seed/index.d.mts +5 -0
  109. package/dist/plugin/builtin/seed/index.mjs +1 -3
  110. package/dist/plugin/builtin/seed/seed-type-processor.d.mts +0 -2
  111. package/dist/plugin/{get-generated-type.d.mts → get-generated-table.d.mts} +5 -5
  112. package/dist/plugin/index.d.mts +3 -2
  113. package/dist/plugin/index.mjs +1 -251
  114. package/dist/plugin/index.mjs.map +1 -1
  115. package/dist/plugin/types.d.mts +30 -23
  116. package/dist/plugin/with-context.d.mts +3 -3
  117. package/dist/register-ts-hook-oDA2JLp2.mjs +640 -0
  118. package/dist/register-ts-hook-oDA2JLp2.mjs.map +1 -0
  119. package/dist/registry-HlEaGvl5.mjs +2 -0
  120. package/dist/{registry-BIGVUrMB.mjs.map → registry-HlEaGvl5.mjs.map} +1 -1
  121. package/dist/repl-editor-BG1aDOfH.mjs +2 -0
  122. package/dist/{repl-editor-F9LotMNx.mjs.map → repl-editor-BG1aDOfH.mjs.map} +1 -1
  123. package/dist/runtime/aigateway.mjs +1 -3
  124. package/dist/runtime/authconnection.mjs +1 -3
  125. package/dist/runtime/context.mjs +1 -3
  126. package/dist/runtime/file.d.mts +21 -21
  127. package/dist/runtime/file.mjs +1 -3
  128. package/dist/runtime/globals.mjs +1 -1
  129. package/dist/runtime/iconv.mjs +1 -3
  130. package/dist/runtime/idp.mjs +1 -3
  131. package/dist/runtime/index.mjs +1 -11
  132. package/dist/runtime/logger.mjs +1 -3
  133. package/dist/runtime/secretmanager.mjs +1 -3
  134. package/dist/runtime/types.d.mts +1 -1
  135. package/dist/runtime/workflow.mjs +1 -3
  136. package/dist/schema-AYG4OhXY.mjs +2 -0
  137. package/dist/schema-AYG4OhXY.mjs.map +1 -0
  138. package/dist/secret-file-C9wp_FCX.mjs +2 -0
  139. package/dist/{secret-file-C3J4Gy8r.mjs.map → secret-file-C9wp_FCX.mjs.map} +1 -1
  140. package/dist/secretmanager-5olfnI1b.mjs +2 -0
  141. package/dist/{secretmanager-IY4UvinW.mjs.map → secretmanager-5olfnI1b.mjs.map} +1 -1
  142. package/dist/secretmanager-vHQoXdQz.mjs +2 -0
  143. package/dist/{secretmanager-CYlpffsz.mjs.map → secretmanager-vHQoXdQz.mjs.map} +1 -1
  144. package/dist/seed/index.mjs +8 -244
  145. package/dist/seed/index.mjs.map +1 -1
  146. package/dist/seed-DwqRFdqP.mjs +207 -0
  147. package/dist/seed-DwqRFdqP.mjs.map +1 -0
  148. package/dist/service-CLPMoj9n.mjs +2 -0
  149. package/dist/{service-LTfp03ZZ.mjs.map → service-CLPMoj9n.mjs.map} +1 -1
  150. package/dist/service-D7iXk0BT.mjs +1 -0
  151. package/dist/service-YqDsHmlK.mjs +7 -0
  152. package/dist/service-YqDsHmlK.mjs.map +1 -0
  153. package/dist/service_pb-DGKCLuAs.mjs +2 -0
  154. package/dist/{service_pb-BEWj1pOV.mjs.map → service_pb-DGKCLuAs.mjs.map} +1 -1
  155. package/dist/service_pb-_aeFE-Nv.mjs +1 -0
  156. package/dist/shared/src/color.d.mts +5 -0
  157. package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +1 -1
  158. package/dist/telemetry-Bklv9kQY.mjs +2 -0
  159. package/dist/{telemetry-BRVdwh14.mjs.map → telemetry-Bklv9kQY.mjs.map} +1 -1
  160. package/dist/telemetry-DXHP3VVi.mjs +1 -0
  161. package/dist/type-source--ZNcV8RJ.mjs +2 -0
  162. package/dist/type-source--ZNcV8RJ.mjs.map +1 -0
  163. package/dist/types/executor.generated.d.mts +1 -1
  164. package/dist/user-agent-vdHYF3QL.mjs +2 -0
  165. package/dist/{user-agent-Bgsszb5I.mjs.map → user-agent-vdHYF3QL.mjs.map} +1 -1
  166. package/dist/utils/test/index.mjs +1 -109
  167. package/dist/utils/test/index.mjs.map +1 -1
  168. package/dist/vitest/environment.mjs +1 -41
  169. package/dist/vitest/environment.mjs.map +1 -1
  170. package/dist/vitest/index.mjs +1 -1986
  171. package/dist/vitest/index.mjs.map +1 -1
  172. package/dist/vitest/mocks/file.d.mts +8 -8
  173. package/dist/vitest/setup.mjs +1 -140
  174. package/dist/vitest/setup.mjs.map +1 -1
  175. package/dist/wait-point-invoker-eiP-IIux.mjs +2 -0
  176. package/dist/wait-point-invoker-eiP-IIux.mjs.map +1 -0
  177. package/dist/wait-point-registry-B-ESkTZX.mjs +2 -0
  178. package/dist/wait-point-registry-B-ESkTZX.mjs.map +1 -0
  179. package/dist/workflow-Cs9ISw6j.mjs +2 -0
  180. package/dist/{workflow-Bamae_Yc.mjs.map → workflow-Cs9ISw6j.mjs.map} +1 -1
  181. package/dist/workspace_resource_pb--GeYQPXu.mjs +2 -0
  182. package/dist/{workspace_resource_pb-HNIL_Vfj.mjs.map → workspace_resource_pb--GeYQPXu.mjs.map} +1 -1
  183. package/docs/cli/function.md +66 -6
  184. package/docs/cli/setup.md +24 -14
  185. package/docs/cli/tailordb.md +2 -0
  186. package/docs/cli-reference.md +9 -8
  187. package/docs/github-actions.md +14 -12
  188. package/docs/migration/v2.md +18 -2
  189. package/docs/migration/v3.md +121 -0
  190. package/docs/plugin/custom.md +130 -85
  191. package/docs/plugin/index.md +3 -3
  192. package/docs/services/tailordb-migration.md +21 -7
  193. package/docs/services/tailordb.md +9 -7
  194. package/docs/services/workflow.md +10 -9
  195. package/package.json +14 -13
  196. package/postinstall.mjs +1 -1
  197. package/dist/aigateway-DR4Kwuik.mjs +0 -9
  198. package/dist/application-C8a0UJ-z.mjs +0 -6071
  199. package/dist/application-C8a0UJ-z.mjs.map +0 -1
  200. package/dist/application-D4zOiLLa.mjs +0 -3
  201. package/dist/assert-DBxo8jPo.mjs +0 -9
  202. package/dist/authconnection-CZvi9ANm.mjs +0 -9
  203. package/dist/brand-Eo4pLXPJ.mjs +0 -36
  204. package/dist/context-DYQVYWqZ.mjs +0 -23
  205. package/dist/crashreport-Cd4TqfZq.mjs +0 -3
  206. package/dist/crashreport-Q0pDAlrj.mjs +0 -427
  207. package/dist/errors-Bxut5_Sy.mjs +0 -89
  208. package/dist/errors-Bxut5_Sy.mjs.map +0 -1
  209. package/dist/file-BUcmVIH2.mjs +0 -58
  210. package/dist/file-BUcmVIH2.mjs.map +0 -1
  211. package/dist/globals-B2nlxBrz.mjs +0 -126
  212. package/dist/iconv-QWaZh0TT.mjs +0 -38
  213. package/dist/idp-RA_swu-h.mjs +0 -82
  214. package/dist/interceptor-e33JtsC-.mjs +0 -33
  215. package/dist/logger-BtX0suGY.mjs +0 -48
  216. package/dist/logger-D0bEznPv.mjs +0 -362
  217. package/dist/logger-D0bEznPv.mjs.map +0 -1
  218. package/dist/multiline-sfHpTZZK.mjs +0 -38
  219. package/dist/node-builtins-CmaL2Cbq.mjs +0 -36
  220. package/dist/package-json-8b0O9TlX.mjs +0 -17
  221. package/dist/package-json-Cv2Z-TqQ.mjs +0 -3
  222. package/dist/platform-serialize-RoRtBS0v.mjs +0 -46
  223. package/dist/plugin/builtin/kysely-type/index.mjs.map +0 -1
  224. package/dist/plugin/builtin/seed/types.d.mts +0 -2
  225. package/dist/register-ts-hook-Vqjza10T.mjs +0 -25679
  226. package/dist/register-ts-hook-Vqjza10T.mjs.map +0 -1
  227. package/dist/registry-BIGVUrMB.mjs +0 -54
  228. package/dist/repl-editor-F9LotMNx.mjs +0 -252
  229. package/dist/schema-D4TC4BC3.mjs +0 -640
  230. package/dist/schema-D4TC4BC3.mjs.map +0 -1
  231. package/dist/secret-file-C3J4Gy8r.mjs +0 -64
  232. package/dist/secretmanager-CYlpffsz.mjs +0 -13
  233. package/dist/secretmanager-IY4UvinW.mjs +0 -131
  234. package/dist/seed-Cibjmtry.mjs +0 -489
  235. package/dist/seed-Cibjmtry.mjs.map +0 -1
  236. package/dist/service-2grcAOCJ.mjs +0 -898
  237. package/dist/service-2grcAOCJ.mjs.map +0 -1
  238. package/dist/service-CaBPNDIZ.mjs +0 -3
  239. package/dist/service-LTfp03ZZ.mjs +0 -133
  240. package/dist/service_pb-BEWj1pOV.mjs +0 -167
  241. package/dist/service_pb-BjlhvK9E.mjs +0 -3
  242. package/dist/telemetry-BRVdwh14.mjs +0 -84
  243. package/dist/telemetry-CkbkeJxl.mjs +0 -3
  244. package/dist/type-source-DH_LH20p.mjs +0 -13
  245. package/dist/type-source-DH_LH20p.mjs.map +0 -1
  246. package/dist/user-agent-Bgsszb5I.mjs +0 -28
  247. package/dist/wait-point-invoker-__oE88_P.mjs +0 -148
  248. package/dist/wait-point-invoker-__oE88_P.mjs.map +0 -1
  249. package/dist/wait-point-registry-TL99zotw.mjs +0 -47
  250. package/dist/wait-point-registry-TL99zotw.mjs.map +0 -1
  251. package/dist/workflow-Bamae_Yc.mjs +0 -34
  252. package/dist/workspace_resource_pb-HNIL_Vfj.mjs +0 -860
@@ -165,4 +165,4 @@ type AuthServiceInputLoose = AuthServiceInput<any, any, any, string, any>;
165
165
  type AuthOwnConfig = DefinedAuth<string, AuthServiceInputLoose>;
166
166
  type AuthConfig = AuthOwnConfig | AuthExternalConfig;
167
167
  //#endregion
168
- export { AuthAttributeValue, AuthConfig, AuthConnectionTokenResult, AuthDefinitionBrand, AuthExternalConfig, AuthHooks, AuthOwnConfig, AuthServiceInput, BeforeLoginClaims, BeforeLoginHook, BeforeLoginHookArgs, DefinedAuth, FederatedIdentity, FederatedIdentityClaims, FederatedIdentityProvider, MachineUserName, MachineUserNameRegistry, OAuth2ClientGrantType, SCIMAttributeType, UserAttributeKey, UserAttributeListKey, UserAttributes, UsernameFieldKey, ValueOperand };
168
+ export { AuthAttributeValue, AuthConfig, AuthConnectionTokenResult, AuthDefinitionBrand, AuthExternalConfig, AuthOwnConfig, AuthServiceInput, BeforeLoginClaims, BeforeLoginHook, BeforeLoginHookArgs, DefinedAuth, FederatedIdentity, FederatedIdentityClaims, FederatedIdentityProvider, MachineUserName, MachineUserNameRegistry, OAuth2ClientGrantType, SCIMAttributeType, UserAttributeKey, UserAttributeListKey, UserAttributes, UsernameFieldKey, ValueOperand };
@@ -20,4 +20,4 @@ type IdPOwnConfigInput = Omit<IdPInput, "permission"> & {
20
20
  type IdPOwnConfig = Omit<DefinedIdp<string, IdPOwnConfigInput, string>, "provider">;
21
21
  type IdPConfig = IdPOwnConfig | IdPExternalConfig;
22
22
  //#endregion
23
- export { DefinedIdp, IdPConfig, IdPExternalConfig, IdPOwnConfig, IdpDefinitionBrand };
23
+ export { IdPConfig, IdPExternalConfig, IdPOwnConfig, IdpDefinitionBrand };
@@ -1,7 +1,7 @@
1
1
  import { FieldOptions, FieldOutput, FieldValidateInput, TailorFieldType, TailorToTs } from "../../types/field.types.mjs";
2
- import { InferredAttributes, TailorPrincipal } from "../../../runtime/types.mjs";
2
+ import { InferredAttributes } from "../../../runtime/types.mjs";
3
3
  import { InferFieldsOutput, TypeLevelError, output } from "../../../types/helpers.mjs";
4
- import { DBFieldMetadata, DefinedDBFieldMetadata, ExcludeDefaultedDBFields, ExcludeHookedDBFields, ExcludeNestedDBFields, Hook, IndexDef, RelationType, SerialConfig, TailorDBField as TailorDBField$1, TailorDBType as TailorDBType$1, TypeFeatures, TypeHook, TypeValidateFn } from "./types.mjs";
4
+ import { DBFieldMetadata, DefinedDBFieldMetadata, ExcludeDefaultedDBFields, ExcludeHookedDBFields, ExcludeNestedDBFields, Hook, IndexDef, RelationType, SerialConfig, TailorDBField as TailorDBField$1, TailorDBType as TailorDBType$1, TypeFeatures, TypeHook, TypeValidateFn, UpdateHookFn } from "./types.mjs";
5
5
  import { AllowedValues, AllowedValuesOutput } from "../../types/field.mjs";
6
6
  import { FieldParseArgs } from "../../../runtime/field-parse.mjs";
7
7
  import { PluginConfigs } from "../../../plugin/types.mjs";
@@ -277,18 +277,36 @@ type TailorDBInstance<Fields extends Record<string, TailorAnyDBField> = any, Use
277
277
  interface RelationConfig<S extends RelationType, T extends TailorDBType> {
278
278
  type: S;
279
279
  toward: {
280
+ table: T;
281
+ as?: string;
282
+ key?: keyof T["fields"] & string;
283
+ type?: never;
284
+ } | {
285
+ /**
286
+ * @deprecated since 2.6.0 — use `table` instead. codemod: v3/relation-toward-table
287
+ */
280
288
  type: T;
281
289
  as?: string;
282
290
  key?: keyof T["fields"] & string;
291
+ table?: never;
283
292
  };
284
293
  backward?: string;
285
294
  }
286
295
  type RelationSelfConfig = {
287
296
  type: RelationType;
288
297
  toward: {
298
+ table: "self";
299
+ as?: string;
300
+ key?: string;
301
+ type?: never;
302
+ } | {
303
+ /**
304
+ * @deprecated since 2.6.0 — use `table` instead. codemod: v3/relation-toward-table
305
+ */
289
306
  type: "self";
290
307
  as?: string;
291
308
  key?: string;
309
+ table?: never;
292
310
  };
293
311
  backward?: string;
294
312
  };
@@ -443,6 +461,7 @@ declare function dbTable<const F extends {
443
461
  declare function dbTable<const F extends {
444
462
  id?: never;
445
463
  } & Record<string, TailorAnyDBField>>(name: string | [string, string], description: string, fields: F): DBTable<F, WithDBTypeMetadata<DefinedDBTypeMetadata, "description">>;
464
+ type TimestampsUpdatedAtHookFn = UpdateHookFn<string | Date | null, string | Date>;
446
465
  /** TailorDB schema builder utilities for defining tables and fields. */
447
466
  declare const db: {
448
467
  table: typeof dbTable;
@@ -472,12 +491,7 @@ declare const db: {
472
491
  timestamps: () => {
473
492
  createdAt: TailorDBField<WithDBFieldDescription<WithDBFieldDefault<DBFieldDefined<"datetime", FieldOptions>>>, string | Date, Record<string, TailorAnyDBField>>;
474
493
  updatedAt: TailorDBField<WithDBFieldDescription<WithDBFieldHooks<WithDBFieldDefault<DBFieldDefined<"datetime", FieldOptions>>, {
475
- readonly update: ({ input, now }: {
476
- input: string | Date | null;
477
- oldValue: string | Date;
478
- invoker: TailorPrincipal | null;
479
- now: Date;
480
- }) => string | Date;
494
+ readonly update: TimestampsUpdatedAtHookFn;
481
495
  }>>, string | Date, Record<string, TailorAnyDBField>>;
482
496
  };
483
497
  };
@@ -42,7 +42,7 @@ type GqlOperationsConfig = GqlOperationsInput;
42
42
  interface RawRelationConfig {
43
43
  type: "1-1" | "n-1" | "keyOnly" | "oneToOne" | "manyToOne" | "N-1";
44
44
  toward: {
45
- type: string;
45
+ table: string;
46
46
  as?: string;
47
47
  key?: string;
48
48
  };
@@ -224,4 +224,4 @@ type TailorDBServiceInput = {
224
224
  [namespace: string]: TailorDBServiceConfigInput | TailorDBExternalConfig;
225
225
  };
226
226
  //#endregion
227
- export { DBFieldMetadata, DefinedDBFieldMetadata, ExcludeDefaultedDBFields, ExcludeHookedDBFields, ExcludeNestedDBFields, GqlOperationsConfig, Hook, IndexDef, IsAutoFilledDBField, IsReadOnlyDBField, PluginAttachment, RawRelationConfig, RelationType, SerialConfig, TailorAnyDBField, TailorAnyDBType, TailorDBExternalConfig, TailorDBField, TailorDBInstance, TailorDBServiceInput, TailorDBType, TailorDBTypeMetadata, TypeFeatures, TypeHook, TypeValidateFn };
227
+ export { DBFieldMetadata, DefinedDBFieldMetadata, ExcludeDefaultedDBFields, ExcludeHookedDBFields, ExcludeNestedDBFields, Hook, IndexDef, IsAutoFilledDBField, IsReadOnlyDBField, PluginAttachment, RawRelationConfig, RelationType, SerialConfig, TailorAnyDBField, TailorAnyDBType, TailorDBField, TailorDBInstance, TailorDBServiceInput, TailorDBType, TailorDBTypeMetadata, TypeFeatures, TypeHook, TypeValidateFn, UpdateHookFn };
@@ -57,11 +57,11 @@ declare function defineWorkflowExecutionPolicy<const N extends string, const D e
57
57
  * }),
58
58
  * }));
59
59
  *
60
- * // In a workflow job function:
61
- * await tailor.workflow.execJobFunction("worker", args, {
60
+ * // In a workflow job body:
61
+ * await worker.start(args, {
62
62
  * executionPolicyKey: executionPolicies.premium.key,
63
63
  * });
64
- * await tailor.workflow.execJobFunction("worker", args, {
64
+ * await worker.start(args, {
65
65
  * executionPolicyKey: executionPolicies["tenant-api"].keyFor(input.tenantId),
66
66
  * });
67
67
  */
@@ -29,6 +29,11 @@ interface WorkflowJob<Name extends string = string, Input = undefined, Output =
29
29
  * Start this job with the given input and return the job's output value.
30
30
  * Accepts an optional second argument to pass `executionPolicyKey` for
31
31
  * platform-side concurrency enforcement.
32
+ *
33
+ * Must be called from within another job's `body` (a function defined
34
+ * inside `body` may call it too) — not from a function defined outside
35
+ * `body`. The build cannot see through that indirection to find the call,
36
+ * and fails instead of silently dropping it.
32
37
  * @example
33
38
  * body: async (input) => {
34
39
  * const a = jobA.start({ id: input.id });
@@ -63,9 +68,14 @@ interface CreateWorkflowJobConfig<Name extends string, I, O> {
63
68
  * Input and output must be JsonValue-compatible (primitives, plain objects, arrays).
64
69
  * Functions and objects with a `toJSON` method are rejected at the type level;
65
70
  * class instances exposing methods are rejected via the property walk.
71
+ * `name` and `body` must be written directly in this call — as a string literal and an
72
+ * inline function expression, respectively — not as a reference to a variable or the
73
+ * result of another function call. The build cannot see through that indirection to find
74
+ * the job, and fails instead of silently leaving it out.
66
75
  * @param config - Job configuration with name and body function.
67
- * @param config.name - Unique job name across the project.
68
- * @param config.body - Function that processes the job input.
76
+ * @param config.name - Unique job name across the project. Must be a string literal.
77
+ * @param config.body - Function that processes the job input. Must be an inline function
78
+ * expression, not a reference to a separately-defined function.
69
79
  * @returns A WorkflowJob that can be started from other jobs.
70
80
  * @example
71
81
  * // Simple job with async body:
@@ -67,4 +67,4 @@ interface TailorField<Defined extends DefinedFieldMetadata = DefinedFieldMetadat
67
67
  }
68
68
  type TailorAnyField = TailorField<any>;
69
69
  //#endregion
70
- export { ArrayFieldOutput, DefinedFieldMetadata, EnumValue, FieldMetadata, FieldOptions, FieldOutput, FieldValidateInput, TailorAnyField, TailorField, TailorFieldType, TailorToTs, ValidateFn };
70
+ export { DefinedFieldMetadata, EnumValue, FieldMetadata, FieldOptions, FieldOutput, FieldValidateInput, TailorAnyField, TailorField, TailorFieldType, TailorToTs };
@@ -17,4 +17,4 @@ type UserBooleanArrayOperand<User extends object = InferredAttributes> = {
17
17
  user: BooleanArrayFieldKeys<User>;
18
18
  };
19
19
  //#endregion
20
- export { BooleanArrayFieldKeys, BooleanFieldKeys, StringArrayFieldKeys, StringFieldKeys, UserBooleanArrayOperand, UserBooleanOperand, UserStringArrayOperand, UserStringOperand };
20
+ export { BooleanFieldKeys, StringFieldKeys, UserBooleanArrayOperand, UserBooleanOperand, UserStringArrayOperand, UserStringOperand };
@@ -0,0 +1,2 @@
1
+ function getInvoker(){let e=globalThis.tailor.context.getInvoker();return e?{id:e.id,type:e.type,workspaceId:e.workspaceId,attributes:e.attributeMap,attributeList:e.attributes}:null}const e={getInvoker};export{e as t};
2
+ //# sourceMappingURL=context-D0QjfxzD.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-DYQVYWqZ.mjs","names":[],"sources":["../src/runtime/context.ts"],"sourcesContent":["/**\n * Execution context utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.context` runtime API.\n * At runtime this delegates to `globalThis.tailor.context`.\n * @example\n * import { context } from \"@tailor-platform/sdk/runtime\";\n *\n * const invoker = context.getInvoker();\n * if (invoker) {\n * console.log(invoker.id, invoker.type, invoker.attributes, invoker.attributeList);\n * }\n */\n\nimport type { TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Information about the invoker of the current function execution.\n *\n * Matches the public `TailorPrincipal` shape — `attributes` is the attribute\n * map and `attributeList` is the array of attribute IDs.\n */\nexport type Invoker = TailorPrincipal;\n\n/**\n * Raw platform-side invoker payload returned by `tailor.context.getInvoker()`.\n * The wrapper normalizes this into {@link Invoker}.\n * @internal\n */\nexport interface ContextInvoker {\n /** The invoker's ID */\n id: string;\n /** The invoker's type */\n type: \"user\" | \"machine_user\";\n /** The workspace ID */\n workspaceId: string;\n /** The invoker's attribute IDs */\n attributes: string[];\n /** The invoker's attribute map */\n attributeMap: Record<string, unknown>;\n}\n\n/**\n * Platform API surface for `tailor.context`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.context`.\n * @internal\n */\nexport interface PlatformContextAPI {\n getInvoker(): ContextInvoker | null;\n}\n\n/** Runtime wrapper API for execution context utilities. */\nexport interface TailorContextAPI {\n /**\n * Returns information about the current invoker.\n * @returns Invoker details, or `null` for anonymous invocations\n */\n getInvoker(): Invoker | null;\n}\n\n/**\n * Returns information about the invoker of the current function execution,\n * or `null` for anonymous invocations.\n * @returns Invoker details, or `null` when the call is anonymous\n */\nfunction getInvoker(): Invoker | null {\n const raw = (\n globalThis as unknown as { tailor: { context: PlatformContextAPI } }\n ).tailor.context.getInvoker();\n if (!raw) return null;\n return {\n id: raw.id,\n type: raw.type,\n workspaceId: raw.workspaceId,\n attributes: raw.attributeMap as Invoker[\"attributes\"],\n attributeList: raw.attributes as Invoker[\"attributeList\"],\n };\n}\n\n/** Runtime wrapper namespace for `tailor.context`. */\nexport const context = { getInvoker } as const satisfies TailorContextAPI;\n"],"mappings":";;;;;;AAiEA,SAAS,aAA6B;CACpC,MAAM,MACJ,WACA,OAAO,QAAQ,WAAW;CAC5B,IAAI,CAAC,KAAK,OAAO;CACjB,OAAO;EACL,IAAI,IAAI;EACR,MAAM,IAAI;EACV,aAAa,IAAI;EACjB,YAAY,IAAI;EAChB,eAAe,IAAI;CACrB;AACF;;AAGA,MAAa,UAAU,EAAE,WAAW"}
1
+ {"version":3,"file":"context-D0QjfxzD.mjs","names":[],"sources":["../src/runtime/context.ts"],"sourcesContent":["/**\n * Execution context utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.context` runtime API.\n * At runtime this delegates to `globalThis.tailor.context`.\n * @example\n * import { context } from \"@tailor-platform/sdk/runtime\";\n *\n * const invoker = context.getInvoker();\n * if (invoker) {\n * console.log(invoker.id, invoker.type, invoker.attributes, invoker.attributeList);\n * }\n */\n\nimport type { TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Information about the invoker of the current function execution.\n *\n * Matches the public `TailorPrincipal` shape — `attributes` is the attribute\n * map and `attributeList` is the array of attribute IDs.\n */\nexport type Invoker = TailorPrincipal;\n\n/**\n * Raw platform-side invoker payload returned by `tailor.context.getInvoker()`.\n * The wrapper normalizes this into {@link Invoker}.\n * @internal\n */\nexport interface ContextInvoker {\n /** The invoker's ID */\n id: string;\n /** The invoker's type */\n type: \"user\" | \"machine_user\";\n /** The workspace ID */\n workspaceId: string;\n /** The invoker's attribute IDs */\n attributes: string[];\n /** The invoker's attribute map */\n attributeMap: Record<string, unknown>;\n}\n\n/**\n * Platform API surface for `tailor.context`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.context`.\n * @internal\n */\nexport interface PlatformContextAPI {\n getInvoker(): ContextInvoker | null;\n}\n\n/** Runtime wrapper API for execution context utilities. */\nexport interface TailorContextAPI {\n /**\n * Returns information about the current invoker.\n * @returns Invoker details, or `null` for anonymous invocations\n */\n getInvoker(): Invoker | null;\n}\n\n/**\n * Returns information about the invoker of the current function execution,\n * or `null` for anonymous invocations.\n * @returns Invoker details, or `null` when the call is anonymous\n */\nfunction getInvoker(): Invoker | null {\n const raw = (\n globalThis as unknown as { tailor: { context: PlatformContextAPI } }\n ).tailor.context.getInvoker();\n if (!raw) return null;\n return {\n id: raw.id,\n type: raw.type,\n workspaceId: raw.workspaceId,\n attributes: raw.attributeMap as Invoker[\"attributes\"],\n attributeList: raw.attributes as Invoker[\"attributeList\"],\n };\n}\n\n/** Runtime wrapper namespace for `tailor.context`. */\nexport const context = { getInvoker } as const satisfies TailorContextAPI;\n"],"mappings":"AAiEA,SAAS,YAA6B,CACpC,IAAM,EACJ,WACA,OAAO,QAAQ,WAAW,EAE5B,OADK,EACE,CACL,GAAI,EAAI,GACR,KAAM,EAAI,KACV,YAAa,EAAI,YACjB,WAAY,EAAI,aAChB,cAAe,EAAI,UACrB,EAPiB,IAQnB,CAGA,MAAa,EAAU,CAAE,UAAW"}
@@ -0,0 +1,42 @@
1
+ import{n as e}from"./logger-CCjs1DuH.mjs";import{t}from"./package-json-C690ceex.mjs";import{n}from"./user-agent-vdHYF3QL.mjs";import{r,t as i}from"./secret-file-C9wp_FCX.mjs";import*as a from"pathe";import*as o from"node:fs";import{parseYAML as s}from"confbox";import{xdgConfig as c}from"xdg-basedir";import*as l from"node:crypto";import{isCI as u}from"std-env";import*as d from"node:os";function parseCrashReportConfig(){if(u)return{localEnabled:!1,remoteEnabled:!1,localDir:``};let e=(process.env.TAILOR_CRASH_REPORTS_LOCAL??`on`).toLowerCase()!==`off`,t=(process.env.TAILOR_CRASH_REPORTS_REMOTE??`off`).toLowerCase()===`on`,n=c?a.join(c,`tailor-platform`,`crash-reports`):``;return{localEnabled:e&&n!==``,remoteEnabled:t,localDir:n}}const f=`--- JSON ---`,p=`.crash.log`;function formatCrashReport(e){return[`Crash Report: ${e.id}`,`Timestamp: ${e.timestamp}`,`Error Type: ${e.errorType}`,``,`--- Environment ---`,`SDK Version: ${e.sdkVersion}`,`Node Version: ${e.nodeVersion}`,`OS: ${e.osPlatform} ${e.osRelease}`,`Arch: ${e.arch}`,``,`--- Command ---`,`Command: ${e.command}`,`Arguments: ${JSON.stringify(e.argv)}`,``,`--- Error ---`,`Name: ${e.errorName}`,`Message: ${e.errorMessage}`,``,`--- Stack Trace ---`,e.stackTrace||`(no stack trace available)`,``,f,JSON.stringify(e),``].join(`
2
+ `)}function generateFilename(e){return`${e.timestamp.replace(/[:.]/g,`-`)}-${e.id.slice(0,8)}${p}`}function cleanupOldFiles(e){try{let t=o.readdirSync(e).filter(e=>e.endsWith(p)).toSorted().toReversed();for(let n of t.slice(10))o.unlinkSync(a.join(e,n))}catch{}}function writeCrashReport(e,t){try{i(t);let n=generateFilename(e),o=a.join(t,n),s=formatCrashReport(e);return r(o,s),cleanupOldFiles(t),o}catch{return}}async function sendCrashReport(e,t){try{let n=process.env.TAILOR_CRASH_REPORT_ENDPOINT||`https://sdk-error-tracking-926vh9t4cl.erp.dev/query`,r=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`,"User-Agent":t},body:JSON.stringify({query:`
3
+ mutation SubmitCrashReport(
4
+ $id: String!
5
+ $timestamp: String!
6
+ $sdkVersion: String!
7
+ $nodeVersion: String!
8
+ $osPlatform: String!
9
+ $osRelease: String!
10
+ $arch: String!
11
+ $command: String!
12
+ $argv: [String]
13
+ $errorName: String!
14
+ $errorMessage: String!
15
+ $stackTrace: String
16
+ $errorType: String!
17
+ $userId: String
18
+ $userEmail: String
19
+ ) {
20
+ submitCrashReport(
21
+ id: $id
22
+ timestamp: $timestamp
23
+ sdkVersion: $sdkVersion
24
+ nodeVersion: $nodeVersion
25
+ osPlatform: $osPlatform
26
+ osRelease: $osRelease
27
+ arch: $arch
28
+ command: $command
29
+ argv: $argv
30
+ errorName: $errorName
31
+ errorMessage: $errorMessage
32
+ stackTrace: $stackTrace
33
+ errorType: $errorType
34
+ userId: $userId
35
+ userEmail: $userEmail
36
+ ) {
37
+ success
38
+ }
39
+ }`,variables:e}),signal:AbortSignal.timeout(5e3)});if(!r.ok)return!1;let i=await r.json();return!i.errors?.length&&i.data?.submitCrashReport.success===!0}catch{return!1}}const m=d.homedir(),h=/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,g=/\b[0-9a-fA-F]{32,}\b/g,_=/\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b/g,v=/(?:\/(?:[\w.@\- ]+\/)+[\w.@\- ]+)/g,y=/(?:[A-Za-z]:\\(?:[\w.@\- ]+\\)+[\w.@\- ]+)/g,b=/[?&][^?\s]*/g,x=/\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b/,S=/^[A-Za-z]:\\/,C=`packages/sdk/`;function lastSegment(e,t){return e.split(t).pop()??e}function sanitizeStackTrace(e){let t=e.search(/\n\s+at /),n;return n=t===-1?sanitizeMessage(e):sanitizeMessage(e.slice(0,t))+e.slice(t),n=n.replace(v,e=>{let t=e.indexOf(C);return t===-1?e.startsWith(m)?`~/<redacted>/${lastSegment(e,`/`)}`:`<external>/${lastSegment(e,`/`)}`:e.slice(t)}),n=n.replace(y,e=>{let t=e.replace(/\\/g,`/`),n=t.indexOf(C);return n===-1?`<external>/${lastSegment(e,`\\`)}`:t.slice(n)}),n}function sanitizeMessage(e){let t=e;return t=t.replace(/\nRequest:\s*[\s\S]*$/,`
40
+ Request: <redacted>`),t=t.replace(h,`<uuid>`),t=t.replace(g,`<redacted>`),t=t.replace(_,`<email>`),t=t.replace(b,`?<redacted>`),t=t.replace(v,e=>`<path>/${lastSegment(e,`/`)}`),t=t.replace(y,e=>`<path>/${lastSegment(e,`\\`)}`),t}function sanitizeArgv(e){let t=[],n=!1;for(let r of e){if(n){if(!r.startsWith(`-`)){t.push(`<redacted>`),n=!1;continue}n=!1}if(r.startsWith(`-`)){let e=r.indexOf(`=`);if(e!==-1){t.push(`${r.slice(0,e)}=<redacted>`);continue}t.push(r),n=!0;continue}if(r.startsWith(`/`)&&r.includes(`/`,1)){t.push(`<path>`);continue}if(S.test(r)){t.push(`<path>`);continue}if(x.test(r)){t.push(`<email>`);continue}t.push(r)}return t}function parseCommand(){let e=process.argv.slice(2),t=[];for(let n of e){if(n.startsWith(`-`)||t.length>=3)break;t.push(n)}return t.join(` `)||`<unknown>`}function buildCrashReport(e){let{error:t,sdkVersion:n,errorType:r}=e,i=t instanceof Error,a=i?t.message:String(t),o=i&&t.stack?t.stack:``,s=i?t.name:`UnknownError`,c=readCurrentUser();return{id:l.randomUUID(),timestamp:new Date().toISOString(),sdkVersion:n,nodeVersion:process.version,osPlatform:process.platform,osRelease:d.release(),arch:process.arch,command:sanitizeMessage(parseCommand()),argv:sanitizeArgv(process.argv),errorName:s,errorMessage:sanitizeMessage(a),stackTrace:sanitizeStackTrace(o),errorType:r,userId:c?.id??null,userEmail:c?.email??null}}function readCurrentUser(){try{if(!c)return null;let e=a.join(c,`tailor-platform`,`config.yaml`);if(!o.existsSync(e))return null;let t=s(o.readFileSync(e,`utf-8`)),n=t?.current_user??null;if(!n)return null;let r=t.users?.[n]?.email;return{id:n,email:typeof r==`string`?r:legacyEmail(n)}}catch{return null}}function legacyEmail(e){return e.includes(`@`)?e:null}async function reportCrash(r,i){try{let a=parseCrashReportConfig();if(!a.localEnabled&&!a.remoteEnabled)return;let o=(await t()).version??`unknown`,s=buildCrashReport({error:r,sdkVersion:o,errorType:i});if(a.localEnabled){let t=writeCrashReport(s,a.localDir);t&&e.log([``,`An unexpected error occurred. A crash report has been saved to:`,` ${t}`,``,`To submit this report:`,` tailor crashreport send --file "${t}"`].join(`
41
+ `))}a.remoteEnabled&&await sendCrashReport(s,n(o))}catch{}}function initCrashReporting(){let t=parseCrashReportConfig();if(!t.localEnabled&&!t.remoteEnabled)return;let handleFatal=(t,n)=>{let r=t instanceof Error?t.message:String(t);e.error(r),reportCrash(t,n).finally(()=>{process.exit(1)})};process.on(`uncaughtException`,e=>handleFatal(e,`uncaughtException`)),process.on(`unhandledRejection`,e=>handleFatal(e,`unhandledRejection`))}export{f as a,p as i,reportCrash as n,parseCrashReportConfig as o,sendCrashReport as r,initCrashReporting as t};
42
+ //# sourceMappingURL=crashreport-BN28xp5B.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"crashreport-Q0pDAlrj.mjs","names":[],"sources":["../src/cli/crashreport/config.ts","../src/cli/crashreport/writer.ts","../src/cli/crashreport/sender.ts","../src/cli/crashreport/sanitize.ts","../src/cli/crashreport/report.ts","../src/cli/crashreport/index.ts"],"sourcesContent":["import * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { xdgConfig } from \"xdg-basedir\";\n\nexport interface CrashReportConfig {\n readonly localEnabled: boolean;\n readonly remoteEnabled: boolean;\n readonly localDir: string;\n}\n\n/**\n * Parse crash report configuration from environment variables.\n * Local crash log writing is enabled by default (opt-out via TAILOR_CRASH_REPORTS_LOCAL=off).\n * Remote sending is disabled by default (opt-in via TAILOR_CRASH_REPORTS_REMOTE=on).\n * Both are auto-disabled in CI environments.\n * @returns Crash report configuration\n */\nexport function parseCrashReportConfig(): CrashReportConfig {\n if (isCI) {\n return {\n localEnabled: false,\n remoteEnabled: false,\n localDir: \"\",\n };\n }\n\n const localEnabled = (process.env.TAILOR_CRASH_REPORTS_LOCAL ?? \"on\").toLowerCase() !== \"off\";\n const remoteEnabled = (process.env.TAILOR_CRASH_REPORTS_REMOTE ?? \"off\").toLowerCase() === \"on\";\n const localDir = xdgConfig ? path.join(xdgConfig, \"tailor-platform\", \"crash-reports\") : \"\";\n\n return {\n localEnabled: localEnabled && localDir !== \"\",\n remoteEnabled,\n localDir,\n };\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { ensureSecretDir, writeSecretFile } from \"#/cli/shared/secret-file\";\nimport type { CrashReport } from \"./report\";\n\nconst MAX_CRASH_FILES = 10;\n\n/** Marker line that separates human-readable content from the JSON footer. */\nexport const JSON_FOOTER_MARKER = \"--- JSON ---\";\n\n/** File extension for crash log files. */\nexport const CRASH_LOG_EXTENSION = \".crash.log\";\n\n/**\n * Format a CrashReport as human-readable text for local crash log files.\n * @param report - Crash report to format\n * @returns Formatted text content\n */\nexport function formatCrashReport(report: CrashReport): string {\n const lines = [\n `Crash Report: ${report.id}`,\n `Timestamp: ${report.timestamp}`,\n `Error Type: ${report.errorType}`,\n \"\",\n \"--- Environment ---\",\n `SDK Version: ${report.sdkVersion}`,\n `Node Version: ${report.nodeVersion}`,\n `OS: ${report.osPlatform} ${report.osRelease}`,\n `Arch: ${report.arch}`,\n \"\",\n \"--- Command ---\",\n `Command: ${report.command}`,\n `Arguments: ${JSON.stringify(report.argv)}`,\n \"\",\n \"--- Error ---\",\n `Name: ${report.errorName}`,\n `Message: ${report.errorMessage}`,\n \"\",\n \"--- Stack Trace ---\",\n report.stackTrace || \"(no stack trace available)\",\n \"\",\n JSON_FOOTER_MARKER,\n JSON.stringify(report),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a filename for a crash log file.\n * Format: {timestamp}-{shortId}.crash.log\n * @param report - Crash report to generate filename for\n * @returns Filename string\n */\nfunction generateFilename(report: CrashReport): string {\n const safeTimestamp = report.timestamp.replace(/[:.]/g, \"-\");\n const shortId = report.id.slice(0, 8);\n return `${safeTimestamp}-${shortId}${CRASH_LOG_EXTENSION}`;\n}\n\n/**\n * Remove old crash log files, keeping only the most recent ones.\n * @param dir - Crash log directory\n */\nfunction cleanupOldFiles(dir: string): void {\n try {\n const files = fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(CRASH_LOG_EXTENSION))\n .toSorted()\n .toReversed();\n\n for (const file of files.slice(MAX_CRASH_FILES)) {\n fs.unlinkSync(path.join(dir, file));\n }\n } catch {\n // Best-effort cleanup, ignore errors\n }\n}\n\n/**\n * Write a crash report to a local file.\n * Creates the directory if it doesn't exist. Keeps only the last 10 crash files.\n * Never throws - returns the file path on success or undefined on failure.\n * @param report - Crash report to write\n * @param dir - Directory to write the crash log file to\n * @returns File path on success, undefined on failure\n */\nexport function writeCrashReport(report: CrashReport, dir: string): string | undefined {\n try {\n ensureSecretDir(dir);\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n writeSecretFile(filePath, content);\n cleanupOldFiles(dir);\n\n return filePath;\n } catch {\n return undefined;\n }\n}\n","import type { CrashReport } from \"./report\";\n\nconst SEND_TIMEOUT_MS = 5000;\nconst PRODUCTION_ENDPOINT = \"https://sdk-error-tracking-926vh9t4cl.erp.dev/query\";\n\nconst SUBMIT_MUTATION = `\nmutation SubmitCrashReport(\n $id: String!\n $timestamp: String!\n $sdkVersion: String!\n $nodeVersion: String!\n $osPlatform: String!\n $osRelease: String!\n $arch: String!\n $command: String!\n $argv: [String]\n $errorName: String!\n $errorMessage: String!\n $stackTrace: String\n $errorType: String!\n $userId: String\n $userEmail: String\n) {\n submitCrashReport(\n id: $id\n timestamp: $timestamp\n sdkVersion: $sdkVersion\n nodeVersion: $nodeVersion\n osPlatform: $osPlatform\n osRelease: $osRelease\n arch: $arch\n command: $command\n argv: $argv\n errorName: $errorName\n errorMessage: $errorMessage\n stackTrace: $stackTrace\n errorType: $errorType\n userId: $userId\n userEmail: $userEmail\n ) {\n success\n }\n}`;\n\n/**\n * Send a crash report to the remote endpoint via GraphQL mutation.\n * Best-effort: never throws, returns boolean success.\n * @param report - Crash report to send\n * @param ua - User-Agent header value\n * @returns true if the request succeeded, false otherwise\n */\nexport async function sendCrashReport(report: CrashReport, ua: string): Promise<boolean> {\n try {\n const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": ua,\n },\n body: JSON.stringify({\n query: SUBMIT_MUTATION,\n variables: report,\n }),\n signal: AbortSignal.timeout(SEND_TIMEOUT_MS),\n });\n\n if (!response.ok) return false;\n\n const data = (await response.json()) as {\n errors?: unknown[];\n data?: { submitCrashReport: { success: boolean } };\n };\n if (data.errors?.length) return false;\n return data.data?.submitCrashReport.success === true;\n } catch {\n return false;\n }\n}\n","import * as os from \"node:os\";\n\nconst HOME_DIR = os.homedir();\n\n// Patterns for sanitization (global variants for use with .replace())\nconst UUID_PATTERN = /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi;\nconst LONG_HEX_PATTERN = /\\b[0-9a-fA-F]{32,}\\b/g;\nconst EMAIL_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g;\nconst ABSOLUTE_PATH_PATTERN = /(?:\\/(?:[\\w.@\\- ]+\\/)+[\\w.@\\- ]+)/g;\nconst WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:\\\\(?:[\\w.@\\- ]+\\\\)+[\\w.@\\- ]+)/g;\nconst URL_QUERY_PATTERN = /[?&][^?\\s]*/g;\n\n// Non-global variants for single-match .test() calls (avoids lastIndex state issues)\nconst EMAIL_TEST_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/;\nconst WINDOWS_DRIVE_TEST_PATTERN = /^[A-Za-z]:\\\\/;\n\n// SDK package path marker for relative paths\nconst SDK_PACKAGE_MARKER = \"packages/sdk/\";\n\nfunction lastSegment(filePath: string, separator: string): string {\n return filePath.split(separator).pop() ?? filePath;\n}\n\n/**\n * Sanitize a stack trace by replacing absolute paths with relative SDK paths.\n * External paths are replaced with `<external>/filename.ext`.\n * Home directories are replaced with `~/<redacted>/`.\n * @param stack - Raw stack trace string\n * @returns Sanitized stack trace\n */\nexport function sanitizeStackTrace(stack: string): string {\n // V8 stack traces start with \"ErrorType: message\\n at ...\".\n // The error message may span multiple lines before the first \" at \" frame.\n // Apply message sanitization to all message lines so secrets embedded in\n // multiline error messages are redacted consistently with errorMessage.\n const firstFrameIndex = stack.search(/\\n\\s+at /);\n let result: string;\n if (firstFrameIndex !== -1) {\n result = sanitizeMessage(stack.slice(0, firstFrameIndex)) + stack.slice(firstFrameIndex);\n } else {\n result = sanitizeMessage(stack);\n }\n\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => {\n const sdkIndex = match.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return match.slice(sdkIndex);\n }\n\n if (match.startsWith(HOME_DIR)) {\n return `~/<redacted>/${lastSegment(match, \"/\")}`;\n }\n\n return `<external>/${lastSegment(match, \"/\")}`;\n });\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => {\n const normalized = match.replace(/\\\\/g, \"/\");\n const sdkIndex = normalized.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return normalized.slice(sdkIndex);\n }\n return `<external>/${lastSegment(match, \"\\\\\")}`;\n });\n return result;\n}\n\n/**\n * Sanitize an error message by redacting sensitive information.\n * Redacts: UUIDs, long hex tokens, email addresses, absolute paths, URL query strings.\n * @param message - Raw error message\n * @returns Sanitized error message\n */\nexport function sanitizeMessage(message: string): string {\n let result = message;\n // Strip serialized request/response bodies that may contain secrets\n result = result.replace(/\\nRequest:\\s*[\\s\\S]*$/, \"\\nRequest: <redacted>\");\n result = result.replace(UUID_PATTERN, \"<uuid>\");\n result = result.replace(LONG_HEX_PATTERN, \"<redacted>\");\n result = result.replace(EMAIL_PATTERN, \"<email>\");\n result = result.replace(URL_QUERY_PATTERN, \"?<redacted>\");\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"/\")}`);\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"\\\\\")}`);\n\n return result;\n}\n\n/**\n * Sanitize process.argv by keeping command/subcommand names and redacting\n * values of sensitive flags.\n * @param argv - Raw process.argv array\n * @returns Sanitized argv array\n */\nexport function sanitizeArgv(argv: string[]): string[] {\n const result: string[] = [];\n let redactNext = false;\n\n for (const arg of argv) {\n if (redactNext) {\n // If the next token is itself a flag, treat it as a new flag rather\n // than consuming it as the previous flag's value. This avoids leaking\n // the *next* flag's value (e.g., `--verbose --workspace-id secret`\n // would otherwise expose `secret`).\n if (!arg.startsWith(\"-\")) {\n result.push(\"<redacted>\");\n redactNext = false;\n continue;\n }\n redactNext = false;\n }\n\n if (arg.startsWith(\"-\")) {\n // --flag=value: keep flag name, redact value\n const eqIndex = arg.indexOf(\"=\");\n if (eqIndex !== -1) {\n result.push(`${arg.slice(0, eqIndex)}=<redacted>`);\n continue;\n }\n\n // --flag / -f: keep flag name, redact next arg as its value\n result.push(arg);\n redactNext = true;\n continue;\n }\n\n // Redact absolute paths\n if (arg.startsWith(\"/\") && arg.includes(\"/\", 1)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact Windows-style absolute paths\n if (WINDOWS_DRIVE_TEST_PATTERN.test(arg)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact email addresses\n if (EMAIL_TEST_PATTERN.test(arg)) {\n result.push(\"<email>\");\n continue;\n }\n\n result.push(arg);\n }\n\n return result;\n}\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport { parseYAML } from \"confbox\";\nimport * as path from \"pathe\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { sanitizeArgv, sanitizeMessage, sanitizeStackTrace } from \"./sanitize\";\n\nexport type ErrorType = \"uncaughtException\" | \"unhandledRejection\" | \"handledError\";\n\nexport interface CrashReport {\n id: string;\n timestamp: string;\n sdkVersion: string;\n nodeVersion: string;\n osPlatform: string;\n osRelease: string;\n arch: string;\n command: string;\n argv: string[];\n errorName: string;\n errorMessage: string;\n stackTrace: string;\n errorType: ErrorType;\n userId: string | null;\n userEmail: string | null;\n}\n\ninterface BuildCrashReportOptions {\n error: unknown;\n sdkVersion: string;\n errorType: ErrorType;\n}\n\n// Maximum subcommand depth to keep (e.g., \"tailordb migrate generate\" = 3 tokens).\n// Positional arguments beyond this are potentially sensitive user input.\n// Accepted trade-off: plain-text positional args that don't match known patterns\n// (UUIDs, hex tokens, emails, paths) pass through to `command` and `argv`.\n// Full redaction would require embedding the CLI command tree here, which is fragile.\nconst MAX_COMMAND_TOKENS = 3;\n\n/**\n * Parse the command name from process.argv.\n * Extracts up to MAX_COMMAND_TOKENS non-flag arguments after the script name.\n * @returns Parsed command string\n */\nfunction parseCommand(): string {\n const args = process.argv.slice(2);\n const commandParts: string[] = [];\n for (const arg of args) {\n if (arg.startsWith(\"-\") || commandParts.length >= MAX_COMMAND_TOKENS) break;\n commandParts.push(arg);\n }\n return commandParts.join(\" \") || \"<unknown>\";\n}\n\n/**\n * Build a CrashReport data structure from an error and context.\n * All sensitive data is sanitized before inclusion.\n * @param options - Error, SDK version, and crash type\n * @returns Sanitized crash report\n */\nexport function buildCrashReport(options: BuildCrashReportOptions): CrashReport {\n const { error, sdkVersion, errorType } = options;\n\n const isError = error instanceof Error;\n const rawMessage = isError ? error.message : String(error);\n const rawStack = isError && error.stack ? error.stack : \"\";\n const errorName = isError ? error.name : \"UnknownError\";\n\n const currentUser = readCurrentUser();\n\n return {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n sdkVersion,\n nodeVersion: process.version,\n osPlatform: process.platform,\n osRelease: os.release(),\n arch: process.arch,\n command: sanitizeMessage(parseCommand()),\n argv: sanitizeArgv(process.argv),\n errorName,\n errorMessage: sanitizeMessage(rawMessage),\n stackTrace: sanitizeStackTrace(rawStack),\n errorType,\n userId: currentUser?.id ?? null,\n userEmail: currentUser?.email ?? null,\n };\n}\n\ntype CurrentUser = {\n id: string;\n email: string | null;\n};\n\n/**\n * Read current_user from Tailor Platform config without side effects.\n * Unlike readPlatformConfig(), this never triggers migration or logs warnings.\n * @returns The current user ID and email, or null if unavailable\n */\nfunction readCurrentUser(): CurrentUser | null {\n try {\n if (!xdgConfig) return null;\n const configPath = path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n if (!fs.existsSync(configPath)) return null;\n const raw = parseYAML(fs.readFileSync(configPath, \"utf-8\")) as {\n current_user?: string | null;\n users?: Record<string, { email?: unknown } | undefined>;\n };\n // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n const currentUser = raw?.current_user ?? null;\n if (!currentUser) return null;\n const email = raw.users?.[currentUser]?.email;\n return {\n id: currentUser,\n email: typeof email === \"string\" ? email : legacyEmail(currentUser),\n };\n } catch {\n return null;\n }\n}\n\nfunction legacyEmail(user: string): string | null {\n return user.includes(\"@\") ? user : null;\n}\n","import { logger } from \"#/cli/shared/logger\";\nimport { readPackageJson } from \"#/cli/shared/package-json\";\nimport { userAgentFromVersion } from \"#/cli/shared/user-agent\";\nimport { parseCrashReportConfig } from \"./config\";\nimport { buildCrashReport, type ErrorType } from \"./report\";\nimport { sendCrashReport } from \"./sender\";\nimport { writeCrashReport } from \"./writer\";\n\n/**\n * Report an unexpected crash. Writes a local crash log file and optionally\n * sends the report to a remote endpoint. Displays a user-facing message\n * with the crash log path and a command to submit the report.\n *\n * Never throws - all errors are silently caught.\n * @param error - The error that caused the crash\n * @param errorType - How the error was caught\n */\nexport async function reportCrash(error: unknown, errorType: ErrorType): Promise<void> {\n try {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"unknown\";\n\n const report = buildCrashReport({ error, sdkVersion, errorType });\n\n if (config.localEnabled) {\n const filePath = writeCrashReport(report, config.localDir);\n if (filePath) {\n logger.log(\n [\n \"\",\n \"An unexpected error occurred. A crash report has been saved to:\",\n ` ${filePath}`,\n \"\",\n \"To submit this report:\",\n ` tailor crashreport send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n const ua = userAgentFromVersion(sdkVersion);\n await sendCrashReport(report, ua);\n }\n } catch {\n // Never throw from crash reporting\n }\n}\n\n/**\n * Register global uncaughtException and unhandledRejection handlers.\n * These catch errors outside the normal cleanup flow (e.g., during\n * argument parsing). Should be called once at CLI startup before runMain.\n */\nexport function initCrashReporting(): void {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const handleFatal = (error: unknown, errorType: ErrorType) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n void reportCrash(error, errorType).finally(() => {\n process.exit(1);\n });\n };\n\n process.on(\"uncaughtException\", (error) => handleFatal(error, \"uncaughtException\"));\n process.on(\"unhandledRejection\", (reason) => handleFatal(reason, \"unhandledRejection\"));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"crashreport-BN28xp5B.mjs","names":[],"sources":["../src/cli/crashreport/config.ts","../src/cli/crashreport/writer.ts","../src/cli/crashreport/sender.ts","../src/cli/crashreport/sanitize.ts","../src/cli/crashreport/report.ts","../src/cli/crashreport/index.ts"],"sourcesContent":["import * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { xdgConfig } from \"xdg-basedir\";\n\nexport interface CrashReportConfig {\n readonly localEnabled: boolean;\n readonly remoteEnabled: boolean;\n readonly localDir: string;\n}\n\n/**\n * Parse crash report configuration from environment variables.\n * Local crash log writing is enabled by default (opt-out via TAILOR_CRASH_REPORTS_LOCAL=off).\n * Remote sending is disabled by default (opt-in via TAILOR_CRASH_REPORTS_REMOTE=on).\n * Both are auto-disabled in CI environments.\n * @returns Crash report configuration\n */\nexport function parseCrashReportConfig(): CrashReportConfig {\n if (isCI) {\n return {\n localEnabled: false,\n remoteEnabled: false,\n localDir: \"\",\n };\n }\n\n const localEnabled = (process.env.TAILOR_CRASH_REPORTS_LOCAL ?? \"on\").toLowerCase() !== \"off\";\n const remoteEnabled = (process.env.TAILOR_CRASH_REPORTS_REMOTE ?? \"off\").toLowerCase() === \"on\";\n const localDir = xdgConfig ? path.join(xdgConfig, \"tailor-platform\", \"crash-reports\") : \"\";\n\n return {\n localEnabled: localEnabled && localDir !== \"\",\n remoteEnabled,\n localDir,\n };\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { ensureSecretDir, writeSecretFile } from \"#/cli/shared/secret-file\";\nimport type { CrashReport } from \"./report\";\n\nconst MAX_CRASH_FILES = 10;\n\n/** Marker line that separates human-readable content from the JSON footer. */\nexport const JSON_FOOTER_MARKER = \"--- JSON ---\";\n\n/** File extension for crash log files. */\nexport const CRASH_LOG_EXTENSION = \".crash.log\";\n\n/**\n * Format a CrashReport as human-readable text for local crash log files.\n * @param report - Crash report to format\n * @returns Formatted text content\n */\nexport function formatCrashReport(report: CrashReport): string {\n const lines = [\n `Crash Report: ${report.id}`,\n `Timestamp: ${report.timestamp}`,\n `Error Type: ${report.errorType}`,\n \"\",\n \"--- Environment ---\",\n `SDK Version: ${report.sdkVersion}`,\n `Node Version: ${report.nodeVersion}`,\n `OS: ${report.osPlatform} ${report.osRelease}`,\n `Arch: ${report.arch}`,\n \"\",\n \"--- Command ---\",\n `Command: ${report.command}`,\n `Arguments: ${JSON.stringify(report.argv)}`,\n \"\",\n \"--- Error ---\",\n `Name: ${report.errorName}`,\n `Message: ${report.errorMessage}`,\n \"\",\n \"--- Stack Trace ---\",\n report.stackTrace || \"(no stack trace available)\",\n \"\",\n JSON_FOOTER_MARKER,\n JSON.stringify(report),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a filename for a crash log file.\n * Format: {timestamp}-{shortId}.crash.log\n * @param report - Crash report to generate filename for\n * @returns Filename string\n */\nfunction generateFilename(report: CrashReport): string {\n const safeTimestamp = report.timestamp.replace(/[:.]/g, \"-\");\n const shortId = report.id.slice(0, 8);\n return `${safeTimestamp}-${shortId}${CRASH_LOG_EXTENSION}`;\n}\n\n/**\n * Remove old crash log files, keeping only the most recent ones.\n * @param dir - Crash log directory\n */\nfunction cleanupOldFiles(dir: string): void {\n try {\n const files = fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(CRASH_LOG_EXTENSION))\n .toSorted()\n .toReversed();\n\n for (const file of files.slice(MAX_CRASH_FILES)) {\n fs.unlinkSync(path.join(dir, file));\n }\n } catch {\n // Best-effort cleanup, ignore errors\n }\n}\n\n/**\n * Write a crash report to a local file.\n * Creates the directory if it doesn't exist. Keeps only the last 10 crash files.\n * Never throws - returns the file path on success or undefined on failure.\n * @param report - Crash report to write\n * @param dir - Directory to write the crash log file to\n * @returns File path on success, undefined on failure\n */\nexport function writeCrashReport(report: CrashReport, dir: string): string | undefined {\n try {\n ensureSecretDir(dir);\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n writeSecretFile(filePath, content);\n cleanupOldFiles(dir);\n\n return filePath;\n } catch {\n return undefined;\n }\n}\n","import type { CrashReport } from \"./report\";\n\nconst SEND_TIMEOUT_MS = 5000;\nconst PRODUCTION_ENDPOINT = \"https://sdk-error-tracking-926vh9t4cl.erp.dev/query\";\n\nconst SUBMIT_MUTATION = `\nmutation SubmitCrashReport(\n $id: String!\n $timestamp: String!\n $sdkVersion: String!\n $nodeVersion: String!\n $osPlatform: String!\n $osRelease: String!\n $arch: String!\n $command: String!\n $argv: [String]\n $errorName: String!\n $errorMessage: String!\n $stackTrace: String\n $errorType: String!\n $userId: String\n $userEmail: String\n) {\n submitCrashReport(\n id: $id\n timestamp: $timestamp\n sdkVersion: $sdkVersion\n nodeVersion: $nodeVersion\n osPlatform: $osPlatform\n osRelease: $osRelease\n arch: $arch\n command: $command\n argv: $argv\n errorName: $errorName\n errorMessage: $errorMessage\n stackTrace: $stackTrace\n errorType: $errorType\n userId: $userId\n userEmail: $userEmail\n ) {\n success\n }\n}`;\n\n/**\n * Send a crash report to the remote endpoint via GraphQL mutation.\n * Best-effort: never throws, returns boolean success.\n * @param report - Crash report to send\n * @param ua - User-Agent header value\n * @returns true if the request succeeded, false otherwise\n */\nexport async function sendCrashReport(report: CrashReport, ua: string): Promise<boolean> {\n try {\n const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": ua,\n },\n body: JSON.stringify({\n query: SUBMIT_MUTATION,\n variables: report,\n }),\n signal: AbortSignal.timeout(SEND_TIMEOUT_MS),\n });\n\n if (!response.ok) return false;\n\n const data = (await response.json()) as {\n errors?: unknown[];\n data?: { submitCrashReport: { success: boolean } };\n };\n if (data.errors?.length) return false;\n return data.data?.submitCrashReport.success === true;\n } catch {\n return false;\n }\n}\n","import * as os from \"node:os\";\n\nconst HOME_DIR = os.homedir();\n\n// Patterns for sanitization (global variants for use with .replace())\nconst UUID_PATTERN = /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi;\nconst LONG_HEX_PATTERN = /\\b[0-9a-fA-F]{32,}\\b/g;\nconst EMAIL_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g;\nconst ABSOLUTE_PATH_PATTERN = /(?:\\/(?:[\\w.@\\- ]+\\/)+[\\w.@\\- ]+)/g;\nconst WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:\\\\(?:[\\w.@\\- ]+\\\\)+[\\w.@\\- ]+)/g;\nconst URL_QUERY_PATTERN = /[?&][^?\\s]*/g;\n\n// Non-global variants for single-match .test() calls (avoids lastIndex state issues)\nconst EMAIL_TEST_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/;\nconst WINDOWS_DRIVE_TEST_PATTERN = /^[A-Za-z]:\\\\/;\n\n// SDK package path marker for relative paths\nconst SDK_PACKAGE_MARKER = \"packages/sdk/\";\n\nfunction lastSegment(filePath: string, separator: string): string {\n return filePath.split(separator).pop() ?? filePath;\n}\n\n/**\n * Sanitize a stack trace by replacing absolute paths with relative SDK paths.\n * External paths are replaced with `<external>/filename.ext`.\n * Home directories are replaced with `~/<redacted>/`.\n * @param stack - Raw stack trace string\n * @returns Sanitized stack trace\n */\nexport function sanitizeStackTrace(stack: string): string {\n // V8 stack traces start with \"ErrorType: message\\n at ...\".\n // The error message may span multiple lines before the first \" at \" frame.\n // Apply message sanitization to all message lines so secrets embedded in\n // multiline error messages are redacted consistently with errorMessage.\n const firstFrameIndex = stack.search(/\\n\\s+at /);\n let result: string;\n if (firstFrameIndex !== -1) {\n result = sanitizeMessage(stack.slice(0, firstFrameIndex)) + stack.slice(firstFrameIndex);\n } else {\n result = sanitizeMessage(stack);\n }\n\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => {\n const sdkIndex = match.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return match.slice(sdkIndex);\n }\n\n if (match.startsWith(HOME_DIR)) {\n return `~/<redacted>/${lastSegment(match, \"/\")}`;\n }\n\n return `<external>/${lastSegment(match, \"/\")}`;\n });\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => {\n const normalized = match.replace(/\\\\/g, \"/\");\n const sdkIndex = normalized.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return normalized.slice(sdkIndex);\n }\n return `<external>/${lastSegment(match, \"\\\\\")}`;\n });\n return result;\n}\n\n/**\n * Sanitize an error message by redacting sensitive information.\n * Redacts: UUIDs, long hex tokens, email addresses, absolute paths, URL query strings.\n * @param message - Raw error message\n * @returns Sanitized error message\n */\nexport function sanitizeMessage(message: string): string {\n let result = message;\n // Strip serialized request/response bodies that may contain secrets\n result = result.replace(/\\nRequest:\\s*[\\s\\S]*$/, \"\\nRequest: <redacted>\");\n result = result.replace(UUID_PATTERN, \"<uuid>\");\n result = result.replace(LONG_HEX_PATTERN, \"<redacted>\");\n result = result.replace(EMAIL_PATTERN, \"<email>\");\n result = result.replace(URL_QUERY_PATTERN, \"?<redacted>\");\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"/\")}`);\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"\\\\\")}`);\n\n return result;\n}\n\n/**\n * Sanitize process.argv by keeping command/subcommand names and redacting\n * values of sensitive flags.\n * @param argv - Raw process.argv array\n * @returns Sanitized argv array\n */\nexport function sanitizeArgv(argv: string[]): string[] {\n const result: string[] = [];\n let redactNext = false;\n\n for (const arg of argv) {\n if (redactNext) {\n // If the next token is itself a flag, treat it as a new flag rather\n // than consuming it as the previous flag's value. This avoids leaking\n // the *next* flag's value (e.g., `--verbose --workspace-id secret`\n // would otherwise expose `secret`).\n if (!arg.startsWith(\"-\")) {\n result.push(\"<redacted>\");\n redactNext = false;\n continue;\n }\n redactNext = false;\n }\n\n if (arg.startsWith(\"-\")) {\n // --flag=value: keep flag name, redact value\n const eqIndex = arg.indexOf(\"=\");\n if (eqIndex !== -1) {\n result.push(`${arg.slice(0, eqIndex)}=<redacted>`);\n continue;\n }\n\n // --flag / -f: keep flag name, redact next arg as its value\n result.push(arg);\n redactNext = true;\n continue;\n }\n\n // Redact absolute paths\n if (arg.startsWith(\"/\") && arg.includes(\"/\", 1)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact Windows-style absolute paths\n if (WINDOWS_DRIVE_TEST_PATTERN.test(arg)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact email addresses\n if (EMAIL_TEST_PATTERN.test(arg)) {\n result.push(\"<email>\");\n continue;\n }\n\n result.push(arg);\n }\n\n return result;\n}\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport { parseYAML } from \"confbox\";\nimport * as path from \"pathe\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { sanitizeArgv, sanitizeMessage, sanitizeStackTrace } from \"./sanitize\";\n\nexport type ErrorType = \"uncaughtException\" | \"unhandledRejection\" | \"handledError\";\n\nexport interface CrashReport {\n id: string;\n timestamp: string;\n sdkVersion: string;\n nodeVersion: string;\n osPlatform: string;\n osRelease: string;\n arch: string;\n command: string;\n argv: string[];\n errorName: string;\n errorMessage: string;\n stackTrace: string;\n errorType: ErrorType;\n userId: string | null;\n userEmail: string | null;\n}\n\ninterface BuildCrashReportOptions {\n error: unknown;\n sdkVersion: string;\n errorType: ErrorType;\n}\n\n// Maximum subcommand depth to keep (e.g., \"tailordb migrate generate\" = 3 tokens).\n// Positional arguments beyond this are potentially sensitive user input.\n// Accepted trade-off: plain-text positional args that don't match known patterns\n// (UUIDs, hex tokens, emails, paths) pass through to `command` and `argv`.\n// Full redaction would require embedding the CLI command tree here, which is fragile.\nconst MAX_COMMAND_TOKENS = 3;\n\n/**\n * Parse the command name from process.argv.\n * Extracts up to MAX_COMMAND_TOKENS non-flag arguments after the script name.\n * @returns Parsed command string\n */\nfunction parseCommand(): string {\n const args = process.argv.slice(2);\n const commandParts: string[] = [];\n for (const arg of args) {\n if (arg.startsWith(\"-\") || commandParts.length >= MAX_COMMAND_TOKENS) break;\n commandParts.push(arg);\n }\n return commandParts.join(\" \") || \"<unknown>\";\n}\n\n/**\n * Build a CrashReport data structure from an error and context.\n * All sensitive data is sanitized before inclusion.\n * @param options - Error, SDK version, and crash type\n * @returns Sanitized crash report\n */\nexport function buildCrashReport(options: BuildCrashReportOptions): CrashReport {\n const { error, sdkVersion, errorType } = options;\n\n const isError = error instanceof Error;\n const rawMessage = isError ? error.message : String(error);\n const rawStack = isError && error.stack ? error.stack : \"\";\n const errorName = isError ? error.name : \"UnknownError\";\n\n const currentUser = readCurrentUser();\n\n return {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n sdkVersion,\n nodeVersion: process.version,\n osPlatform: process.platform,\n osRelease: os.release(),\n arch: process.arch,\n command: sanitizeMessage(parseCommand()),\n argv: sanitizeArgv(process.argv),\n errorName,\n errorMessage: sanitizeMessage(rawMessage),\n stackTrace: sanitizeStackTrace(rawStack),\n errorType,\n userId: currentUser?.id ?? null,\n userEmail: currentUser?.email ?? null,\n };\n}\n\ntype CurrentUser = {\n id: string;\n email: string | null;\n};\n\n/**\n * Read current_user from Tailor Platform config without side effects.\n * Unlike readPlatformConfig(), this never triggers migration or logs warnings.\n * @returns The current user ID and email, or null if unavailable\n */\nfunction readCurrentUser(): CurrentUser | null {\n try {\n if (!xdgConfig) return null;\n const configPath = path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n if (!fs.existsSync(configPath)) return null;\n const raw = parseYAML(fs.readFileSync(configPath, \"utf-8\")) as {\n current_user?: string | null;\n users?: Record<string, { email?: unknown } | undefined>;\n };\n // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n const currentUser = raw?.current_user ?? null;\n if (!currentUser) return null;\n const email = raw.users?.[currentUser]?.email;\n return {\n id: currentUser,\n email: typeof email === \"string\" ? email : legacyEmail(currentUser),\n };\n } catch {\n return null;\n }\n}\n\nfunction legacyEmail(user: string): string | null {\n return user.includes(\"@\") ? user : null;\n}\n","import { logger } from \"#/cli/shared/logger\";\nimport { readPackageJson } from \"#/cli/shared/package-json\";\nimport { userAgentFromVersion } from \"#/cli/shared/user-agent\";\nimport { parseCrashReportConfig } from \"./config\";\nimport { buildCrashReport, type ErrorType } from \"./report\";\nimport { sendCrashReport } from \"./sender\";\nimport { writeCrashReport } from \"./writer\";\n\n/**\n * Report an unexpected crash. Writes a local crash log file and optionally\n * sends the report to a remote endpoint. Displays a user-facing message\n * with the crash log path and a command to submit the report.\n *\n * Never throws - all errors are silently caught.\n * @param error - The error that caused the crash\n * @param errorType - How the error was caught\n */\nexport async function reportCrash(error: unknown, errorType: ErrorType): Promise<void> {\n try {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"unknown\";\n\n const report = buildCrashReport({ error, sdkVersion, errorType });\n\n if (config.localEnabled) {\n const filePath = writeCrashReport(report, config.localDir);\n if (filePath) {\n logger.log(\n [\n \"\",\n \"An unexpected error occurred. A crash report has been saved to:\",\n ` ${filePath}`,\n \"\",\n \"To submit this report:\",\n ` tailor crashreport send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n const ua = userAgentFromVersion(sdkVersion);\n await sendCrashReport(report, ua);\n }\n } catch {\n // Never throw from crash reporting\n }\n}\n\n/**\n * Register global uncaughtException and unhandledRejection handlers.\n * These catch errors outside the normal cleanup flow (e.g., during\n * argument parsing). Should be called once at CLI startup before runMain.\n */\nexport function initCrashReporting(): void {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const handleFatal = (error: unknown, errorType: ErrorType) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n void reportCrash(error, errorType).finally(() => {\n process.exit(1);\n });\n };\n\n process.on(\"uncaughtException\", (error) => handleFatal(error, \"uncaughtException\"));\n process.on(\"unhandledRejection\", (reason) => handleFatal(reason, \"unhandledRejection\"));\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import{n as e}from"./crashreport-BN28xp5B.mjs";export{e as reportCrash};
@@ -0,0 +1,2 @@
1
+ import{r as e}from"./logger-CCjs1DuH.mjs";function shellQuote(e){return process.platform===`win32`?/^[A-Za-z0-9_./:=@+\\-]+$/.test(e)?e:`"${e.replaceAll(`"`,`\\"`)}"`:/^[A-Za-z0-9_./:=@+-]+$/.test(e)?e:`'${e.replaceAll(`'`,`'"'"'`)}'`}function needsArgvRendering(e){return process.platform===`win32`&&e.some(e=>/[%$!]/.test(e))}function formatCopyableCommand(e){return needsArgvRendering(e)?`argv ${JSON.stringify(e)}`:e.map(shellQuote).join(` `)}function formatNextAction(e){let t=[e.command,...e.args],n=formatCopyableCommand(t);return needsArgvRendering(t)?`with ${n}`:`\`${n}\``}function formatError(t){let n=[e.error(`Error${t.code?` [${t.code}]`:``}: ${t.message}`)];return t.details&&n.push(`\n ${e.dim(`Details:`)} ${t.details}`),t.suggestion&&n.push(`\n ${e.info(`Suggestion:`)} ${t.suggestion}`),t.command&&n.push(`\n ${e.dim(`Help:`)} Run \`tailor ${t.command} --help\` for usage information.`),t.next&&n.push(`\n ${e.info(`Next:`)} Run ${formatNextAction(t.next)}.`),n.join(``)}function createCLIError(e){let t=Error(e.message);return t.name=`CLIError`,t.code=e.code,t.details=e.details,t.suggestion=e.suggestion,t.command=e.command,t.next=e.next,t.context=e.context,t.format=()=>formatError(t),t}function isCLIError(e){return e instanceof Error&&e.name===`CLIError`}function toError(e){return e instanceof Error?e:Error(String(e))}const t=/does not provide an export named '(?!default')([^']+)'/;function typeOnlyImportHint(e){if(!(e instanceof SyntaxError))return;let n=t.exec(e.message)?.[1];if(n)return`If '${n}' is a type, import it with \`import type\` (or the inline \`type\` modifier). The CLI runs TypeScript by stripping types from each file in isolation, so type-only exports do not exist at runtime. Set "verbatimModuleSyntax": true in tsconfig.json to catch this at typecheck.`}export{toError as a,isCLIError as i,formatCopyableCommand as n,typeOnlyImportHint as o,formatNextAction as r,createCLIError as t};
2
+ //# sourceMappingURL=errors-DLsQ_-ol.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-DLsQ_-ol.mjs","names":[],"sources":["../src/cli/shared/errors.ts"],"sourcesContent":["import { styles } from \"./logger\";\n\n/**\n * Options for creating a CLI error\n */\ninterface CLIErrorOptions {\n message: string;\n details?: string;\n suggestion?: string;\n command?: string;\n code?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, unknown>>;\n}\n\nexport interface CLIErrorNextAction {\n /** Executable name, such as `tailor`. */\n command: string;\n /** Arguments passed directly to the executable. */\n args: readonly string[];\n}\n\n/**\n * CLI error interface with formatted output\n */\nexport interface CLIError extends Error {\n readonly code?: string;\n readonly details?: string;\n readonly suggestion?: string;\n readonly command?: string;\n readonly next?: CLIErrorNextAction;\n readonly context?: Readonly<Record<string, unknown>>;\n format(): string;\n}\n\ntype CLIErrorInternal = Error & {\n code?: string;\n details?: string;\n suggestion?: string;\n command?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, unknown>>;\n format(): string;\n};\n\nfunction shellQuote(value: string): string {\n if (process.platform === \"win32\") {\n if (/^[A-Za-z0-9_./:=@+\\\\-]+$/.test(value)) return value;\n return `\"${value.replaceAll('\"', '\\\\\"')}\"`;\n }\n if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nfunction needsArgvRendering(argv: readonly string[]): boolean {\n // cmd.exe/PowerShell expand %, $, and ! even inside double quotes, so no\n // quoting can keep such values literal on Windows.\n return process.platform === \"win32\" && argv.some((value) => /[%$!]/.test(value));\n}\n\n/**\n * Render an argv array as a copyable command line for the current platform's shell\n * @param {readonly string[]} argv - Executable name followed by its arguments\n * @returns {string} A shell-quoted command line, or an `argv [...]` JSON rendering when the platform shell cannot keep a value literal\n */\nexport function formatCopyableCommand(argv: readonly string[]): string {\n if (needsArgvRendering(argv)) {\n return `argv ${JSON.stringify(argv)}`;\n }\n return argv.map(shellQuote).join(\" \");\n}\n\n/**\n * Format an executable and argv as a shell-safe user-facing command.\n * @param next - Executable and arguments to format\n * @returns Shell command, or an argv representation when shell quoting is unsafe\n */\nexport function formatNextAction(next: CLIErrorNextAction): string {\n const argv = [next.command, ...next.args];\n const rendered = formatCopyableCommand(argv);\n return needsArgvRendering(argv) ? `with ${rendered}` : `\\`${rendered}\\``;\n}\n\n/**\n * Format CLI error for output\n * @param error - CLIError instance to format\n * @returns Formatted error message\n */\nfunction formatError(error: CLIError): string {\n const parts: string[] = [\n styles.error(`Error${error.code ? ` [${error.code}]` : \"\"}: ${error.message}`),\n ];\n\n if (error.details) {\n parts.push(`\\n ${styles.dim(\"Details:\")} ${error.details}`);\n }\n\n if (error.suggestion) {\n parts.push(`\\n ${styles.info(\"Suggestion:\")} ${error.suggestion}`);\n }\n\n if (error.command) {\n parts.push(\n `\\n ${styles.dim(\"Help:\")} Run \\`tailor ${error.command} --help\\` for usage information.`,\n );\n }\n\n if (error.next) {\n parts.push(`\\n ${styles.info(\"Next:\")} Run ${formatNextAction(error.next)}.`);\n }\n\n return parts.join(\"\");\n}\n\n/**\n * Create a CLI error with formatted output\n * @param options - Options to construct a CLIError\n * @returns Constructed CLIError instance\n */\nfunction createCLIError(options: CLIErrorOptions): CLIError {\n const error = new Error(options.message) as CLIErrorInternal;\n error.name = \"CLIError\";\n error.code = options.code;\n error.details = options.details;\n error.suggestion = options.suggestion;\n error.command = options.command;\n error.next = options.next;\n error.context = options.context;\n error.format = () => formatError(error);\n return error;\n}\n\n/**\n * Type guard to check if an error is a CLIError\n * @param error - Error to check\n * @returns True if the error is a CLIError\n */\nexport function isCLIError(error: unknown): error is CLIError {\n return error instanceof Error && error.name === \"CLIError\";\n}\n\n/**\n * Convert a caught value into an Error, keeping Error instances as-is\n * @param value - Caught value\n * @returns The value itself when it is an Error, otherwise an Error of its string form\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\nconst MISSING_NAMED_EXPORT_PATTERN = /does not provide an export named '(?!default')([^']+)'/;\n\n/**\n * Suggest `import type` when importing user code fails on a missing named\n * export. The CLI strips types from each file in isolation, so a type-only\n * export does not exist at runtime and a plain import of it fails to link.\n * @param error - Error thrown while importing user modules\n * @returns Suggestion text, or undefined when the error is not that failure\n */\nexport function typeOnlyImportHint(error: unknown): string | undefined {\n if (!(error instanceof SyntaxError)) return undefined;\n const name = MISSING_NAMED_EXPORT_PATTERN.exec(error.message)?.[1];\n if (!name) return undefined;\n return (\n `If '${name}' is a type, import it with \\`import type\\` (or the inline \\`type\\` modifier). ` +\n \"The CLI runs TypeScript by stripping types from each file in isolation, so type-only exports do not exist at runtime. \" +\n 'Set \"verbatimModuleSyntax\": true in tsconfig.json to catch this at typecheck.'\n );\n}\n\n// Re-export createCLIError as CLIError for backward compatibility\nexport { createCLIError as CLIError };\n"],"mappings":"0CA6CA,SAAS,WAAW,EAAuB,CAMzC,OALI,QAAQ,WAAa,QACnB,2BAA2B,KAAK,CAAK,EAAU,EAC5C,IAAI,EAAM,WAAW,IAAK,KAAK,EAAE,GAEtC,yBAAyB,KAAK,CAAK,EAAU,EAC1C,IAAI,EAAM,WAAW,IAAK,OAAO,EAAE,EAC5C,CAEA,SAAS,mBAAmB,EAAkC,CAG5D,OAAO,QAAQ,WAAa,SAAW,EAAK,KAAM,GAAU,QAAQ,KAAK,CAAK,CAAC,CACjF,CAOA,SAAgB,sBAAsB,EAAiC,CAIrE,OAHI,mBAAmB,CAAI,EAClB,QAAQ,KAAK,UAAU,CAAI,IAE7B,EAAK,IAAI,UAAU,CAAC,CAAC,KAAK,GAAG,CACtC,CAOA,SAAgB,iBAAiB,EAAkC,CACjE,IAAM,EAAO,CAAC,EAAK,QAAS,GAAG,EAAK,IAAI,EAClC,EAAW,sBAAsB,CAAI,EAC3C,OAAO,mBAAmB,CAAI,EAAI,QAAQ,IAAa,KAAK,EAAS,GACvE,CAOA,SAAS,YAAY,EAAyB,CAC5C,IAAM,EAAkB,CACtB,EAAO,MAAM,QAAQ,EAAM,KAAO,KAAK,EAAM,KAAK,GAAK,GAAG,IAAI,EAAM,SAAS,CAC/E,EAoBA,OAlBI,EAAM,SACR,EAAM,KAAK,OAAO,EAAO,IAAI,UAAU,EAAE,GAAG,EAAM,SAAS,EAGzD,EAAM,YACR,EAAM,KAAK,OAAO,EAAO,KAAK,aAAa,EAAE,GAAG,EAAM,YAAY,EAGhE,EAAM,SACR,EAAM,KACJ,OAAO,EAAO,IAAI,OAAO,EAAE,gBAAgB,EAAM,QAAQ,iCAC3D,EAGE,EAAM,MACR,EAAM,KAAK,OAAO,EAAO,KAAK,OAAO,EAAE,OAAO,iBAAiB,EAAM,IAAI,EAAE,EAAE,EAGxE,EAAM,KAAK,EAAE,CACtB,CAOA,SAAS,eAAe,EAAoC,CAC1D,IAAM,EAAY,MAAM,EAAQ,OAAO,EASvC,MARA,GAAM,KAAO,WACb,EAAM,KAAO,EAAQ,KACrB,EAAM,QAAU,EAAQ,QACxB,EAAM,WAAa,EAAQ,WAC3B,EAAM,QAAU,EAAQ,QACxB,EAAM,KAAO,EAAQ,KACrB,EAAM,QAAU,EAAQ,QACxB,EAAM,WAAe,YAAY,CAAK,EAC/B,CACT,CAOA,SAAgB,WAAW,EAAmC,CAC5D,OAAO,aAAiB,OAAS,EAAM,OAAS,UAClD,CAOA,SAAgB,QAAQ,EAAuB,CAC7C,OAAO,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CACjE,CAEA,MAAM,EAA+B,yDASrC,SAAgB,mBAAmB,EAAoC,CACrE,GAAI,EAAE,aAAiB,aAAc,OACrC,IAAM,EAAO,EAA6B,KAAK,EAAM,OAAO,CAAC,GAAG,GAC3D,KACL,MACE,OAAO,EAAK,mRAIhB"}
@@ -0,0 +1,2 @@
1
+ import*as e from"globals";const t=e.default??e,n=new Set([...Object.keys(t.builtin??{}),...Object.keys(t[`shared-node-browser`]??{})]);export{n as t};
2
+ //# sourceMappingURL=es-builtins-n3wBv4Sv.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"es-builtins-n3wBv4Sv.mjs","names":[],"sources":["../src/utils/es-builtins.ts"],"sourcesContent":["import * as globals from \"globals\";\n\ntype GlobalsShape = {\n builtin?: Record<string, boolean>;\n \"shared-node-browser\"?: Record<string, boolean>;\n};\n\nconst globalsMap: GlobalsShape =\n (globals as unknown as { default?: GlobalsShape }).default ?? globals;\n\n/**\n * Runtime globals available in the PF execution environment.\n * Identifiers in this set are excluded from free variable detection\n * since they are always available in the runtime environment.\n *\n * Combines globals.builtin (ECMAScript language builtins) and\n * globals['shared-node-browser'] (shared runtime globals like\n * console, fetch, setTimeout, etc.) from the `globals` npm package.\n */\nexport const ES_BUILTINS = new Set([\n ...Object.keys(globalsMap.builtin ?? {}),\n ...Object.keys(globalsMap[\"shared-node-browser\"] ?? {}),\n]);\n"],"mappings":"0BAOA,MAAM,EACH,EAAkD,SAAW,EAWnD,EAAc,IAAI,IAAI,CACjC,GAAG,OAAO,KAAK,EAAW,SAAW,CAAC,CAAC,EACvC,GAAG,OAAO,KAAK,EAAW,wBAA0B,CAAC,CAAC,CACxD,CAAC"}
@@ -0,0 +1,2 @@
1
+ const api=()=>globalThis.tailordb.file,e={upload:(...e)=>api().upload(...e),download:(...e)=>api().download(...e),downloadAsBase64:(...e)=>api().downloadAsBase64(...e),delete:(...e)=>api().delete(...e),getMetadata:(...e)=>api().getMetadata(...e),downloadStream:(...e)=>api().downloadStream(...e),uploadStream:(...e)=>api().uploadStream(...e)};export{e as t};
2
+ //# sourceMappingURL=file-COPYfju_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-COPYfju_.mjs","names":[],"sources":["../src/runtime/file.ts"],"sourcesContent":["/**\n * TailorDB file (BLOB) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailordb.file` runtime API.\n * At runtime this delegates to `globalThis.tailordb.file`. Use `mockFile` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { file } from \"@tailor-platform/sdk/runtime\";\n *\n * const { metadata } = await file.upload(\n * \"my-namespace\",\n * \"Document\",\n * \"attachment\",\n * recordId,\n * bytes,\n * );\n */\n\n/** Upload response metadata. */\nexport interface UploadMetadata {\n fileSize: number;\n sha256sum: string;\n}\n\n/** Download response metadata. */\nexport interface DownloadMetadata {\n contentType: string;\n fileSize: number;\n sha256sum: string;\n lastUploadedAt: string;\n}\n\n/** File metadata (for {@link TailorDBFileAPI.getMetadata}). */\nexport interface FileMetadata {\n contentType: string;\n fileSize: number;\n sha256sum: string;\n urlPath: string;\n lastUploadedAt?: string;\n}\n\n/** Upload options. */\nexport interface FileUploadOptions {\n contentType?: string;\n}\n\n/** Upload stream options. */\nexport interface FileUploadStreamOptions {\n contentType?: string;\n fileSize?: number;\n}\n\n/** Upload response. */\nexport interface FileUploadResponse {\n metadata: UploadMetadata;\n}\n\n/** Download response. */\nexport interface FileDownloadResponse {\n data: Uint8Array;\n metadata: DownloadMetadata;\n}\n\n/** Download-as-Base64 response. */\nexport interface FileDownloadAsBase64Response {\n data: string;\n metadata: DownloadMetadata;\n}\n\n/** Download stream response. */\nexport interface FileDownloadStreamResponse {\n body: ReadableStream<Uint8Array>;\n metadata: DownloadMetadata;\n}\n\n/** Error code emitted by {@link TailorDBFileError}. */\nexport type TailorDBFileErrorCode =\n | \"INVALID_PARAMS\"\n | \"INVALID_DATA_TYPE\"\n | \"OPERATION_FAILED\"\n | \"DELETE_FAILED\"\n | \"STREAM_OPEN_FAILED\"\n | \"STREAM_READ_ERROR\"\n | \"STREAM_ERROR\"\n | \"FILE_TOO_LARGE\";\n\n/**\n * Type-only shape of the `TailorDBFileError` runtime class. The class itself\n * is provided by the platform runtime (and by `injectMocks` in tests); this\n * interface mirrors it so callers can `import type { TailorDBFileError }` from\n * the wrapper module without depending on any ambient declaration.\n */\nexport interface TailorDBFileError extends Error {\n name: \"TailorDBFileError\";\n code?: TailorDBFileErrorCode;\n cause?: unknown;\n}\n\n/**\n * Platform API surface for `tailordb.file`. Describes the shape the platform\n * runtime injects on `globalThis.tailordb.file`.\n */\nexport interface TailorDBFileAPI {\n /**\n * Upload a file to TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - File contents\n * @param options - Upload options (e.g. `contentType`)\n * @returns Upload response containing the file metadata\n */\n upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | ArrayBuffer | Uint8Array | number[],\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse>;\n\n /**\n * Download a file from TailorDB.\n *\n * Throws `TailorDBFileError` with code `FILE_TOO_LARGE` when the file\n * exceeds 10MB — use {@link downloadStream} for large files.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Bytes and metadata for the file\n */\n download(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadResponse>;\n\n /**\n * Download a file from TailorDB as a Base64-encoded string.\n *\n * Throws `TailorDBFileError` with code `FILE_TOO_LARGE` when the file\n * exceeds 10MB — use {@link downloadStream} for large files.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Base64-encoded contents and metadata for the file\n */\n downloadAsBase64(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadAsBase64Response>;\n\n /**\n * Delete a file from TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Resolves once the file has been deleted\n */\n delete(namespace: string, tableName: string, fieldName: string, recordId: string): Promise<void>;\n\n /**\n * Get file metadata from TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Metadata for the stored file\n */\n getMetadata(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileMetadata>;\n\n /**\n * Download a file as a ReadableStream.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns ReadableStream body and metadata for the file\n */\n downloadStream(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadStreamResponse>;\n\n /**\n * Upload a file using a ReadableStream.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param readableStream - ReadableStream providing the file data\n * @param options - Upload stream options (e.g. `contentType`, `fileSize`)\n * @returns Upload response containing the file metadata\n */\n uploadStream(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n readableStream: ReadableStream<Uint8Array | ArrayBuffer>,\n options?: FileUploadStreamOptions,\n ): Promise<FileUploadResponse>;\n}\n\nconst api = (): TailorDBFileAPI =>\n (globalThis as unknown as { tailordb: { file: TailorDBFileAPI } }).tailordb.file;\n\n/**\n * See {@link TailorDBFileAPI.upload}.\n * @param args - Forwarded to {@link TailorDBFileAPI.upload}\n * @returns Upload response containing the file metadata\n */\nconst upload: TailorDBFileAPI[\"upload\"] = (...args) => api().upload(...args);\n\n/**\n * See {@link TailorDBFileAPI.download}.\n * @param args - Forwarded to {@link TailorDBFileAPI.download}\n * @returns Bytes and metadata for the file\n */\nconst download: TailorDBFileAPI[\"download\"] = (...args) => api().download(...args);\n\n/**\n * See {@link TailorDBFileAPI.downloadAsBase64}.\n * @param args - Forwarded to {@link TailorDBFileAPI.downloadAsBase64}\n * @returns Base64-encoded contents and metadata for the file\n */\nconst downloadAsBase64: TailorDBFileAPI[\"downloadAsBase64\"] = (...args) =>\n api().downloadAsBase64(...args);\n\n/**\n * See {@link TailorDBFileAPI.delete}.\n * @param args - Forwarded to {@link TailorDBFileAPI.delete}\n * @returns Resolves once the file has been deleted\n */\nconst deleteFile: TailorDBFileAPI[\"delete\"] = (...args) => api().delete(...args);\n\n/**\n * See {@link TailorDBFileAPI.getMetadata}.\n * @param args - Forwarded to {@link TailorDBFileAPI.getMetadata}\n * @returns Metadata for the stored file\n */\nconst getMetadata: TailorDBFileAPI[\"getMetadata\"] = (...args) => api().getMetadata(...args);\n\n/**\n * See {@link TailorDBFileAPI.downloadStream}.\n * @param args - Forwarded to {@link TailorDBFileAPI.downloadStream}\n * @returns ReadableStream body and metadata for the file\n */\nconst downloadStream: TailorDBFileAPI[\"downloadStream\"] = (...args) =>\n api().downloadStream(...args);\n\n/**\n * See {@link TailorDBFileAPI.uploadStream}.\n * @param args - Forwarded to {@link TailorDBFileAPI.uploadStream}\n * @returns Upload response containing the file metadata\n */\nconst uploadStream: TailorDBFileAPI[\"uploadStream\"] = (...args) => api().uploadStream(...args);\n\n/** Runtime wrapper namespace for `tailordb.file`. */\nexport const file = {\n upload,\n download,\n downloadAsBase64,\n delete: deleteFile,\n getMetadata,\n downloadStream,\n uploadStream,\n} as const satisfies TailorDBFileAPI;\n"],"mappings":"AA0NA,MAAM,QACH,WAAkE,SAAS,KAsDjE,EAAO,CAClB,QAhDyC,GAAG,IAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAI,EAiDzE,UA1C6C,GAAG,IAAS,IAAI,CAAC,CAAC,SAAS,GAAG,CAAI,EA2C/E,kBApC6D,GAAG,IAChE,IAAI,CAAC,CAAC,iBAAiB,GAAG,CAAI,EAoC9B,QA7B6C,GAAG,IAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAI,EA8B7E,aAvBmD,GAAG,IAAS,IAAI,CAAC,CAAC,YAAY,GAAG,CAAI,EAwBxF,gBAjByD,GAAG,IAC5D,IAAI,CAAC,CAAC,eAAe,GAAG,CAAI,EAiB5B,cAVqD,GAAG,IAAS,IAAI,CAAC,CAAC,aAAa,GAAG,CAAI,CAW7F"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./registry-HlEaGvl5.mjs";import{t}from"./platform-serialize-DkiTdHOt.mjs";function createDefaultWorkflowRuntime(){return{execJobFunction:e=>{throw Error(`No workflow job mock for "${e}". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`)},startWorkflow:async(n,r)=>(t(r),e),resumeWorkflowExecution:async e=>e,wait:e=>{throw Error(`No wait handler for "${e}". Acquire mockWorkflow() and call setWaitHandler(...).`)},resolve:async()=>{throw Error(`No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).`)}}}const n=`__tailorRuntimeActive`;var TailorErrorsMock=class extends Error{errors;constructor(e){if(!Array.isArray(e))throw TypeError(`TailorErrors: errors must be an array`);let t=e.map((e,t)=>{if(typeof e.message!=`string`)throw TypeError(`TailorErrors: errors[${t}].message must be a string`);if(!Array.isArray(e.path))throw TypeError(`TailorErrors: errors[${t}].path must be an array`);return{message:e.message,path:e.path}});super(`TailorErrors: ${JSON.stringify({errors:t})}`),this.name=`TailorErrors`,this.errors=t}},TailorDBFileErrorMock=class extends Error{code;cause;constructor(e,t,n){super(e),this.name=`TailorDBFileError`,this.code=t,this.cause=n}};function defaultGetInvoker(){return null}function noop(){}const r={debug:noop,info:noop,warn:noop,error:noop,setAttributes:noop};function installPlatformGlobals(e){let t=e;return t[n]=!0,t.tailor={context:{getInvoker:defaultGetInvoker},workflow:createDefaultWorkflowRuntime(),logger:{...r}},t.tailordb={},t.TailorErrors=TailorErrorsMock,t.TailorDBFileError=TailorDBFileErrorMock,{[Symbol.dispose](){cleanupPlatformGlobals(e)}}}function cleanupPlatformGlobals(e){let t=e;delete t.tailordb,delete t.tailor,delete t.TailorErrors,delete t.TailorDBFileError,delete t[n]}export{cleanupPlatformGlobals as n,installPlatformGlobals as r,n as t};
2
+ //# sourceMappingURL=globals-CMHSnj4w.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"globals-B2nlxBrz.mjs","names":[],"sources":["../src/vitest/workflow-runtime.ts","../src/vitest/globals.ts"],"sourcesContent":["// Default `tailor.workflow` runner installed by the `tailor-runtime` environment.\n// Must stay free of `vitest` (`vi`): it loads via `./globals` in the environment\n// realm where `vi` is unavailable, hence relative imports only (no `@/` alias).\nimport { START_DEFAULT } from \"../configure/services/workflow/registry\";\nimport { platformSerialize } from \"../utils/test/platform-serialize\";\nimport type { ExecJobFunctionOptions, StartWorkflowOptions } from \"../runtime/workflow\";\n\nexport interface DefaultWorkflowRuntime {\n execJobFunction: (name: string, args?: unknown, options?: ExecJobFunctionOptions) => unknown;\n startWorkflow: (name: string, args?: unknown, options?: StartWorkflowOptions) => Promise<string>;\n resumeWorkflowExecution: (executionId: string) => Promise<string>;\n wait: (key: string, payload?: unknown) => unknown;\n resolve: (\n executionId: string,\n key: string,\n callback: (payload: unknown) => unknown,\n ) => Promise<void>;\n}\n\nexport function createDefaultWorkflowRuntime(): DefaultWorkflowRuntime {\n const execJobFunction: DefaultWorkflowRuntime[\"execJobFunction\"] = (name) => {\n throw new Error(\n `No workflow job mock for \"${name}\". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`,\n );\n };\n const startWorkflow: DefaultWorkflowRuntime[\"startWorkflow\"] = async (_name, args) => {\n platformSerialize(args);\n return START_DEFAULT;\n };\n const resumeWorkflowExecution: DefaultWorkflowRuntime[\"resumeWorkflowExecution\"] = async (\n executionId,\n ) => executionId;\n return {\n execJobFunction,\n startWorkflow,\n resumeWorkflowExecution,\n wait: (key: string): unknown => {\n throw new Error(\n `No wait handler for \"${key}\". Acquire mockWorkflow() and call setWaitHandler(...).`,\n );\n },\n resolve: async (): Promise<void> => {\n throw new Error(\n \"No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).\",\n );\n },\n };\n}\n","/**\n * Base platform globals for the tailor-runtime test environment.\n *\n * This module is intentionally free of any `vitest` (`vi`) dependency so it can\n * be imported from the Vitest *environment* module (which runs in a realm where\n * `vi` is not available). It installs only the always-present structural pieces:\n *\n * - `globalThis.tailor` / `globalThis.tailordb` container objects\n * - `globalThis.tailor.context.getInvoker` default stub\n * - the platform error classes (`TailorErrors`,\n * `TailorDBFileError`)\n * - the `__tailorRuntimeActive` sentinel flag\n *\n * The per-namespace mock behavior (TailorDB client, workflow, secretmanager, …)\n * is installed on demand by the `xMock()` factories in `./mock`, which run in\n * test context where `vi` *is* available.\n */\n\nimport { createDefaultWorkflowRuntime } from \"./workflow-runtime\";\nimport type { ContextInvoker } from \"../runtime/context\";\nimport type { TailorDBFileErrorCode } from \"../runtime/file\";\n\n// Sentinel set when the tailor-runtime environment is active. setup.ts reads it\n// to decide whether to run its blocked-globals lifecycle and config-secret\n// loading.\nexport const RUNTIME_FLAG_KEY = \"__tailorRuntimeActive\";\n\n// ---------------------------------------------------------------------------\n// Error class mocks\n// ---------------------------------------------------------------------------\n\ninterface TailorErrorItem {\n message: string;\n path: (string | number)[];\n}\n\nclass TailorErrorsMock extends Error {\n errors: TailorErrorItem[];\n\n constructor(errors: TailorErrorItem[]) {\n if (!Array.isArray(errors)) {\n throw new TypeError(\"TailorErrors: errors must be an array\");\n }\n const validated = errors.map((e, i) => {\n if (typeof e.message !== \"string\") {\n throw new TypeError(`TailorErrors: errors[${i}].message must be a string`);\n }\n if (!Array.isArray(e.path)) {\n throw new TypeError(`TailorErrors: errors[${i}].path must be an array`);\n }\n return { message: e.message, path: e.path };\n });\n // Match the PF runtime's TailorErrors serialization, which prefixes the\n // JSON payload with \"TailorErrors: \". Other SDK code (e.g. apply\n // integration fixtures) strips this prefix before JSON.parse.\n super(`TailorErrors: ${JSON.stringify({ errors: validated })}`);\n this.name = \"TailorErrors\";\n this.errors = validated;\n }\n}\n\nclass TailorDBFileErrorMock extends Error {\n code?: TailorDBFileErrorCode;\n override cause: unknown;\n\n constructor(message: string, code?: TailorDBFileErrorCode, cause?: unknown) {\n super(message);\n this.name = \"TailorDBFileError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Base install / cleanup\n// ---------------------------------------------------------------------------\n\n// Stub-only injection. SDK consumers configure invokers at the body level\n// (resolver/executor/workflow `.body()` `invoker` arg) or, for bundled tests,\n// via `vi.spyOn(globalThis.tailor.context, \"getInvoker\")`.\nfunction defaultGetInvoker(): ContextInvoker | null {\n return null;\n}\n\n// No-op logger stub so `tailor.logger.*` calls in code under test don't throw\n// without an explicit `mockLogger()`. `mockLogger()` overlays vi.fn spies and\n// restores this on dispose.\nfunction noop(): void {}\nconst defaultLogger = {\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n setAttributes: noop,\n};\n\n/**\n * Install the always-present base platform globals (containers, context stub,\n * error classes, runtime flag). Per-namespace mocks are layered on top by the\n * `xMock()` factories in `./mock`.\n *\n * Acquire with a `using` declaration and the globals are removed when the\n * scope exits; alternatively call `cleanupPlatformGlobals` yourself.\n * @param global - The global object to install into (typically `globalThis`)\n * @returns A `Disposable` that removes the installed globals\n */\nexport function installPlatformGlobals(global: typeof globalThis): Disposable {\n const g = global as Record<string, unknown>;\n\n g[RUNTIME_FLAG_KEY] = true;\n\n // Containers. Namespace mocks (secretmanager, …) are added to these by the\n // corresponding `xMock()` on acquisition. `workflow` carries a default\n // runner: job/wait/resolve calls throw a helpful error, and workflow starts\n // return a placeholder execution id, unless overlaid by `mockWorkflow()` or\n // `runWorkflowLocally()`.\n g.tailor = {\n context: { getInvoker: defaultGetInvoker },\n workflow: createDefaultWorkflowRuntime(),\n logger: { ...defaultLogger },\n };\n g.tailordb = {};\n\n g.TailorErrors = TailorErrorsMock;\n g.TailorDBFileError = TailorDBFileErrorMock;\n\n return {\n [Symbol.dispose]() {\n cleanupPlatformGlobals(global);\n },\n };\n}\n\n/**\n * Remove the base platform globals (and anything the namespace mocks layered on\n * top, since they live under the same containers).\n * @param global - The global object to clean up (typically `globalThis`)\n */\nexport function cleanupPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n delete g.tailordb;\n delete g.tailor;\n delete g.TailorErrors;\n delete g.TailorDBFileError;\n delete g[RUNTIME_FLAG_KEY];\n}\n"],"mappings":";;;;AAmBA,SAAgB,+BAAuD;CACrE,MAAM,mBAA8D,SAAS;EAC3E,MAAM,IAAI,MACR,6BAA6B,KAAK,uIACpC;CACF;CACA,MAAM,gBAAyD,OAAO,OAAO,SAAS;EACpF,kBAAkB,IAAI;EACtB,OAAO;CACT;CACA,MAAM,0BAA6E,OACjF,gBACG;CACL,OAAO;EACL;EACA;EACA;EACA,OAAO,QAAyB;GAC9B,MAAM,IAAI,MACR,wBAAwB,IAAI,wDAC9B;EACF;EACA,SAAS,YAA2B;GAClC,MAAM,IAAI,MACR,6EACF;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;ACtBA,MAAa,mBAAmB;AAWhC,IAAM,mBAAN,cAA+B,MAAM;CACnC;CAEA,YAAY,QAA2B;EACrC,IAAI,CAAC,MAAM,QAAQ,MAAM,GACvB,MAAM,IAAI,UAAU,uCAAuC;EAE7D,MAAM,YAAY,OAAO,KAAK,GAAG,MAAM;GACrC,IAAI,OAAO,EAAE,YAAY,UACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,2BAA2B;GAE3E,IAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,GACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,wBAAwB;GAExE,OAAO;IAAE,SAAS,EAAE;IAAS,MAAM,EAAE;GAAK;EAC5C,CAAC;EAID,MAAM,iBAAiB,KAAK,UAAU,EAAE,QAAQ,UAAU,CAAC,GAAG;EAC9D,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;AACF;AAEA,IAAM,wBAAN,cAAoC,MAAM;CACxC;CACA,AAAS;CAET,YAAY,SAAiB,MAA8B,OAAiB;EAC1E,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;AASA,SAAS,oBAA2C;CAClD,OAAO;AACT;AAKA,SAAS,OAAa,CAAC;AACvB,MAAM,gBAAgB;CACpB,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,eAAe;AACjB;;;;;;;;;;;AAYA,SAAgB,uBAAuB,QAAuC;CAC5E,MAAM,IAAI;CAEV,EAAE,oBAAoB;CAOtB,EAAE,SAAS;EACT,SAAS,EAAE,YAAY,kBAAkB;EACzC,UAAU,6BAA6B;EACvC,QAAQ,EAAE,GAAG,cAAc;CAC7B;CACA,EAAE,WAAW,CAAC;CAEd,EAAE,eAAe;CACjB,EAAE,oBAAoB;CAEtB,OAAO,EACL,CAAC,OAAO,WAAW;EACjB,uBAAuB,MAAM;CAC/B,EACF;AACF;;;;;;AAOA,SAAgB,uBAAuB,QAAiC;CACtE,MAAM,IAAI;CACV,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;AACX"}
1
+ {"version":3,"file":"globals-CMHSnj4w.mjs","names":[],"sources":["../src/vitest/workflow-runtime.ts","../src/vitest/globals.ts"],"sourcesContent":["// Default `tailor.workflow` runner installed by the `tailor-runtime` environment.\n// Must stay free of `vitest` (`vi`): it loads via `./globals` in the environment\n// realm where `vi` is unavailable, hence relative imports only (no `@/` alias).\nimport { START_DEFAULT } from \"../configure/services/workflow/registry\";\nimport { platformSerialize } from \"../utils/test/platform-serialize\";\nimport type { ExecJobFunctionOptions, StartWorkflowOptions } from \"../runtime/workflow\";\n\nexport interface DefaultWorkflowRuntime {\n execJobFunction: (name: string, args?: unknown, options?: ExecJobFunctionOptions) => unknown;\n startWorkflow: (name: string, args?: unknown, options?: StartWorkflowOptions) => Promise<string>;\n resumeWorkflowExecution: (executionId: string) => Promise<string>;\n wait: (key: string, payload?: unknown) => unknown;\n resolve: (\n executionId: string,\n key: string,\n callback: (payload: unknown) => unknown,\n ) => Promise<void>;\n}\n\nexport function createDefaultWorkflowRuntime(): DefaultWorkflowRuntime {\n const execJobFunction: DefaultWorkflowRuntime[\"execJobFunction\"] = (name) => {\n throw new Error(\n `No workflow job mock for \"${name}\". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`,\n );\n };\n const startWorkflow: DefaultWorkflowRuntime[\"startWorkflow\"] = async (_name, args) => {\n platformSerialize(args);\n return START_DEFAULT;\n };\n const resumeWorkflowExecution: DefaultWorkflowRuntime[\"resumeWorkflowExecution\"] = async (\n executionId,\n ) => executionId;\n return {\n execJobFunction,\n startWorkflow,\n resumeWorkflowExecution,\n wait: (key: string): unknown => {\n throw new Error(\n `No wait handler for \"${key}\". Acquire mockWorkflow() and call setWaitHandler(...).`,\n );\n },\n resolve: async (): Promise<void> => {\n throw new Error(\n \"No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).\",\n );\n },\n };\n}\n","/**\n * Base platform globals for the tailor-runtime test environment.\n *\n * This module is intentionally free of any `vitest` (`vi`) dependency so it can\n * be imported from the Vitest *environment* module (which runs in a realm where\n * `vi` is not available). It installs only the always-present structural pieces:\n *\n * - `globalThis.tailor` / `globalThis.tailordb` container objects\n * - `globalThis.tailor.context.getInvoker` default stub\n * - the platform error classes (`TailorErrors`,\n * `TailorDBFileError`)\n * - the `__tailorRuntimeActive` sentinel flag\n *\n * The per-namespace mock behavior (TailorDB client, workflow, secretmanager, …)\n * is installed on demand by the `xMock()` factories in `./mock`, which run in\n * test context where `vi` *is* available.\n */\n\nimport { createDefaultWorkflowRuntime } from \"./workflow-runtime\";\nimport type { ContextInvoker } from \"../runtime/context\";\nimport type { TailorDBFileErrorCode } from \"../runtime/file\";\n\n// Sentinel set when the tailor-runtime environment is active. setup.ts reads it\n// to decide whether to run its blocked-globals lifecycle and config-secret\n// loading.\nexport const RUNTIME_FLAG_KEY = \"__tailorRuntimeActive\";\n\n// ---------------------------------------------------------------------------\n// Error class mocks\n// ---------------------------------------------------------------------------\n\ninterface TailorErrorItem {\n message: string;\n path: (string | number)[];\n}\n\nclass TailorErrorsMock extends Error {\n errors: TailorErrorItem[];\n\n constructor(errors: TailorErrorItem[]) {\n if (!Array.isArray(errors)) {\n throw new TypeError(\"TailorErrors: errors must be an array\");\n }\n const validated = errors.map((e, i) => {\n if (typeof e.message !== \"string\") {\n throw new TypeError(`TailorErrors: errors[${i}].message must be a string`);\n }\n if (!Array.isArray(e.path)) {\n throw new TypeError(`TailorErrors: errors[${i}].path must be an array`);\n }\n return { message: e.message, path: e.path };\n });\n // Match the PF runtime's TailorErrors serialization, which prefixes the\n // JSON payload with \"TailorErrors: \". Other SDK code (e.g. apply\n // integration fixtures) strips this prefix before JSON.parse.\n super(`TailorErrors: ${JSON.stringify({ errors: validated })}`);\n this.name = \"TailorErrors\";\n this.errors = validated;\n }\n}\n\nclass TailorDBFileErrorMock extends Error {\n code?: TailorDBFileErrorCode;\n override cause: unknown;\n\n constructor(message: string, code?: TailorDBFileErrorCode, cause?: unknown) {\n super(message);\n this.name = \"TailorDBFileError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Base install / cleanup\n// ---------------------------------------------------------------------------\n\n// Stub-only injection. SDK consumers configure invokers at the body level\n// (resolver/executor/workflow `.body()` `invoker` arg) or, for bundled tests,\n// via `vi.spyOn(globalThis.tailor.context, \"getInvoker\")`.\nfunction defaultGetInvoker(): ContextInvoker | null {\n return null;\n}\n\n// No-op logger stub so `tailor.logger.*` calls in code under test don't throw\n// without an explicit `mockLogger()`. `mockLogger()` overlays vi.fn spies and\n// restores this on dispose.\nfunction noop(): void {}\nconst defaultLogger = {\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n setAttributes: noop,\n};\n\n/**\n * Install the always-present base platform globals (containers, context stub,\n * error classes, runtime flag). Per-namespace mocks are layered on top by the\n * `xMock()` factories in `./mock`.\n *\n * Acquire with a `using` declaration and the globals are removed when the\n * scope exits; alternatively call `cleanupPlatformGlobals` yourself.\n * @param global - The global object to install into (typically `globalThis`)\n * @returns A `Disposable` that removes the installed globals\n */\nexport function installPlatformGlobals(global: typeof globalThis): Disposable {\n const g = global as Record<string, unknown>;\n\n g[RUNTIME_FLAG_KEY] = true;\n\n // Containers. Namespace mocks (secretmanager, …) are added to these by the\n // corresponding `xMock()` on acquisition. `workflow` carries a default\n // runner: job/wait/resolve calls throw a helpful error, and workflow starts\n // return a placeholder execution id, unless overlaid by `mockWorkflow()` or\n // `runWorkflowLocally()`.\n g.tailor = {\n context: { getInvoker: defaultGetInvoker },\n workflow: createDefaultWorkflowRuntime(),\n logger: { ...defaultLogger },\n };\n g.tailordb = {};\n\n g.TailorErrors = TailorErrorsMock;\n g.TailorDBFileError = TailorDBFileErrorMock;\n\n return {\n [Symbol.dispose]() {\n cleanupPlatformGlobals(global);\n },\n };\n}\n\n/**\n * Remove the base platform globals (and anything the namespace mocks layered on\n * top, since they live under the same containers).\n * @param global - The global object to clean up (typically `globalThis`)\n */\nexport function cleanupPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n delete g.tailordb;\n delete g.tailor;\n delete g.TailorErrors;\n delete g.TailorDBFileError;\n delete g[RUNTIME_FLAG_KEY];\n}\n"],"mappings":"6FAmBA,SAAgB,8BAAuD,CAarE,MAAO,CACL,gBAbkE,GAAS,CAC3E,MAAU,MACR,6BAA6B,EAAK,uIACpC,CACF,EAUE,oBAToE,EAAO,KAC3E,EAAkB,CAAI,EACf,GAQP,6BALA,IACG,EAKH,KAAO,GAAyB,CAC9B,MAAU,MACR,wBAAwB,EAAI,wDAC9B,CACF,EACA,QAAS,SAA2B,CAClC,MAAU,MACR,6EACF,CACF,CACF,CACF,CCtBA,MAAa,EAAmB,wBAWhC,IAAM,iBAAN,cAA+B,KAAM,CACnC,OAEA,YAAY,EAA2B,CACrC,GAAI,CAAC,MAAM,QAAQ,CAAM,EACvB,MAAU,UAAU,uCAAuC,EAE7D,IAAM,EAAY,EAAO,KAAK,EAAG,IAAM,CACrC,GAAI,OAAO,EAAE,SAAY,SACvB,MAAU,UAAU,wBAAwB,EAAE,2BAA2B,EAE3E,GAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,EACvB,MAAU,UAAU,wBAAwB,EAAE,wBAAwB,EAExE,MAAO,CAAE,QAAS,EAAE,QAAS,KAAM,EAAE,IAAK,CAC5C,CAAC,EAID,MAAM,iBAAiB,KAAK,UAAU,CAAE,OAAQ,CAAU,CAAC,GAAG,EAC9D,KAAK,KAAO,eACZ,KAAK,OAAS,CAChB,CACF,EAEM,sBAAN,cAAoC,KAAM,CACxC,KACA,MAEA,YAAY,EAAiB,EAA8B,EAAiB,CAC1E,MAAM,CAAO,EACb,KAAK,KAAO,oBACZ,KAAK,KAAO,EACZ,KAAK,MAAQ,CACf,CACF,EASA,SAAS,mBAA2C,CAClD,OAAO,IACT,CAKA,SAAS,MAAa,CAAC,CACvB,MAAM,EAAgB,CACpB,MAAO,KACP,KAAM,KACN,KAAM,KACN,MAAO,KACP,cAAe,IACjB,EAYA,SAAgB,uBAAuB,EAAuC,CAC5E,IAAM,EAAI,EAmBV,MAjBA,GAAE,GAAoB,GAOtB,EAAE,OAAS,CACT,QAAS,CAAE,WAAY,iBAAkB,EACzC,SAAU,6BAA6B,EACvC,OAAQ,CAAE,GAAG,CAAc,CAC7B,EACA,EAAE,SAAW,CAAC,EAEd,EAAE,aAAe,iBACjB,EAAE,kBAAoB,sBAEf,CACL,CAAC,OAAO,UAAW,CACjB,uBAAuB,CAAM,CAC/B,CACF,CACF,CAOA,SAAgB,uBAAuB,EAAiC,CACtE,IAAM,EAAI,EACV,OAAO,EAAE,SACT,OAAO,EAAE,OACT,OAAO,EAAE,aACT,OAAO,EAAE,kBACT,OAAO,EAAE,EACX"}
@@ -0,0 +1,2 @@
1
+ const api=()=>globalThis.tailor.iconv,e={convert:(...e)=>api().convert(...e),convertBuffer:(...e)=>api().convertBuffer(...e),decode:(...e)=>api().decode(...e),encode:(...e)=>api().encode(...e),encodings:()=>api().encodings(),Iconv:class{impl;constructor(e,t){this.impl=new(api()).Iconv(e,t)}convert(e){return this.impl.convert(e)}}};export{e as t};
2
+ //# sourceMappingURL=iconv-DlFMt2gW.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"iconv-QWaZh0TT.mjs","names":[],"sources":["../src/runtime/iconv.ts"],"sourcesContent":["/**\n * Character encoding conversion utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.iconv` runtime API.\n * At runtime this delegates to `globalThis.tailor.iconv`, which is provided by\n * the Tailor Platform Function runtime. Use `mockIconv` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { iconv } from \"@tailor-platform/sdk/runtime\";\n *\n * const utf8 = iconv.convert(sjisBuffer, \"Shift_JIS\", \"UTF-8\"); // string\n * const sjis = iconv.convert(\"こんにちは\", \"UTF-8\", \"Shift_JIS\"); // Uint8Array\n *\n * const conv = new iconv.Iconv(\"Shift_JIS\", \"UTF-8\");\n * const out = conv.convert(sjisBuffer);\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/** Instance methods exposed by `tailor.iconv.Iconv`. */\nexport interface IconvInstance {\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array;\n}\n\n/** Constructor shape for `tailor.iconv.Iconv`. */\nexport interface IconvConstructor {\n new (fromEncoding: string, toEncoding: string): IconvInstance;\n}\n\n/**\n * Platform API surface for `tailor.iconv`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.iconv` so the wrapper and ambient\n * globals stay in sync.\n */\nexport interface TailorIconvAPI {\n /**\n * Convert a string or buffer between encodings.\n * @param str - Input data to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convert<T extends string>(\n str: string | Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Convert a buffer between encodings.\n * @param buffer - Input bytes to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convertBuffer<T extends string>(\n buffer: Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Decode a buffer to a UTF-8 string using the given source encoding.\n * @param buffer - Input bytes\n * @param encoding - Source encoding name\n * @returns Decoded UTF-8 string\n */\n decode(buffer: Uint8Array | ArrayBuffer, encoding: string): string;\n\n /**\n * Encode a UTF-8 string into the given target encoding.\n * @param str - Input string\n * @param encoding - Target encoding name\n * @returns `string` when `encoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n encode<T extends string>(\n str: string,\n encoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Returns the list of supported encoding names.\n * @returns Array of encoding names supported by the platform iconv runtime\n */\n encodings(): string[];\n\n /** Constructor for the stateful converter. */\n Iconv: IconvConstructor;\n}\n\nconst api = (): TailorIconvAPI =>\n (globalThis as unknown as { tailor: { iconv: TailorIconvAPI } }).tailor.iconv;\n\nconst convert: TailorIconvAPI[\"convert\"] = (...args) => api().convert(...args);\n\nconst convertBuffer: TailorIconvAPI[\"convertBuffer\"] = (...args) => api().convertBuffer(...args);\n\nconst decode: TailorIconvAPI[\"decode\"] = (...args) => api().decode(...args);\n\nconst encode: TailorIconvAPI[\"encode\"] = (...args) => api().encode(...args);\n\nconst encodings: TailorIconvAPI[\"encodings\"] = () => api().encodings();\n\n/**\n * Stateful converter for repeated conversions between a fixed encoding pair.\n * Compatible with the `node-iconv` API surface.\n */\nclass Iconv {\n private impl: IconvInstance;\n\n constructor(fromEncoding: string, toEncoding: string) {\n this.impl = new (api().Iconv)(fromEncoding, toEncoding);\n }\n\n /**\n * Convert input using this converter's fixed encoding pair.\n * @param input - Bytes or string to convert\n * @returns Encoded output (string for UTF-8 targets, otherwise `Uint8Array`).\n */\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array {\n return this.impl.convert(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.iconv`. */\nexport const iconv: TailorIconvAPI = {\n convert,\n convertBuffer,\n decode,\n encode,\n encodings,\n Iconv,\n};\n"],"mappings":";AA0FA,MAAM,YACH,WAAgE,OAAO;AAE1E,MAAM,WAAsC,GAAG,SAAS,IAAI,CAAC,CAAC,QAAQ,GAAG,IAAI;AAE7E,MAAM,iBAAkD,GAAG,SAAS,IAAI,CAAC,CAAC,cAAc,GAAG,IAAI;AAE/F,MAAM,UAAoC,GAAG,SAAS,IAAI,CAAC,CAAC,OAAO,GAAG,IAAI;AAE1E,MAAM,UAAoC,GAAG,SAAS,IAAI,CAAC,CAAC,OAAO,GAAG,IAAI;AAE1E,MAAM,kBAA+C,IAAI,CAAC,CAAC,UAAU;;;;;AAMrE,IAAM,QAAN,MAAY;CACV,AAAQ;CAER,YAAY,cAAsB,YAAoB;EACpD,KAAK,OAAO,KAAK,IAAI,EAAC,CAAC,MAAO,cAAc,UAAU;CACxD;;;;;;CAOA,QAAQ,OAA+D;EACrE,OAAO,KAAK,KAAK,QAAQ,KAAK;CAChC;AACF;;AAIA,MAAa,QAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;AACF"}
1
+ {"version":3,"file":"iconv-DlFMt2gW.mjs","names":[],"sources":["../src/runtime/iconv.ts"],"sourcesContent":["/**\n * Character encoding conversion utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.iconv` runtime API.\n * At runtime this delegates to `globalThis.tailor.iconv`, which is provided by\n * the Tailor Platform Function runtime. Use `mockIconv` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { iconv } from \"@tailor-platform/sdk/runtime\";\n *\n * const utf8 = iconv.convert(sjisBuffer, \"Shift_JIS\", \"UTF-8\"); // string\n * const sjis = iconv.convert(\"こんにちは\", \"UTF-8\", \"Shift_JIS\"); // Uint8Array\n *\n * const conv = new iconv.Iconv(\"Shift_JIS\", \"UTF-8\");\n * const out = conv.convert(sjisBuffer);\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/** Instance methods exposed by `tailor.iconv.Iconv`. */\nexport interface IconvInstance {\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array;\n}\n\n/** Constructor shape for `tailor.iconv.Iconv`. */\nexport interface IconvConstructor {\n new (fromEncoding: string, toEncoding: string): IconvInstance;\n}\n\n/**\n * Platform API surface for `tailor.iconv`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.iconv` so the wrapper and ambient\n * globals stay in sync.\n */\nexport interface TailorIconvAPI {\n /**\n * Convert a string or buffer between encodings.\n * @param str - Input data to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convert<T extends string>(\n str: string | Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Convert a buffer between encodings.\n * @param buffer - Input bytes to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convertBuffer<T extends string>(\n buffer: Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Decode a buffer to a UTF-8 string using the given source encoding.\n * @param buffer - Input bytes\n * @param encoding - Source encoding name\n * @returns Decoded UTF-8 string\n */\n decode(buffer: Uint8Array | ArrayBuffer, encoding: string): string;\n\n /**\n * Encode a UTF-8 string into the given target encoding.\n * @param str - Input string\n * @param encoding - Target encoding name\n * @returns `string` when `encoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n encode<T extends string>(\n str: string,\n encoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Returns the list of supported encoding names.\n * @returns Array of encoding names supported by the platform iconv runtime\n */\n encodings(): string[];\n\n /** Constructor for the stateful converter. */\n Iconv: IconvConstructor;\n}\n\nconst api = (): TailorIconvAPI =>\n (globalThis as unknown as { tailor: { iconv: TailorIconvAPI } }).tailor.iconv;\n\nconst convert: TailorIconvAPI[\"convert\"] = (...args) => api().convert(...args);\n\nconst convertBuffer: TailorIconvAPI[\"convertBuffer\"] = (...args) => api().convertBuffer(...args);\n\nconst decode: TailorIconvAPI[\"decode\"] = (...args) => api().decode(...args);\n\nconst encode: TailorIconvAPI[\"encode\"] = (...args) => api().encode(...args);\n\nconst encodings: TailorIconvAPI[\"encodings\"] = () => api().encodings();\n\n/**\n * Stateful converter for repeated conversions between a fixed encoding pair.\n * Compatible with the `node-iconv` API surface.\n */\nclass Iconv {\n private impl: IconvInstance;\n\n constructor(fromEncoding: string, toEncoding: string) {\n this.impl = new (api().Iconv)(fromEncoding, toEncoding);\n }\n\n /**\n * Convert input using this converter's fixed encoding pair.\n * @param input - Bytes or string to convert\n * @returns Encoded output (string for UTF-8 targets, otherwise `Uint8Array`).\n */\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array {\n return this.impl.convert(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.iconv`. */\nexport const iconv: TailorIconvAPI = {\n convert,\n convertBuffer,\n decode,\n encode,\n encodings,\n Iconv,\n};\n"],"mappings":"AA0FA,MAAM,QACH,WAAgE,OAAO,MAmC7D,EAAwB,CACnC,SAlC0C,GAAG,IAAS,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAI,EAmC3E,eAjCsD,GAAG,IAAS,IAAI,CAAC,CAAC,cAAc,GAAG,CAAI,EAkC7F,QAhCwC,GAAG,IAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAI,EAiCxE,QA/BwC,GAAG,IAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAI,EAgCxE,cA9BmD,IAAI,CAAC,CAAC,UAAU,EA+BnE,WAzBU,CACV,KAEA,YAAY,EAAsB,EAAoB,CACpD,KAAK,KAAO,IAAK,IAAI,EAAA,CAAE,MAAO,EAAc,CAAU,CACxD,CAOA,QAAQ,EAA+D,CACrE,OAAO,KAAK,KAAK,QAAQ,CAAK,CAChC,CACF,CAWA"}
@@ -0,0 +1,2 @@
1
+ const e={Client:class{#e;constructor(e){this.#e=new globalThis.tailor.idp.Client(e)}users(e){return this.#e.users(e)}user(e){return this.#e.user(e)}userByName(e){return this.#e.userByName(e)}createUser(e){return this.#e.createUser(e)}updateUser(e){return this.#e.updateUser(e)}deleteUser(e){return this.#e.deleteUser(e)}sendPasswordResetEmail(e){return this.#e.sendPasswordResetEmail(e)}unenrollMfa(e){return this.#e.unenrollMfa(e)}}};export{e as t};
2
+ //# sourceMappingURL=idp-G_ojPBB5.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"idp-RA_swu-h.mjs","names":["#impl"],"sources":["../src/runtime/idp.ts"],"sourcesContent":["/**\n * IDP (Identity Provider) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.idp` runtime API.\n * At runtime this delegates to `globalThis.tailor.idp`. Use `mockIdp` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { idp } from \"@tailor-platform/sdk/runtime\";\n *\n * const client = new idp.Client({ namespace: \"my-namespace\" });\n * const { users } = await client.users({ first: 10 });\n */\n\n/** Configuration object for `idp.Client`. */\nexport interface ClientConfig {\n namespace: string;\n}\n\n/** User record returned by IDP operations. */\nexport interface User {\n id: string;\n name: string;\n disabled: boolean;\n createdAt?: string;\n /**\n * True when the user has at least one enrolled MFA second factor. False when\n * the namespace has MFA disabled or the user has not enrolled a factor.\n */\n mfaEnrolled: boolean;\n /**\n * Enrolled MFA second factor IDs. Pass an entry into\n * `idp.Client.unenrollMfa()` to remove that factor.\n */\n mfaFactorIds: string[];\n}\n\n/** Filter options for `idp.Client.users()`. */\nexport interface UserQuery {\n /** Filter by user IDs */\n ids?: string[];\n /** Filter by user names */\n names?: string[];\n}\n\n/** Pagination/filter options for `idp.Client.users()`. */\nexport interface ListUsersOptions {\n /** Maximum number of users to return */\n first?: number;\n /** Page token for pagination */\n after?: string;\n /** Query filter for users */\n query?: UserQuery;\n}\n\n/** Response shape for `idp.Client.users()`. */\nexport interface ListUsersResponse {\n users: User[];\n nextPageToken: string | null;\n totalCount: number;\n}\n\n/** Input for `idp.Client.createUser()`. */\nexport interface CreateUserInput {\n /** The user's name (typically email) */\n name: string;\n /** The user's password. If omitted, the user is created without a password (cannot log in with any password). */\n password?: string;\n /** Whether the user is disabled */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.updateUser()`. */\nexport interface UpdateUserInput {\n /** The user's ID */\n id: string;\n /** New name for the user */\n name?: string;\n /** New password for the user. Cannot be used with clearPassword. */\n password?: string;\n /** If true, remove the user's password. Cannot be used with password. */\n clearPassword?: boolean;\n /** New disabled status for the user */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.sendPasswordResetEmail()`. */\nexport interface SendPasswordResetEmailInput {\n /** The ID of the user */\n userId: string;\n /** The URI to redirect to after password reset */\n redirectUri: string;\n /** The sender display name. Defaults to 'Tailor Platform IdP'. */\n fromName?: string;\n /** The email subject line. Defaults to the localized default subject. */\n subject?: string;\n}\n\n/** Input for `idp.Client.unenrollMfa()`. */\nexport interface UnenrollMfaInput {\n /** The ID of the user whose factor will be unenrolled. */\n userId: string;\n /**\n * The ID of the factor to unenroll. Factor IDs are exposed on the user\n * record (see {@link User.mfaFactorIds}).\n */\n mfaFactorId: string;\n}\n\n/** Instance methods exposed by `tailor.idp.Client`. */\nexport interface IdpClientInstance {\n users(options?: ListUsersOptions): Promise<ListUsersResponse>;\n user(userId: string): Promise<User>;\n userByName(name: string): Promise<User>;\n createUser(input: CreateUserInput): Promise<User>;\n updateUser(input: UpdateUserInput): Promise<User>;\n deleteUser(userId: string): Promise<boolean>;\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean>;\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean>;\n}\n\n/**\n * Constructor shape for `tailor.idp.Client`.\n * @internal\n */\nexport interface IdpClientConstructor {\n new (config: ClientConfig): IdpClientInstance;\n}\n\n/**\n * Platform API surface for `tailor.idp`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.idp`.\n * @internal\n */\nexport interface TailorIdpAPI {\n Client: IdpClientConstructor;\n}\n\n/**\n * IDP Client for user management operations.\n *\n * Wraps the platform-provided `tailor.idp.Client` and exposes the same surface.\n */\nclass Client {\n #impl: IdpClientInstance;\n\n constructor(config: ClientConfig) {\n this.#impl = new (globalThis as unknown as { tailor: { idp: TailorIdpAPI } }).tailor.idp.Client(\n config,\n );\n }\n\n /**\n * List users in the namespace with optional filtering and pagination.\n * @param options - Pagination and filter options\n * @returns Page of users with `nextPageToken` and `totalCount`\n */\n users(options?: ListUsersOptions): Promise<ListUsersResponse> {\n return this.#impl.users(options);\n }\n\n /**\n * Get a user by ID.\n * @param userId - IDP user ID\n * @returns The matching user\n */\n user(userId: string): Promise<User> {\n return this.#impl.user(userId);\n }\n\n /**\n * Get a user by name.\n * @param name - IDP user name\n * @returns The matching user\n */\n userByName(name: string): Promise<User> {\n return this.#impl.userByName(name);\n }\n\n /**\n * Create a new user.\n * @param input - User attributes\n * @returns The newly created user\n */\n createUser(input: CreateUserInput): Promise<User> {\n return this.#impl.createUser(input);\n }\n\n /**\n * Update an existing user.\n * @param input - User ID plus attributes to update\n * @returns The updated user\n */\n updateUser(input: UpdateUserInput): Promise<User> {\n return this.#impl.updateUser(input);\n }\n\n /**\n * Delete a user by ID.\n * @param userId - IDP user ID\n * @returns `true` when the user was deleted\n */\n deleteUser(userId: string): Promise<boolean> {\n return this.#impl.deleteUser(userId);\n }\n\n /**\n * Send a password reset email to a user.\n * @param input - Target user ID and redirect URI\n * @returns `true` when the email was queued\n */\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean> {\n return this.#impl.sendPasswordResetEmail(input);\n }\n\n /**\n * Unenroll an MFA factor from a user.\n * @param input - Target user ID and factor ID (see {@link User.mfaFactorIds})\n * @returns `true` when the factor was removed\n */\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean> {\n return this.#impl.unenrollMfa(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.idp`. */\nexport const idp: TailorIdpAPI = { Client };\n"],"mappings":";;;;;;AA8IA,IAAM,SAAN,MAAa;CACX;CAEA,YAAY,QAAsB;EAChC,KAAKA,QAAQ,IAAK,WAA4D,OAAO,IAAI,OACvF,MACF;CACF;;;;;;CAOA,MAAM,SAAwD;EAC5D,OAAO,KAAKA,MAAM,MAAM,OAAO;CACjC;;;;;;CAOA,KAAK,QAA+B;EAClC,OAAO,KAAKA,MAAM,KAAK,MAAM;CAC/B;;;;;;CAOA,WAAW,MAA6B;EACtC,OAAO,KAAKA,MAAM,WAAW,IAAI;CACnC;;;;;;CAOA,WAAW,OAAuC;EAChD,OAAO,KAAKA,MAAM,WAAW,KAAK;CACpC;;;;;;CAOA,WAAW,OAAuC;EAChD,OAAO,KAAKA,MAAM,WAAW,KAAK;CACpC;;;;;;CAOA,WAAW,QAAkC;EAC3C,OAAO,KAAKA,MAAM,WAAW,MAAM;CACrC;;;;;;CAOA,uBAAuB,OAAsD;EAC3E,OAAO,KAAKA,MAAM,uBAAuB,KAAK;CAChD;;;;;;CAOA,YAAY,OAA2C;EACrD,OAAO,KAAKA,MAAM,YAAY,KAAK;CACrC;AACF;;AAIA,MAAa,MAAoB,EAAE,OAAO"}
1
+ {"version":3,"file":"idp-G_ojPBB5.mjs","names":["#impl"],"sources":["../src/runtime/idp.ts"],"sourcesContent":["/**\n * IDP (Identity Provider) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.idp` runtime API.\n * At runtime this delegates to `globalThis.tailor.idp`. Use `mockIdp` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { idp } from \"@tailor-platform/sdk/runtime\";\n *\n * const client = new idp.Client({ namespace: \"my-namespace\" });\n * const { users } = await client.users({ first: 10 });\n */\n\n/** Configuration object for `idp.Client`. */\nexport interface ClientConfig {\n namespace: string;\n}\n\n/** User record returned by IDP operations. */\nexport interface User {\n id: string;\n name: string;\n disabled: boolean;\n createdAt?: string;\n /**\n * True when the user has at least one enrolled MFA second factor. False when\n * the namespace has MFA disabled or the user has not enrolled a factor.\n */\n mfaEnrolled: boolean;\n /**\n * Enrolled MFA second factor IDs. Pass an entry into\n * `idp.Client.unenrollMfa()` to remove that factor.\n */\n mfaFactorIds: string[];\n}\n\n/** Filter options for `idp.Client.users()`. */\nexport interface UserQuery {\n /** Filter by user IDs */\n ids?: string[];\n /** Filter by user names */\n names?: string[];\n}\n\n/** Pagination/filter options for `idp.Client.users()`. */\nexport interface ListUsersOptions {\n /** Maximum number of users to return */\n first?: number;\n /** Page token for pagination */\n after?: string;\n /** Query filter for users */\n query?: UserQuery;\n}\n\n/** Response shape for `idp.Client.users()`. */\nexport interface ListUsersResponse {\n users: User[];\n nextPageToken: string | null;\n totalCount: number;\n}\n\n/** Input for `idp.Client.createUser()`. */\nexport interface CreateUserInput {\n /** The user's name (typically email) */\n name: string;\n /** The user's password. If omitted, the user is created without a password (cannot log in with any password). */\n password?: string;\n /** Whether the user is disabled */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.updateUser()`. */\nexport interface UpdateUserInput {\n /** The user's ID */\n id: string;\n /** New name for the user */\n name?: string;\n /** New password for the user. Cannot be used with clearPassword. */\n password?: string;\n /** If true, remove the user's password. Cannot be used with password. */\n clearPassword?: boolean;\n /** New disabled status for the user */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.sendPasswordResetEmail()`. */\nexport interface SendPasswordResetEmailInput {\n /** The ID of the user */\n userId: string;\n /** The URI to redirect to after password reset */\n redirectUri: string;\n /** The sender display name. Defaults to 'Tailor Platform IdP'. */\n fromName?: string;\n /** The email subject line. Defaults to the localized default subject. */\n subject?: string;\n}\n\n/** Input for `idp.Client.unenrollMfa()`. */\nexport interface UnenrollMfaInput {\n /** The ID of the user whose factor will be unenrolled. */\n userId: string;\n /**\n * The ID of the factor to unenroll. Factor IDs are exposed on the user\n * record (see {@link User.mfaFactorIds}).\n */\n mfaFactorId: string;\n}\n\n/** Instance methods exposed by `tailor.idp.Client`. */\nexport interface IdpClientInstance {\n users(options?: ListUsersOptions): Promise<ListUsersResponse>;\n user(userId: string): Promise<User>;\n userByName(name: string): Promise<User>;\n createUser(input: CreateUserInput): Promise<User>;\n updateUser(input: UpdateUserInput): Promise<User>;\n deleteUser(userId: string): Promise<boolean>;\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean>;\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean>;\n}\n\n/**\n * Constructor shape for `tailor.idp.Client`.\n * @internal\n */\nexport interface IdpClientConstructor {\n new (config: ClientConfig): IdpClientInstance;\n}\n\n/**\n * Platform API surface for `tailor.idp`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.idp`.\n * @internal\n */\nexport interface TailorIdpAPI {\n Client: IdpClientConstructor;\n}\n\n/**\n * IDP Client for user management operations.\n *\n * Wraps the platform-provided `tailor.idp.Client` and exposes the same surface.\n */\nclass Client {\n #impl: IdpClientInstance;\n\n constructor(config: ClientConfig) {\n this.#impl = new (globalThis as unknown as { tailor: { idp: TailorIdpAPI } }).tailor.idp.Client(\n config,\n );\n }\n\n /**\n * List users in the namespace with optional filtering and pagination.\n * @param options - Pagination and filter options\n * @returns Page of users with `nextPageToken` and `totalCount`\n */\n users(options?: ListUsersOptions): Promise<ListUsersResponse> {\n return this.#impl.users(options);\n }\n\n /**\n * Get a user by ID.\n * @param userId - IDP user ID\n * @returns The matching user\n */\n user(userId: string): Promise<User> {\n return this.#impl.user(userId);\n }\n\n /**\n * Get a user by name.\n * @param name - IDP user name\n * @returns The matching user\n */\n userByName(name: string): Promise<User> {\n return this.#impl.userByName(name);\n }\n\n /**\n * Create a new user.\n * @param input - User attributes\n * @returns The newly created user\n */\n createUser(input: CreateUserInput): Promise<User> {\n return this.#impl.createUser(input);\n }\n\n /**\n * Update an existing user.\n * @param input - User ID plus attributes to update\n * @returns The updated user\n */\n updateUser(input: UpdateUserInput): Promise<User> {\n return this.#impl.updateUser(input);\n }\n\n /**\n * Delete a user by ID.\n * @param userId - IDP user ID\n * @returns `true` when the user was deleted\n */\n deleteUser(userId: string): Promise<boolean> {\n return this.#impl.deleteUser(userId);\n }\n\n /**\n * Send a password reset email to a user.\n * @param input - Target user ID and redirect URI\n * @returns `true` when the email was queued\n */\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean> {\n return this.#impl.sendPasswordResetEmail(input);\n }\n\n /**\n * Unenroll an MFA factor from a user.\n * @param input - Target user ID and factor ID (see {@link User.mfaFactorIds})\n * @returns `true` when the factor was removed\n */\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean> {\n return this.#impl.unenrollMfa(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.idp`. */\nexport const idp: TailorIdpAPI = { Client };\n"],"mappings":"AAkOA,MAAa,EAAoB,CAAE,YApFtB,CACX,GAEA,YAAY,EAAsB,CAChC,KAAKA,GAAQ,IAAK,WAA4D,OAAO,IAAI,OACvF,CACF,CACF,CAOA,MAAM,EAAwD,CAC5D,OAAO,KAAKA,GAAM,MAAM,CAAO,CACjC,CAOA,KAAK,EAA+B,CAClC,OAAO,KAAKA,GAAM,KAAK,CAAM,CAC/B,CAOA,WAAW,EAA6B,CACtC,OAAO,KAAKA,GAAM,WAAW,CAAI,CACnC,CAOA,WAAW,EAAuC,CAChD,OAAO,KAAKA,GAAM,WAAW,CAAK,CACpC,CAOA,WAAW,EAAuC,CAChD,OAAO,KAAKA,GAAM,WAAW,CAAK,CACpC,CAOA,WAAW,EAAkC,CAC3C,OAAO,KAAKA,GAAM,WAAW,CAAM,CACrC,CAOA,uBAAuB,EAAsD,CAC3E,OAAO,KAAKA,GAAM,uBAAuB,CAAK,CAChD,CAOA,YAAY,EAA2C,CACrD,OAAO,KAAKA,GAAM,YAAY,CAAK,CACrC,CACF,CAI0C"}
@@ -0,0 +1,2 @@
1
+ import{SpanStatusCode as e,trace as t}from"@opentelemetry/api";function createTracingInterceptor(){return n=>async r=>t.getTracer(`tailor`).startActiveSpan(`rpc.${r.method.name}`,async t=>{t.setAttribute(`rpc.method`,r.method.name),t.setAttribute(`rpc.service`,`OperatorService`),t.setAttribute(`rpc.system`,`connect-rpc`);try{let i=await n(r);return t.setStatus({code:e.OK}),i}catch(n){throw t.setStatus({code:e.ERROR}),n instanceof Error&&t.recordException(n),n}finally{t.end()}})}export{createTracingInterceptor};
2
+ //# sourceMappingURL=interceptor-DQg3cR_9.mjs.map