@tailor-platform/sdk 1.25.4 → 1.26.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 (32) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/{application-DegTCDd8.mjs → application-CxH6Yp54.mjs} +1 -1
  3. package/dist/{application-91Th6tm6.mjs → application-D9xahQRQ.mjs} +2066 -1968
  4. package/dist/application-D9xahQRQ.mjs.map +1 -0
  5. package/dist/cli/index.mjs +152 -3
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/cli/lib.d.mts +350 -8
  8. package/dist/cli/lib.mjs +2 -2
  9. package/dist/configure/index.d.mts +5 -5
  10. package/dist/configure/index.mjs.map +1 -1
  11. package/dist/{env-uBeVwE9B.d.mts → env-CSsVESbH.d.mts} +2 -2
  12. package/dist/{index-Bu12qy3m.d.mts → index-BJg0DTbR.d.mts} +4 -4
  13. package/dist/{index-CT53egux.d.mts → index-BKy-OC5C.d.mts} +2 -2
  14. package/dist/{index-cZilKprY.d.mts → index-BtYPY8ya.d.mts} +2 -2
  15. package/dist/{index-BD-K97-C.d.mts → index-DgRShBpu.d.mts} +2 -2
  16. package/dist/{index-D1J5SfyK.d.mts → index-DkJbItB-.d.mts} +2 -2
  17. package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
  18. package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
  19. package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
  20. package/dist/plugin/builtin/seed/index.d.mts +1 -1
  21. package/dist/plugin/index.d.mts +2 -2
  22. package/dist/{plugin-zY5wvV82.d.mts → plugin-B1hNwcCC.d.mts} +15 -3
  23. package/dist/{query-kb_4EQp4.mjs → query-B8ml6ClT.mjs} +454 -358
  24. package/dist/query-B8ml6ClT.mjs.map +1 -0
  25. package/dist/utils/test/index.d.mts +2 -2
  26. package/dist/{workflow.generated-v1LXRuB6.d.mts → workflow.generated-Bm4b8hEk.d.mts} +2 -2
  27. package/docs/cli/setup.md +82 -0
  28. package/docs/cli-reference.md +8 -0
  29. package/docs/services/auth.md +33 -0
  30. package/package.json +4 -4
  31. package/dist/application-91Th6tm6.mjs.map +0 -1
  32. package/dist/query-kb_4EQp4.mjs.map +0 -1
@@ -26,12 +26,12 @@ import { findUpSync } from "find-up-simple";
26
26
  import ml from "multiline-ts";
27
27
  import { xdgConfig } from "xdg-basedir";
28
28
  import * as crypto from "node:crypto";
29
+ import * as rolldown from "rolldown";
30
+ import * as fs from "node:fs/promises";
31
+ import { parseSync } from "oxc-parser";
29
32
  import { pathToFileURL } from "node:url";
30
33
  import * as inflection from "inflection";
31
- import { parseSync } from "oxc-parser";
32
- import * as rolldown from "rolldown";
33
34
  import * as globals from "globals";
34
- import * as fs from "node:fs/promises";
35
35
 
36
36
  //#region src/cli/shared/logger.ts
37
37
  /**
@@ -325,7 +325,7 @@ const file_tailor_v1_secret_manager_resource = /* @__PURE__ */ fileDesc("Cid0YWl
325
325
  /**
326
326
  * Describes the file tailor/v1/auth_resource.proto.
327
327
  */
328
- const file_tailor_v1_auth_resource = /* @__PURE__ */ fileDesc("Ch10YWlsb3IvdjEvYXV0aF9yZXNvdXJjZS5wcm90bxIJdGFpbG9yLnYxIlYKC0F1dGhTZXJ2aWNlEicKCW5hbWVzcGFjZRgBIAEoCzIULnRhaWxvci52MS5OYW1lc3BhY2USHgoWcHVibGlzaF9zZXNzaW9uX2V2ZW50cxgCIAEoCCK0BgoNQXV0aElEUENvbmZpZxI2CgRuYW1lGAEgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjQKCWF1dGhfdHlwZRgCIAEoDjIhLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLkF1dGhUeXBlEi8KBmNvbmZpZxgDIAEoCzIfLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLkNvbmZpZxq4AQoGQ29uZmlnEjMKBG9pZGMYASABKAsyIy50YWlsb3IudjEuQXV0aElEUENvbmZpZy5PSURDQ29uZmlnSAASMwoEc2FtbBgCIAEoCzIjLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLlNBTUxDb25maWdIABI6CghpZF90b2tlbhgDIAEoCzImLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLklEVG9rZW5Db25maWdIAEIICgZjb25maWcamAEKCk9JRENDb25maWcSFQoNY2xpZW50X2lkX2tleRgBIAEoCRIxChFjbGllbnRfc2VjcmV0X2tleRgCIAEoCzIWLnRhaWxvci52MS5TZWNyZXRWYWx1ZRIUCgxwcm92aWRlcl91cmwYAyABKAkSEgoKaXNzdWVyX3VybBgEIAEoCRIWCg51c2VybmFtZV9jbGFpbRgFIAEoCRphCgpTQU1MQ29uZmlnEhQKDG1ldGFkYXRhX3VybBgBIAEoCRIUCgxyYXdfbWV0YWRhdGEYBCABKAkSGwoTZW5hYmxlX3NpZ25fcmVxdWVzdBgFIAEoCEoECAIQA0oECAMQBBpkCg1JRFRva2VuQ29uZmlnEhQKDHByb3ZpZGVyX3VybBgBIAEoCRIRCgljbGllbnRfaWQYAiABKAkSEgoKaXNzdWVyX3VybBgDIAEoCRIWCg51c2VybmFtZV9jbGFpbRgEIAEoCSJlCghBdXRoVHlwZRIZChVBVVRIX1RZUEVfVU5TUEVDSUZJRUQQABISCg5BVVRIX1RZUEVfT0lEQxABEhIKDkFVVEhfVFlQRV9TQU1MEAISFgoSQVVUSF9UWVBFX0lEX1RPS0VOEAMirQYKGVVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcSFAoIcHJvdmlkZXIYASABKAlCAhgBElMKDXByb3ZpZGVyX3R5cGUYAiABKA4yPC50YWlsb3IudjEuVXNlclByb2ZpbGVQcm92aWRlckNvbmZpZy5Vc2VyUHJvZmlsZVByb3ZpZGVyVHlwZRI7CgZjb25maWcYAyABKAsyKy50YWlsb3IudjEuVXNlclByb2ZpbGVQcm92aWRlckNvbmZpZy5Db25maWcaYwoGQ29uZmlnEk8KCHRhaWxvcmRiGAEgASgLMjsudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcuVGFpbG9yREJQcm92aWRlckNvbmZpZ0gAQggKBmNvbmZpZxqSAwoWVGFpbG9yREJQcm92aWRlckNvbmZpZxI7CgluYW1lc3BhY2UYASABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSLQoEdHlwZRgCIAEoCUIfukgcchoyGF5bQS1aXVthLXpBLVowLTldezAsNjJ9JBIWCg51c2VybmFtZV9maWVsZBgDIAEoCRIZChFhdHRyaWJ1dGVzX2ZpZWxkcxgEIAMoCRIXCg90ZW5hbnRfaWRfZmllbGQYBSABKAkSigEKDWF0dHJpYnV0ZV9tYXAYBiADKAsyTS50YWlsb3IudjEuVXNlclByb2ZpbGVQcm92aWRlckNvbmZpZy5UYWlsb3JEQlByb3ZpZGVyQ29uZmlnLkF0dHJpYnV0ZU1hcEVudHJ5QiS6SCGaAR4iHHIaMhheW2Etel1bMC05YS16QS1aXXswLDYyfSQaMwoRQXR0cmlidXRlTWFwRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJuChdVc2VyUHJvZmlsZVByb3ZpZGVyVHlwZRIqCiZVU0VSX1BST0ZJTEVfUFJPVklERVJfVFlQRV9VTlNQRUNJRklFRBAAEicKI1VTRVJfUFJPRklMRV9QUk9WSURFUl9UWVBFX1RBSUxPUkRCEAEivgMKFFRlbmFudFByb3ZpZGVyQ29uZmlnEhAKCHByb3ZpZGVyGAEgASgJEkkKDXByb3ZpZGVyX3R5cGUYAiABKA4yMi50YWlsb3IudjEuVGVuYW50UHJvdmlkZXJDb25maWcuVGVuYW50UHJvdmlkZXJUeXBlEjYKBmNvbmZpZxgDIAEoCzImLnRhaWxvci52MS5UZW5hbnRQcm92aWRlckNvbmZpZy5Db25maWcaXgoGQ29uZmlnEkoKCHRhaWxvcmRiGAEgASgLMjYudGFpbG9yLnYxLlRlbmFudFByb3ZpZGVyQ29uZmlnLlRhaWxvckRCUHJvdmlkZXJDb25maWdIAEIICgZjb25maWcaUgoWVGFpbG9yREJQcm92aWRlckNvbmZpZxIRCgluYW1lc3BhY2UYASABKAkSDAoEdHlwZRgCIAEoCRIXCg9zaWduYXR1cmVfZmllbGQYAyABKAkiXQoSVGVuYW50UHJvdmlkZXJUeXBlEiQKIFRFTkFOVF9QUk9WSURFUl9UWVBFX1VOU1BFQ0lGSUVEEAASIQodVEVOQU5UX1BST1ZJREVSX1RZUEVfVEFJTE9SREIQASI7CgtBdXRoSW52b2tlchIRCgluYW1lc3BhY2UYASABKAkSGQoRbWFjaGluZV91c2VyX25hbWUYAiABKAkiSAoTUGVyc29uYWxBY2Nlc3NUb2tlbhIMCgRuYW1lGAEgASgJEiMKBnNjb3BlcxgCIAMoDjITLnRhaWxvci52MS5QQVRTY29wZSLGAwoLTWFjaGluZVVzZXISCgoCaWQYASABKAkSNgoEbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIWCgljbGllbnRfaWQYAyABKAlCA+BBAxIaCg1jbGllbnRfc2VjcmV0GAQgASgJQgPgQQMSIQoKYXR0cmlidXRlcxgFIAMoCUINukgKkgEHIgVyA7ABARIzCgpjcmVhdGVkX2F0GAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDEjMKCnVwZGF0ZWRfYXQYByABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgPgQQMSZQoNYXR0cmlidXRlX21hcBgIIAMoCzIoLnRhaWxvci52MS5NYWNoaW5lVXNlci5BdHRyaWJ1dGVNYXBFbnRyeUIkukghmgEeIhxyGjIYXlthLXpdWzAtOWEtekEtWl17MCw2Mn0kGksKEUF0dHJpYnV0ZU1hcEVudHJ5EgsKA2tleRgBIAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToCOAEi3gIKDkF1dGhTQ0lNQ29uZmlnEkMKEW1hY2hpbmVfdXNlcl9uYW1lGAEgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEkcKEmF1dGhvcml6YXRpb25fdHlwZRgCIAEoDjIrLnRhaWxvci52MS5BdXRoU0NJTUNvbmZpZy5BdXRob3JpemF0aW9uVHlwZRIvCg1iZWFyZXJfc2VjcmV0GAogASgLMhYudGFpbG9yLnYxLlNlY3JldFZhbHVlSAAidQoRQXV0aG9yaXphdGlvblR5cGUSIgoeQVVUSE9SSVpBVElPTl9UWVBFX1VOU1BFQ0lGSUVEEAASHQoZQVVUSE9SSVpBVElPTl9UWVBFX0JFQVJFUhABEh0KGUFVVEhPUklaQVRJT05fVFlQRV9PQVVUSDIQAkIWChRhdXRob3JpemF0aW9uX2NvbmZpZyLDAgoQQXV0aFNDSU1SZXNvdXJjZRI/CgRuYW1lGAEgASgJQjG6SC5yLDIqXltBLVphLXowLTldW0EtWmEtejAtOS1dezEsNjF9W0EtWmEtejAtOV0kEkUKE3RhaWxvcl9kYl9uYW1lc3BhY2UYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNwoOdGFpbG9yX2RiX3R5cGUYAyABKAlCH7pIHHIaMhheW0EtWl1bYS16QS1aMC05XXswLDYyfSQSPgoRYXR0cmlidXRlX21hcHBpbmcYBCADKAsyIy50YWlsb3IudjEuQXV0aFNDSU1BdHRyaWJ1dGVNYXBwaW5nEi4KC2NvcmVfc2NoZW1hGAUgASgLMhkudGFpbG9yLnYxLkF1dGhTQ0lNU2NoZW1hIkYKGEF1dGhTQ0lNQXR0cmlidXRlTWFwcGluZxIXCg90YWlsb3JfZGJfZmllbGQYASABKAkSEQoJc2NpbV9wYXRoGAIgASgJIlAKDkF1dGhTQ0lNU2NoZW1hEgwKBG5hbWUYASABKAkSMAoKYXR0cmlidXRlcxgCIAMoCzIcLnRhaWxvci52MS5BdXRoU0NJTUF0dHJpYnV0ZSLZBQoRQXV0aFNDSU1BdHRyaWJ1dGUSLwoEdHlwZRgBIAEoDjIhLnRhaWxvci52MS5BdXRoU0NJTUF0dHJpYnV0ZS5UeXBlEi4KBG5hbWUYAiABKAlCILpIHXIbMhleW0EtWmEtel1bYS16QS1aMC05XyQtXSokEhMKC2Rlc2NyaXB0aW9uGAMgASgJEjsKCm11dGFiaWxpdHkYBCABKA4yJy50YWlsb3IudjEuQXV0aFNDSU1BdHRyaWJ1dGUuTXV0YWJpbGl0eRIQCghyZXF1aXJlZBgFIAEoCBIUCgxtdWx0aV92YWx1ZWQYBiABKAgSOwoKdW5pcXVlbmVzcxgHIAEoDjInLnRhaWxvci52MS5BdXRoU0NJTUF0dHJpYnV0ZS5VbmlxdWVuZXNzEhgKEGNhbm9uaWNhbF92YWx1ZXMYCCADKAkSNAoOc3ViX2F0dHJpYnV0ZXMYCSADKAsyHC50YWlsb3IudjEuQXV0aFNDSU1BdHRyaWJ1dGUidQoEVHlwZRIUChBUWVBFX1VOU1BFQ0lGSUVEEAASEAoMVFlQRV9DT01QTEVYEAESDwoLVFlQRV9TVFJJTkcQAhIPCgtUWVBFX05VTUJFUhADEhAKDFRZUEVfQk9PTEVBThAEEhEKDVRZUEVfREFURVRJTUUQBSJ4CgpNdXRhYmlsaXR5EhoKFk1VVEFCSUxJVFlfVU5TUEVDSUZJRUQQABIYChRNVVRBQklMSVRZX1JFQURfT05MWRABEhkKFU1VVEFCSUxJVFlfUkVBRF9XUklURRACEhkKFU1VVEFCSUxJVFlfV1JJVEVfT05MWRADImsKClVuaXF1ZW5lc3MSGgoWVU5JUVVFTkVTU19VTlNQRUNJRklFRBAAEhMKD1VOSVFVRU5FU1NfTk9ORRABEhUKEVVOSVFVRU5FU1NfU0VSVkVSEAISFQoRVU5JUVVFTkVTU19HTE9CQUwQAyK+BAoOQXV0aENvbm5lY3Rpb24SNgoEbmFtZRgBIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIsCgR0eXBlGAIgASgOMh4udGFpbG9yLnYxLkF1dGhDb25uZWN0aW9uLlR5cGUSRgoGb2F1dGgyGAMgASgLMjQudGFpbG9yLnYxLkF1dGhDb25uZWN0aW9uLkF1dGhDb25uZWN0aW9uT0F1dGgyQ29uZmlnSAASMwoKY3JlYXRlZF9hdBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCA+BBAxqIAgoaQXV0aENvbm5lY3Rpb25PQXV0aDJDb25maWcSFAoMcHJvdmlkZXJfdXJsGAEgASgJEhIKCmlzc3Vlcl91cmwYAiABKAkSEQoJY2xpZW50X2lkGAMgASgJEhoKDWNsaWVudF9zZWNyZXQYBCABKAlCA+BBBBJHCghhdXRoX3VybBgFIAEoCUI1ukgy2AEBci0yKF5odHRwczovL1tBLVphLXowLTkuLV0rKDpbMC05XSspPygvLiopPySIAQESSAoJdG9rZW5fdXJsGAYgASgJQjW6SDLYAQFyLTIoXmh0dHBzOi8vW0EtWmEtejAtOS4tXSsoOlswLTldKyk/KC8uKik/JIgBASItCgRUeXBlEhQKEFRZUEVfVU5TUEVDSUZJRUQQABIPCgtUWVBFX09BVVRIMhABQg8KBmNvbmZpZxIFukgCCAEiowcKEEF1dGhPQXV0aDJDbGllbnQSDAoEbmFtZRgBIAEoCRITCgtkZXNjcmlwdGlvbhgCIAEoCRI6CgtncmFudF90eXBlcxgDIAMoDjIlLnRhaWxvci52MS5BdXRoT0F1dGgyQ2xpZW50LkdyYW50VHlwZRIVCg1yZWRpcmVjdF91cmlzGAQgAygJEhYKCWNsaWVudF9pZBgFIAEoCUID4EEDEhoKDWNsaWVudF9zZWNyZXQYBiABKAlCA+BBAxIzCgpjcmVhdGVkX2F0GAcgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDEkoKC2NsaWVudF90eXBlGAggASgOMiYudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQuQ2xpZW50VHlwZUINukgK2AEBggEEEAEgABJKChVhY2Nlc3NfdG9rZW5fbGlmZXRpbWUYCSABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb25CELpIDaoBCiIECICjBTICCDwSSwoWcmVmcmVzaF90b2tlbl9saWZldGltZRgKIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbkIQukgNqgEKIgQIgPUkMgIIPBIUCgxyZXF1aXJlX2Rwb3AYCyABKAgiaAoJR3JhbnRUeXBlEhoKFkdSQU5UX1RZUEVfVU5TUEVDSUZJRUQQABIhCh1HUkFOVF9UWVBFX0FVVEhPUklaQVRJT05fQ09ERRABEhwKGEdSQU5UX1RZUEVfUkVGUkVTSF9UT0tFThACIngKCkNsaWVudFR5cGUSGwoXQ0xJRU5UX1RZUEVfVU5TUEVDSUZJRUQQABIcChhDTElFTlRfVFlQRV9DT05GSURFTlRJQUwQARIWChJDTElFTlRfVFlQRV9QVUJMSUMQAhIXChNDTElFTlRfVFlQRV9CUk9XU0VSEAM60AG6SMwBGskBCiJicm93c2VyX2NsaWVudF9jYW5ub3RfcmVxdWlyZV9kcG9wEjZyZXF1aXJlX2Rwb3AgY2Fubm90IGJlIHNldCB0byB0cnVlIGZvciBicm93c2VyIGNsaWVudHMaa3RoaXMuY2xpZW50X3R5cGUgIT0gdGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQuQ2xpZW50VHlwZS5DTElFTlRfVFlQRV9CUk9XU0VSIHx8IHRoaXMucmVxdWlyZV9kcG9wID09IGZhbHNlIrcBChdDb250cm9scGxhbmVNYWNoaW5lVXNlchIPCgJpZBgBIAEoCUID4EEDEgwKBG5hbWUYAiABKAkSEwoLZGVzY3JpcHRpb24YAyABKAkSHAoPb3JnYW5pemF0aW9uX2lkGAQgASgJQgPgQQMSFgoJZm9sZGVyX2lkGAUgASgJQgPgQQMSFgoJY2xpZW50X2lkGAYgASgJQgPgQQMSGgoNY2xpZW50X3NlY3JldBgHIAEoCUID4EEDKk4KCFBBVFNjb3BlEhkKFVBBVF9TQ09QRV9VTlNQRUNJRklFRBAAEhIKDlBBVF9TQ09QRV9SRUFEEAESEwoPUEFUX1NDT1BFX1dSSVRFEAJiBnByb3RvMw", [
328
+ const file_tailor_v1_auth_resource = /* @__PURE__ */ fileDesc("Ch10YWlsb3IvdjEvYXV0aF9yZXNvdXJjZS5wcm90bxIJdGFpbG9yLnYxIlYKC0F1dGhTZXJ2aWNlEicKCW5hbWVzcGFjZRgBIAEoCzIULnRhaWxvci52MS5OYW1lc3BhY2USHgoWcHVibGlzaF9zZXNzaW9uX2V2ZW50cxgCIAEoCCK0BgoNQXV0aElEUENvbmZpZxI2CgRuYW1lGAEgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjQKCWF1dGhfdHlwZRgCIAEoDjIhLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLkF1dGhUeXBlEi8KBmNvbmZpZxgDIAEoCzIfLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLkNvbmZpZxq4AQoGQ29uZmlnEjMKBG9pZGMYASABKAsyIy50YWlsb3IudjEuQXV0aElEUENvbmZpZy5PSURDQ29uZmlnSAASMwoEc2FtbBgCIAEoCzIjLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLlNBTUxDb25maWdIABI6CghpZF90b2tlbhgDIAEoCzImLnRhaWxvci52MS5BdXRoSURQQ29uZmlnLklEVG9rZW5Db25maWdIAEIICgZjb25maWcamAEKCk9JRENDb25maWcSFQoNY2xpZW50X2lkX2tleRgBIAEoCRIxChFjbGllbnRfc2VjcmV0X2tleRgCIAEoCzIWLnRhaWxvci52MS5TZWNyZXRWYWx1ZRIUCgxwcm92aWRlcl91cmwYAyABKAkSEgoKaXNzdWVyX3VybBgEIAEoCRIWCg51c2VybmFtZV9jbGFpbRgFIAEoCRphCgpTQU1MQ29uZmlnEhQKDG1ldGFkYXRhX3VybBgBIAEoCRIUCgxyYXdfbWV0YWRhdGEYBCABKAkSGwoTZW5hYmxlX3NpZ25fcmVxdWVzdBgFIAEoCEoECAIQA0oECAMQBBpkCg1JRFRva2VuQ29uZmlnEhQKDHByb3ZpZGVyX3VybBgBIAEoCRIRCgljbGllbnRfaWQYAiABKAkSEgoKaXNzdWVyX3VybBgDIAEoCRIWCg51c2VybmFtZV9jbGFpbRgEIAEoCSJlCghBdXRoVHlwZRIZChVBVVRIX1RZUEVfVU5TUEVDSUZJRUQQABISCg5BVVRIX1RZUEVfT0lEQxABEhIKDkFVVEhfVFlQRV9TQU1MEAISFgoSQVVUSF9UWVBFX0lEX1RPS0VOEAMirQYKGVVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcSFAoIcHJvdmlkZXIYASABKAlCAhgBElMKDXByb3ZpZGVyX3R5cGUYAiABKA4yPC50YWlsb3IudjEuVXNlclByb2ZpbGVQcm92aWRlckNvbmZpZy5Vc2VyUHJvZmlsZVByb3ZpZGVyVHlwZRI7CgZjb25maWcYAyABKAsyKy50YWlsb3IudjEuVXNlclByb2ZpbGVQcm92aWRlckNvbmZpZy5Db25maWcaYwoGQ29uZmlnEk8KCHRhaWxvcmRiGAEgASgLMjsudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcuVGFpbG9yREJQcm92aWRlckNvbmZpZ0gAQggKBmNvbmZpZxqSAwoWVGFpbG9yREJQcm92aWRlckNvbmZpZxI7CgluYW1lc3BhY2UYASABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSLQoEdHlwZRgCIAEoCUIfukgcchoyGF5bQS1aXVthLXpBLVowLTldezAsNjJ9JBIWCg51c2VybmFtZV9maWVsZBgDIAEoCRIZChFhdHRyaWJ1dGVzX2ZpZWxkcxgEIAMoCRIXCg90ZW5hbnRfaWRfZmllbGQYBSABKAkSigEKDWF0dHJpYnV0ZV9tYXAYBiADKAsyTS50YWlsb3IudjEuVXNlclByb2ZpbGVQcm92aWRlckNvbmZpZy5UYWlsb3JEQlByb3ZpZGVyQ29uZmlnLkF0dHJpYnV0ZU1hcEVudHJ5QiS6SCGaAR4iHHIaMhheW2Etel1bMC05YS16QS1aXXswLDYyfSQaMwoRQXR0cmlidXRlTWFwRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJuChdVc2VyUHJvZmlsZVByb3ZpZGVyVHlwZRIqCiZVU0VSX1BST0ZJTEVfUFJPVklERVJfVFlQRV9VTlNQRUNJRklFRBAAEicKI1VTRVJfUFJPRklMRV9QUk9WSURFUl9UWVBFX1RBSUxPUkRCEAEivgMKFFRlbmFudFByb3ZpZGVyQ29uZmlnEhAKCHByb3ZpZGVyGAEgASgJEkkKDXByb3ZpZGVyX3R5cGUYAiABKA4yMi50YWlsb3IudjEuVGVuYW50UHJvdmlkZXJDb25maWcuVGVuYW50UHJvdmlkZXJUeXBlEjYKBmNvbmZpZxgDIAEoCzImLnRhaWxvci52MS5UZW5hbnRQcm92aWRlckNvbmZpZy5Db25maWcaXgoGQ29uZmlnEkoKCHRhaWxvcmRiGAEgASgLMjYudGFpbG9yLnYxLlRlbmFudFByb3ZpZGVyQ29uZmlnLlRhaWxvckRCUHJvdmlkZXJDb25maWdIAEIICgZjb25maWcaUgoWVGFpbG9yREJQcm92aWRlckNvbmZpZxIRCgluYW1lc3BhY2UYASABKAkSDAoEdHlwZRgCIAEoCRIXCg9zaWduYXR1cmVfZmllbGQYAyABKAkiXQoSVGVuYW50UHJvdmlkZXJUeXBlEiQKIFRFTkFOVF9QUk9WSURFUl9UWVBFX1VOU1BFQ0lGSUVEEAASIQodVEVOQU5UX1BST1ZJREVSX1RZUEVfVEFJTE9SREIQASI7CgtBdXRoSW52b2tlchIRCgluYW1lc3BhY2UYASABKAkSGQoRbWFjaGluZV91c2VyX25hbWUYAiABKAkiSAoTUGVyc29uYWxBY2Nlc3NUb2tlbhIMCgRuYW1lGAEgASgJEiMKBnNjb3BlcxgCIAMoDjITLnRhaWxvci52MS5QQVRTY29wZSLGAwoLTWFjaGluZVVzZXISCgoCaWQYASABKAkSNgoEbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIWCgljbGllbnRfaWQYAyABKAlCA+BBAxIaCg1jbGllbnRfc2VjcmV0GAQgASgJQgPgQQMSIQoKYXR0cmlidXRlcxgFIAMoCUINukgKkgEHIgVyA7ABARIzCgpjcmVhdGVkX2F0GAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDEjMKCnVwZGF0ZWRfYXQYByABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgPgQQMSZQoNYXR0cmlidXRlX21hcBgIIAMoCzIoLnRhaWxvci52MS5NYWNoaW5lVXNlci5BdHRyaWJ1dGVNYXBFbnRyeUIkukghmgEeIhxyGjIYXlthLXpdWzAtOWEtekEtWl17MCw2Mn0kGksKEUF0dHJpYnV0ZU1hcEVudHJ5EgsKA2tleRgBIAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToCOAEi3gIKDkF1dGhTQ0lNQ29uZmlnEkMKEW1hY2hpbmVfdXNlcl9uYW1lGAEgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEkcKEmF1dGhvcml6YXRpb25fdHlwZRgCIAEoDjIrLnRhaWxvci52MS5BdXRoU0NJTUNvbmZpZy5BdXRob3JpemF0aW9uVHlwZRIvCg1iZWFyZXJfc2VjcmV0GAogASgLMhYudGFpbG9yLnYxLlNlY3JldFZhbHVlSAAidQoRQXV0aG9yaXphdGlvblR5cGUSIgoeQVVUSE9SSVpBVElPTl9UWVBFX1VOU1BFQ0lGSUVEEAASHQoZQVVUSE9SSVpBVElPTl9UWVBFX0JFQVJFUhABEh0KGUFVVEhPUklaQVRJT05fVFlQRV9PQVVUSDIQAkIWChRhdXRob3JpemF0aW9uX2NvbmZpZyLDAgoQQXV0aFNDSU1SZXNvdXJjZRI/CgRuYW1lGAEgASgJQjG6SC5yLDIqXltBLVphLXowLTldW0EtWmEtejAtOS1dezEsNjF9W0EtWmEtejAtOV0kEkUKE3RhaWxvcl9kYl9uYW1lc3BhY2UYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNwoOdGFpbG9yX2RiX3R5cGUYAyABKAlCH7pIHHIaMhheW0EtWl1bYS16QS1aMC05XXswLDYyfSQSPgoRYXR0cmlidXRlX21hcHBpbmcYBCADKAsyIy50YWlsb3IudjEuQXV0aFNDSU1BdHRyaWJ1dGVNYXBwaW5nEi4KC2NvcmVfc2NoZW1hGAUgASgLMhkudGFpbG9yLnYxLkF1dGhTQ0lNU2NoZW1hIkYKGEF1dGhTQ0lNQXR0cmlidXRlTWFwcGluZxIXCg90YWlsb3JfZGJfZmllbGQYASABKAkSEQoJc2NpbV9wYXRoGAIgASgJIlAKDkF1dGhTQ0lNU2NoZW1hEgwKBG5hbWUYASABKAkSMAoKYXR0cmlidXRlcxgCIAMoCzIcLnRhaWxvci52MS5BdXRoU0NJTUF0dHJpYnV0ZSLZBQoRQXV0aFNDSU1BdHRyaWJ1dGUSLwoEdHlwZRgBIAEoDjIhLnRhaWxvci52MS5BdXRoU0NJTUF0dHJpYnV0ZS5UeXBlEi4KBG5hbWUYAiABKAlCILpIHXIbMhleW0EtWmEtel1bYS16QS1aMC05XyQtXSokEhMKC2Rlc2NyaXB0aW9uGAMgASgJEjsKCm11dGFiaWxpdHkYBCABKA4yJy50YWlsb3IudjEuQXV0aFNDSU1BdHRyaWJ1dGUuTXV0YWJpbGl0eRIQCghyZXF1aXJlZBgFIAEoCBIUCgxtdWx0aV92YWx1ZWQYBiABKAgSOwoKdW5pcXVlbmVzcxgHIAEoDjInLnRhaWxvci52MS5BdXRoU0NJTUF0dHJpYnV0ZS5VbmlxdWVuZXNzEhgKEGNhbm9uaWNhbF92YWx1ZXMYCCADKAkSNAoOc3ViX2F0dHJpYnV0ZXMYCSADKAsyHC50YWlsb3IudjEuQXV0aFNDSU1BdHRyaWJ1dGUidQoEVHlwZRIUChBUWVBFX1VOU1BFQ0lGSUVEEAASEAoMVFlQRV9DT01QTEVYEAESDwoLVFlQRV9TVFJJTkcQAhIPCgtUWVBFX05VTUJFUhADEhAKDFRZUEVfQk9PTEVBThAEEhEKDVRZUEVfREFURVRJTUUQBSJ4CgpNdXRhYmlsaXR5EhoKFk1VVEFCSUxJVFlfVU5TUEVDSUZJRUQQABIYChRNVVRBQklMSVRZX1JFQURfT05MWRABEhkKFU1VVEFCSUxJVFlfUkVBRF9XUklURRACEhkKFU1VVEFCSUxJVFlfV1JJVEVfT05MWRADImsKClVuaXF1ZW5lc3MSGgoWVU5JUVVFTkVTU19VTlNQRUNJRklFRBAAEhMKD1VOSVFVRU5FU1NfTk9ORRABEhUKEVVOSVFVRU5FU1NfU0VSVkVSEAISFQoRVU5JUVVFTkVTU19HTE9CQUwQAyKYAQoIQXV0aEhvb2sSOAoKaG9va19wb2ludBgBIAEoDjIYLnRhaWxvci52MS5BdXRoSG9va1BvaW50Qgq6SAeCAQQQASAAEhsKCnNjcmlwdF9yZWYYAiABKAlCB7pIBHICEAESLwoHaW52b2tlchgEIAEoCzIWLnRhaWxvci52MS5BdXRoSW52b2tlckIGukgDyAEBSgQIAxAEIr4ECg5BdXRoQ29ubmVjdGlvbhI2CgRuYW1lGAEgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEiwKBHR5cGUYAiABKA4yHi50YWlsb3IudjEuQXV0aENvbm5lY3Rpb24uVHlwZRJGCgZvYXV0aDIYAyABKAsyNC50YWlsb3IudjEuQXV0aENvbm5lY3Rpb24uQXV0aENvbm5lY3Rpb25PQXV0aDJDb25maWdIABIzCgpjcmVhdGVkX2F0GAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEID4EEDGogCChpBdXRoQ29ubmVjdGlvbk9BdXRoMkNvbmZpZxIUCgxwcm92aWRlcl91cmwYASABKAkSEgoKaXNzdWVyX3VybBgCIAEoCRIRCgljbGllbnRfaWQYAyABKAkSGgoNY2xpZW50X3NlY3JldBgEIAEoCUID4EEEEkcKCGF1dGhfdXJsGAUgASgJQjW6SDLYAQFyLTIoXmh0dHBzOi8vW0EtWmEtejAtOS4tXSsoOlswLTldKyk/KC8uKik/JIgBARJICgl0b2tlbl91cmwYBiABKAlCNbpIMtgBAXItMiheaHR0cHM6Ly9bQS1aYS16MC05Li1dKyg6WzAtOV0rKT8oLy4qKT8kiAEBIi0KBFR5cGUSFAoQVFlQRV9VTlNQRUNJRklFRBAAEg8KC1RZUEVfT0FVVEgyEAFCDwoGY29uZmlnEgW6SAIIASKjBwoQQXV0aE9BdXRoMkNsaWVudBIMCgRuYW1lGAEgASgJEhMKC2Rlc2NyaXB0aW9uGAIgASgJEjoKC2dyYW50X3R5cGVzGAMgAygOMiUudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQuR3JhbnRUeXBlEhUKDXJlZGlyZWN0X3VyaXMYBCADKAkSFgoJY2xpZW50X2lkGAUgASgJQgPgQQMSGgoNY2xpZW50X3NlY3JldBgGIAEoCUID4EEDEjMKCmNyZWF0ZWRfYXQYByABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgPgQQMSSgoLY2xpZW50X3R5cGUYCCABKA4yJi50YWlsb3IudjEuQXV0aE9BdXRoMkNsaWVudC5DbGllbnRUeXBlQg26SArYAQGCAQQQASAAEkoKFWFjY2Vzc190b2tlbl9saWZldGltZRgJIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbkIQukgNqgEKIgQIgKMFMgIIPBJLChZyZWZyZXNoX3Rva2VuX2xpZmV0aW1lGAogASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uQhC6SA2qAQoiBAiA9SQyAgg8EhQKDHJlcXVpcmVfZHBvcBgLIAEoCCJoCglHcmFudFR5cGUSGgoWR1JBTlRfVFlQRV9VTlNQRUNJRklFRBAAEiEKHUdSQU5UX1RZUEVfQVVUSE9SSVpBVElPTl9DT0RFEAESHAoYR1JBTlRfVFlQRV9SRUZSRVNIX1RPS0VOEAIieAoKQ2xpZW50VHlwZRIbChdDTElFTlRfVFlQRV9VTlNQRUNJRklFRBAAEhwKGENMSUVOVF9UWVBFX0NPTkZJREVOVElBTBABEhYKEkNMSUVOVF9UWVBFX1BVQkxJQxACEhcKE0NMSUVOVF9UWVBFX0JST1dTRVIQAzrQAbpIzAEayQEKImJyb3dzZXJfY2xpZW50X2Nhbm5vdF9yZXF1aXJlX2Rwb3ASNnJlcXVpcmVfZHBvcCBjYW5ub3QgYmUgc2V0IHRvIHRydWUgZm9yIGJyb3dzZXIgY2xpZW50cxprdGhpcy5jbGllbnRfdHlwZSAhPSB0YWlsb3IudjEuQXV0aE9BdXRoMkNsaWVudC5DbGllbnRUeXBlLkNMSUVOVF9UWVBFX0JST1dTRVIgfHwgdGhpcy5yZXF1aXJlX2Rwb3AgPT0gZmFsc2UitwEKF0NvbnRyb2xwbGFuZU1hY2hpbmVVc2VyEg8KAmlkGAEgASgJQgPgQQMSDAoEbmFtZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRIcCg9vcmdhbml6YXRpb25faWQYBCABKAlCA+BBAxIWCglmb2xkZXJfaWQYBSABKAlCA+BBAxIWCgljbGllbnRfaWQYBiABKAlCA+BBAxIaCg1jbGllbnRfc2VjcmV0GAcgASgJQgPgQQMqTgoIUEFUU2NvcGUSGQoVUEFUX1NDT1BFX1VOU1BFQ0lGSUVEEAASEgoOUEFUX1NDT1BFX1JFQUQQARITCg9QQVRfU0NPUEVfV1JJVEUQAipSCg1BdXRoSG9va1BvaW50Eh8KG0FVVEhfSE9PS19QT0lOVF9VTlNQRUNJRklFRBAAEiAKHEFVVEhfSE9PS19QT0lOVF9CRUZPUkVfTE9HSU4QAWIGcHJvdG8z", [
329
329
  file_buf_validate_validate,
330
330
  file_google_api_field_behavior,
331
331
  file_google_protobuf_duration,
@@ -398,7 +398,7 @@ const AuthSCIMAttribute_Uniqueness = /* @__PURE__ */ tsEnum(AuthSCIMAttribute_Un
398
398
  /**
399
399
  * Describes the enum tailor.v1.AuthOAuth2Client.GrantType.
400
400
  */
401
- const AuthOAuth2Client_GrantTypeSchema = /* @__PURE__ */ enumDesc(file_tailor_v1_auth_resource, 13, 0);
401
+ const AuthOAuth2Client_GrantTypeSchema = /* @__PURE__ */ enumDesc(file_tailor_v1_auth_resource, 14, 0);
402
402
  /**
403
403
  * @generated from enum tailor.v1.AuthOAuth2Client.GrantType
404
404
  */
@@ -406,7 +406,7 @@ const AuthOAuth2Client_GrantType = /* @__PURE__ */ tsEnum(AuthOAuth2Client_Grant
406
406
  /**
407
407
  * Describes the enum tailor.v1.AuthOAuth2Client.ClientType.
408
408
  */
409
- const AuthOAuth2Client_ClientTypeSchema = /* @__PURE__ */ enumDesc(file_tailor_v1_auth_resource, 13, 1);
409
+ const AuthOAuth2Client_ClientTypeSchema = /* @__PURE__ */ enumDesc(file_tailor_v1_auth_resource, 14, 1);
410
410
  /**
411
411
  * @generated from enum tailor.v1.AuthOAuth2Client.ClientType
412
412
  */
@@ -419,13 +419,23 @@ const PATScopeSchema = /* @__PURE__ */ enumDesc(file_tailor_v1_auth_resource, 0)
419
419
  * @generated from enum tailor.v1.PATScope
420
420
  */
421
421
  const PATScope = /* @__PURE__ */ tsEnum(PATScopeSchema);
422
+ /**
423
+ * Describes the enum tailor.v1.AuthHookPoint.
424
+ */
425
+ const AuthHookPointSchema = /* @__PURE__ */ enumDesc(file_tailor_v1_auth_resource, 1);
426
+ /**
427
+ * Auth Hook --------------------------------------------------------
428
+ *
429
+ * @generated from enum tailor.v1.AuthHookPoint
430
+ */
431
+ const AuthHookPoint = /* @__PURE__ */ tsEnum(AuthHookPointSchema);
422
432
 
423
433
  //#endregion
424
434
  //#region ../tailor-proto/src/tailor/v1/auth_pb.js
425
435
  /**
426
436
  * Describes the file tailor/v1/auth.proto.
427
437
  */
428
- const file_tailor_v1_auth = /* @__PURE__ */ fileDesc("ChR0YWlsb3IvdjEvYXV0aC5wcm90bxIJdGFpbG9yLnYxIpwBChhDcmVhdGVBdXRoU2VydmljZVJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIeChZwdWJsaXNoX3Nlc3Npb25fZXZlbnRzGAMgASgIIkkKGUNyZWF0ZUF1dGhTZXJ2aWNlUmVzcG9uc2USLAoMYXV0aF9zZXJ2aWNlGAEgASgLMhYudGFpbG9yLnYxLkF1dGhTZXJ2aWNlIpwBChhVcGRhdGVBdXRoU2VydmljZVJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIeChZwdWJsaXNoX3Nlc3Npb25fZXZlbnRzGAMgASgIIkkKGVVwZGF0ZUF1dGhTZXJ2aWNlUmVzcG9uc2USLAoMYXV0aF9zZXJ2aWNlGAEgASgLMhYudGFpbG9yLnYxLkF1dGhTZXJ2aWNlInwKGERlbGV0ZUF1dGhTZXJ2aWNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kIhsKGURlbGV0ZUF1dGhTZXJ2aWNlUmVzcG9uc2UieQoVR2V0QXV0aFNlcnZpY2VSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiRgoWR2V0QXV0aFNlcnZpY2VSZXNwb25zZRIsCgxhdXRoX3NlcnZpY2UYASABKAsyFi50YWlsb3IudjEuQXV0aFNlcnZpY2UikgEKF0xpc3RBdXRoU2VydmljZXNSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESEgoKcGFnZV90b2tlbhgCIAEoCRIRCglwYWdlX3NpemUYAyABKA0SMAoOcGFnZV9kaXJlY3Rpb24YBCABKA4yGC50YWlsb3IudjEuUGFnZURpcmVjdGlvbiJ3ChhMaXN0QXV0aFNlcnZpY2VzUmVzcG9uc2USLQoNYXV0aF9zZXJ2aWNlcxgBIAMoCzIWLnRhaWxvci52MS5BdXRoU2VydmljZRIXCg9uZXh0X3BhZ2VfdG9rZW4YAiABKAkSEwoLdG90YWxfY291bnQYAyABKAMirAEKGkNyZWF0ZUF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSLAoKaWRwX2NvbmZpZxgDIAEoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnIksKG0NyZWF0ZUF1dGhJRFBDb25maWdSZXNwb25zZRIsCgppZHBfY29uZmlnGAEgASgLMhgudGFpbG9yLnYxLkF1dGhJRFBDb25maWcirAEKGlVwZGF0ZUF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSLAoKaWRwX2NvbmZpZxgDIAEoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnIksKG1VwZGF0ZUF1dGhJRFBDb25maWdSZXNwb25zZRIsCgppZHBfY29uZmlnGAEgASgLMhgudGFpbG9yLnYxLkF1dGhJRFBDb25maWcitgEKGkRlbGV0ZUF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIdChtEZWxldGVBdXRoSURQQ29uZmlnUmVzcG9uc2UiswEKF0dldEF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCJIChhHZXRBdXRoSURQQ29uZmlnUmVzcG9uc2USLAoKaWRwX2NvbmZpZxgBIAEoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnItYBChlMaXN0QXV0aElEUENvbmZpZ3NSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSEgoKcGFnZV90b2tlbhgDIAEoCRIRCglwYWdlX3NpemUYBCABKA0SMAoOcGFnZV9kaXJlY3Rpb24YBSABKA4yGC50YWlsb3IudjEuUGFnZURpcmVjdGlvbiJ5ChpMaXN0QXV0aElEUENvbmZpZ3NSZXNwb25zZRItCgtpZHBfY29uZmlncxgBIAMoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnEhcKD25leHRfcGFnZV90b2tlbhgCIAEoCRITCgt0b3RhbF9jb3VudBgDIAEoAyLOAQoeQ3JlYXRlVXNlclByb2ZpbGVDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSSgocdXNlcl9wcm9maWxlX3Byb3ZpZGVyX2NvbmZpZxgDIAEoCzIkLnRhaWxvci52MS5Vc2VyUHJvZmlsZVByb3ZpZGVyQ29uZmlnIm0KH0NyZWF0ZVVzZXJQcm9maWxlQ29uZmlnUmVzcG9uc2USSgocdXNlcl9wcm9maWxlX3Byb3ZpZGVyX2NvbmZpZxgBIAEoCzIkLnRhaWxvci52MS5Vc2VyUHJvZmlsZVByb3ZpZGVyQ29uZmlnIs4BCh5VcGRhdGVVc2VyUHJvZmlsZUNvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBJKChx1c2VyX3Byb2ZpbGVfcHJvdmlkZXJfY29uZmlnGAMgASgLMiQudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcibQofVXBkYXRlVXNlclByb2ZpbGVDb25maWdSZXNwb25zZRJKChx1c2VyX3Byb2ZpbGVfcHJvdmlkZXJfY29uZmlnGAEgASgLMiQudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWciggEKHkRlbGV0ZVVzZXJQcm9maWxlQ29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kIiEKH0RlbGV0ZVVzZXJQcm9maWxlQ29uZmlnUmVzcG9uc2UifwobR2V0VXNlclByb2ZpbGVDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiagocR2V0VXNlclByb2ZpbGVDb25maWdSZXNwb25zZRJKChx1c2VyX3Byb2ZpbGVfcHJvdmlkZXJfY29uZmlnGAEgASgLMiQudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcixgEKGUNyZWF0ZVRlbmFudENvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBJHChZ0ZW5hbnRfcHJvdmlkZXJfY29uZmlnGAMgASgLMh8udGFpbG9yLnYxLlRlbmFudFByb3ZpZGVyQ29uZmlnQga6SAPIAQEiXQoaQ3JlYXRlVGVuYW50Q29uZmlnUmVzcG9uc2USPwoWdGVuYW50X3Byb3ZpZGVyX2NvbmZpZxgBIAEoCzIfLnRhaWxvci52MS5UZW5hbnRQcm92aWRlckNvbmZpZyLGAQoZVXBkYXRlVGVuYW50Q29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEkcKFnRlbmFudF9wcm92aWRlcl9jb25maWcYAyABKAsyHy50YWlsb3IudjEuVGVuYW50UHJvdmlkZXJDb25maWdCBrpIA8gBASJdChpVcGRhdGVUZW5hbnRDb25maWdSZXNwb25zZRI/ChZ0ZW5hbnRfcHJvdmlkZXJfY29uZmlnGAEgASgLMh8udGFpbG9yLnYxLlRlbmFudFByb3ZpZGVyQ29uZmlnIn0KGURlbGV0ZVRlbmFudENvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIcChpEZWxldGVUZW5hbnRDb25maWdSZXNwb25zZSJ6ChZHZXRUZW5hbnRDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiWgoXR2V0VGVuYW50Q29uZmlnUmVzcG9uc2USPwoWdGVuYW50X3Byb3ZpZGVyX2NvbmZpZxgBIAEoCzIfLnRhaWxvci52MS5UZW5hbnRQcm92aWRlckNvbmZpZyKSAQogQ3JlYXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlcXVlc3QSNgoEbmFtZRgBIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBI2CgZzY29wZXMYAiADKA4yEy50YWlsb3IudjEuUEFUU2NvcGVCEbpIDpIBCwgBIgeCAQQQASAAIjkKIUNyZWF0ZVBlcnNvbmFsQWNjZXNzVG9rZW5SZXNwb25zZRIUCgxhY2Nlc3NfdG9rZW4YASABKAkiWgogRGVsZXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlcXVlc3QSNgoEbmFtZRgBIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIjCiFEZWxldGVQZXJzb25hbEFjY2Vzc1Rva2VuUmVzcG9uc2UiegofTGlzdFBlcnNvbmFsQWNjZXNzVG9rZW5zUmVxdWVzdBISCgpwYWdlX3Rva2VuGAEgASgJEhEKCXBhZ2Vfc2l6ZRgCIAEoDRIwCg5wYWdlX2RpcmVjdGlvbhgDIAEoDjIYLnRhaWxvci52MS5QYWdlRGlyZWN0aW9uIpABCiBMaXN0UGVyc29uYWxBY2Nlc3NUb2tlbnNSZXNwb25zZRI+ChZwZXJzb25hbF9hY2Nlc3NfdG9rZW5zGAEgAygLMh4udGFpbG9yLnYxLlBlcnNvbmFsQWNjZXNzVG9rZW4SFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhMKC3RvdGFsX2NvdW50GAMgASgDIqMDChxDcmVhdGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQwoOYXV0aF9uYW1lc3BhY2UYAiABKAlCK7pIKHImMiReKFthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0pPyQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIhCgphdHRyaWJ1dGVzGAQgAygJQg26SAqSAQciBXIDsAEBEnYKDWF0dHJpYnV0ZV9tYXAYBSADKAsyOS50YWlsb3IudjEuQ3JlYXRlQXV0aE1hY2hpbmVVc2VyUmVxdWVzdC5BdHRyaWJ1dGVNYXBFbnRyeUIkukghmgEeIhxyGjIYXlthLXpdWzAtOWEtekEtWl17MCw2Mn0kGksKEUF0dHJpYnV0ZU1hcEVudHJ5EgsKA2tleRgBIAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToCOAEiTQodQ3JlYXRlQXV0aE1hY2hpbmVVc2VyUmVzcG9uc2USLAoMbWFjaGluZV91c2VyGAEgASgLMhYudGFpbG9yLnYxLk1hY2hpbmVVc2VyIqADChxVcGRhdGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoOYXV0aF9uYW1lc3BhY2UYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIhCgphdHRyaWJ1dGVzGAQgAygJQg26SAqSAQciBXIDsAEBEnYKDWF0dHJpYnV0ZV9tYXAYBSADKAsyOS50YWlsb3IudjEuVXBkYXRlQXV0aE1hY2hpbmVVc2VyUmVxdWVzdC5BdHRyaWJ1dGVNYXBFbnRyeUIkukghmgEeIhxyGjIYXlthLXpdWzAtOWEtekEtWl17MCw2Mn0kGksKEUF0dHJpYnV0ZU1hcEVudHJ5EgsKA2tleRgBIAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToCOAEiTQodVXBkYXRlQXV0aE1hY2hpbmVVc2VyUmVzcG9uc2USLAoMbWFjaGluZV91c2VyGAEgASgLMhYudGFpbG9yLnYxLk1hY2hpbmVVc2VyIrgBChxEZWxldGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoOYXV0aF9uYW1lc3BhY2UYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIfCh1EZWxldGVBdXRoTWFjaGluZVVzZXJSZXNwb25zZSK1AQoZR2V0QXV0aE1hY2hpbmVVc2VyUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDmF1dGhfbmFtZXNwYWNlGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjYKBG5hbWUYAyABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiSgoaR2V0QXV0aE1hY2hpbmVVc2VyUmVzcG9uc2USLAoMbWFjaGluZV91c2VyGAEgASgLMhYudGFpbG9yLnYxLk1hY2hpbmVVc2VyItgBChtMaXN0QXV0aE1hY2hpbmVVc2Vyc1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5hdXRoX25hbWVzcGFjZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBISCgpwYWdlX3Rva2VuGAMgASgJEhEKCXBhZ2Vfc2l6ZRgEIAEoDRIwCg5wYWdlX2RpcmVjdGlvbhgFIAEoDjIYLnRhaWxvci52MS5QYWdlRGlyZWN0aW9uInsKHExpc3RBdXRoTWFjaGluZVVzZXJzUmVzcG9uc2USLQoNbWFjaGluZV91c2VycxgBIAMoCzIWLnRhaWxvci52MS5NYWNoaW5lVXNlchIXCg9uZXh0X3BhZ2VfdG9rZW4YAiABKAkSEwoLdG90YWxfY291bnQYAyABKAMirwEKG0NyZWF0ZUF1dGhTQ0lNQ29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEi4KC3NjaW1fY29uZmlnGAMgASgLMhkudGFpbG9yLnYxLkF1dGhTQ0lNQ29uZmlnIk4KHENyZWF0ZUF1dGhTQ0lNQ29uZmlnUmVzcG9uc2USLgoLc2NpbV9jb25maWcYASABKAsyGS50YWlsb3IudjEuQXV0aFNDSU1Db25maWcirwEKG1VwZGF0ZUF1dGhTQ0lNQ29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEi4KC3NjaW1fY29uZmlnGAMgASgLMhkudGFpbG9yLnYxLkF1dGhTQ0lNQ29uZmlnIk4KHFVwZGF0ZUF1dGhTQ0lNQ29uZmlnUmVzcG9uc2USLgoLc2NpbV9jb25maWcYASABKAsyGS50YWlsb3IudjEuQXV0aFNDSU1Db25maWcifAoYR2V0QXV0aFNDSU1Db25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiSwoZR2V0QXV0aFNDSU1Db25maWdSZXNwb25zZRIuCgtzY2ltX2NvbmZpZxgBIAEoCzIZLnRhaWxvci52MS5BdXRoU0NJTUNvbmZpZyJ/ChtEZWxldGVBdXRoU0NJTUNvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIeChxEZWxldGVBdXRoU0NJTUNvbmZpZ1Jlc3BvbnNlIrUBCh1DcmVhdGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjIKDXNjaW1fcmVzb3VyY2UYAyABKAsyGy50YWlsb3IudjEuQXV0aFNDSU1SZXNvdXJjZSJUCh5DcmVhdGVBdXRoU0NJTVJlc291cmNlUmVzcG9uc2USMgoNc2NpbV9yZXNvdXJjZRgBIAEoCzIbLnRhaWxvci52MS5BdXRoU0NJTVJlc291cmNlIrUBCh1VcGRhdGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjIKDXNjaW1fcmVzb3VyY2UYAyABKAsyGy50YWlsb3IudjEuQXV0aFNDSU1SZXNvdXJjZSJUCh5VcGRhdGVBdXRoU0NJTVJlc291cmNlUmVzcG9uc2USMgoNc2NpbV9yZXNvdXJjZRgBIAEoCzIbLnRhaWxvci52MS5BdXRoU0NJTVJlc291cmNlIo8BCh1EZWxldGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEgwKBG5hbWUYAyABKAkiIAoeRGVsZXRlQXV0aFNDSU1SZXNvdXJjZVJlc3BvbnNlIrYBChpHZXRBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjYKBG5hbWUYAyABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiUQobR2V0QXV0aFNDSU1SZXNvdXJjZVJlc3BvbnNlEjIKDXNjaW1fcmVzb3VyY2UYASABKAsyGy50YWlsb3IudjEuQXV0aFNDSU1SZXNvdXJjZSJ/ChtHZXRBdXRoU0NJTVJlc291cmNlc1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCJTChxHZXRBdXRoU0NJTVJlc291cmNlc1Jlc3BvbnNlEjMKDnNjaW1fcmVzb3VyY2VzGAEgAygLMhsudGFpbG9yLnYxLkF1dGhTQ0lNUmVzb3VyY2UidAobQ3JlYXRlQXV0aENvbm5lY3Rpb25SZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESNQoKY29ubmVjdGlvbhgCIAEoCzIZLnRhaWxvci52MS5BdXRoQ29ubmVjdGlvbkIGukgDyAEBIh4KHENyZWF0ZUF1dGhDb25uZWN0aW9uUmVzcG9uc2UilQEKGkxpc3RBdXRoQ29ubmVjdGlvbnNSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESEgoKcGFnZV90b2tlbhgCIAEoCRIRCglwYWdlX3NpemUYAyABKA0SMAoOcGFnZV9kaXJlY3Rpb24YBCABKA4yGC50YWlsb3IudjEuUGFnZURpcmVjdGlvbiJ7ChtMaXN0QXV0aENvbm5lY3Rpb25zUmVzcG9uc2USLgoLY29ubmVjdGlvbnMYASADKAsyGS50YWlsb3IudjEuQXV0aENvbm5lY3Rpb24SFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhMKC3RvdGFsX2NvdW50GAMgASgDIoABChtSZXZva2VBdXRoQ29ubmVjdGlvblJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJBCg9jb25uZWN0aW9uX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiHgocUmV2b2tlQXV0aENvbm5lY3Rpb25SZXNwb25zZSLmAQokUmVnaXN0ZXJBdXRoQ29ubmVjdGlvblNlc3Npb25SZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQQoPY29ubmVjdGlvbl9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEhQKDGFjY2Vzc190b2tlbhgDIAEoCRIVCg1yZWZyZXNoX3Rva2VuGAQgASgJEi4KCmV4cGlyZXNfYXQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wIicKJVJlZ2lzdGVyQXV0aENvbm5lY3Rpb25TZXNzaW9uUmVzcG9uc2Ui1wEKLkV4Y2hhbmdlQXV0aENvbm5lY3Rpb25BdXRob3JpemF0aW9uQ29kZVJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJBCg9jb25uZWN0aW9uX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSIwoSYXV0aG9yaXphdGlvbl9jb2RlGAMgASgJQge6SARyAhABEh0KDHJlZGlyZWN0X3VyaRgEIAEoCUIHukgEcgIQASIxCi9FeGNoYW5nZUF1dGhDb25uZWN0aW9uQXV0aG9yaXphdGlvbkNvZGVSZXNwb25zZSKLAQodQ3JlYXRlQXV0aE9BdXRoMkNsaWVudFJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARIWCg5uYW1lc3BhY2VfbmFtZRgCIAEoCRIyCg1vYXV0aDJfY2xpZW50GAMgASgLMhsudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQiVAoeQ3JlYXRlQXV0aE9BdXRoMkNsaWVudFJlc3BvbnNlEjIKDW9hdXRoMl9jbGllbnQYASABKAsyGy50YWlsb3IudjEuQXV0aE9BdXRoMkNsaWVudCKLAQodVXBkYXRlQXV0aE9BdXRoMkNsaWVudFJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARIWCg5uYW1lc3BhY2VfbmFtZRgCIAEoCRIyCg1vYXV0aDJfY2xpZW50GAMgASgLMhsudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQiVAoeVXBkYXRlQXV0aE9BdXRoMkNsaWVudFJlc3BvbnNlEjIKDW9hdXRoMl9jbGllbnQYASABKAsyGy50YWlsb3IudjEuQXV0aE9BdXRoMkNsaWVudCJlCh1EZWxldGVBdXRoT0F1dGgyQ2xpZW50UmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEhYKDm5hbWVzcGFjZV9uYW1lGAIgASgJEgwKBG5hbWUYAyABKAkiIAoeRGVsZXRlQXV0aE9BdXRoMkNsaWVudFJlc3BvbnNlIrYBChpHZXRBdXRoT0F1dGgyQ2xpZW50UmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjYKBG5hbWUYAyABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiUQobR2V0QXV0aE9BdXRoMkNsaWVudFJlc3BvbnNlEjIKDW9hdXRoMl9jbGllbnQYASABKAsyGy50YWlsb3IudjEuQXV0aE9BdXRoMkNsaWVudCKvAQocTGlzdEF1dGhPQXV0aDJDbGllbnRzUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEhYKDm5hbWVzcGFjZV9uYW1lGAIgASgJEhIKCnBhZ2VfdG9rZW4YAyABKAkSEQoJcGFnZV9zaXplGAQgASgNEjAKDnBhZ2VfZGlyZWN0aW9uGAUgASgOMhgudGFpbG9yLnYxLlBhZ2VEaXJlY3Rpb24iggEKHUxpc3RBdXRoT0F1dGgyQ2xpZW50c1Jlc3BvbnNlEjMKDm9hdXRoMl9jbGllbnRzGAEgAygLMhsudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQSFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhMKC3RvdGFsX2NvdW50GAMgASgDIrYBCiRDcmVhdGVDb250cm9scGxhbmVNYWNoaW5lVXNlclJlcXVlc3QSIQoPb3JnYW5pemF0aW9uX2lkGAEgASgJQgi6SAVyA7ABARIeCglmb2xkZXJfaWQYAiABKAlCC7pICNgBAXIDsAEBEjYKBG5hbWUYAyABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSEwoLZGVzY3JpcHRpb24YBCABKAkiYQolQ3JlYXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXNwb25zZRI4CgxtYWNoaW5lX3VzZXIYASABKAsyIi50YWlsb3IudjEuQ29udHJvbHBsYW5lTWFjaGluZVVzZXIi/AEKJFVwZGF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVxdWVzdBIhCg9vcmdhbml6YXRpb25faWQYASABKAlCCLpIBXIDsAEBEh4KCWZvbGRlcl9pZBgCIAEoCUILukgI2AEBcgOwAQESIQoPbWFjaGluZV91c2VyX2lkGAMgASgJQgi6SAVyA7ABARI7CgRuYW1lGAQgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kSACIAQESGAoLZGVzY3JpcHRpb24YBSABKAlIAYgBAUIHCgVfbmFtZUIOCgxfZGVzY3JpcHRpb24iYQolVXBkYXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXNwb25zZRI4CgxtYWNoaW5lX3VzZXIYASABKAsyIi50YWlsb3IudjEuQ29udHJvbHBsYW5lTWFjaGluZVVzZXIiiQEKIUdldENvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVxdWVzdBIhCg9vcmdhbml6YXRpb25faWQYASABKAlCCLpIBXIDsAEBEh4KCWZvbGRlcl9pZBgCIAEoCUILukgI2AEBcgOwAQESIQoPbWFjaGluZV91c2VyX2lkGAMgASgJQgi6SAVyA7ABASJeCiJHZXRDb250cm9scGxhbmVNYWNoaW5lVXNlclJlc3BvbnNlEjgKDG1hY2hpbmVfdXNlchgBIAEoCzIiLnRhaWxvci52MS5Db250cm9scGxhbmVNYWNoaW5lVXNlciKkAQonR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJCeU5hbWVSZXF1ZXN0EiEKD29yZ2FuaXphdGlvbl9pZBgBIAEoCUIIukgFcgOwAQESHgoJZm9sZGVyX2lkGAIgASgJQgu6SAjYAQFyA7ABARI2CgRuYW1lGAMgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kImQKKEdldENvbnRyb2xwbGFuZU1hY2hpbmVVc2VyQnlOYW1lUmVzcG9uc2USOAoMbWFjaGluZV91c2VyGAEgASgLMiIudGFpbG9yLnYxLkNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyIsEBCiNMaXN0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJzUmVxdWVzdBIhCg9vcmdhbml6YXRpb25faWQYASABKAlCCLpIBXIDsAEBEh4KCWZvbGRlcl9pZBgCIAEoCUILukgI2AEBcgOwAQESEgoKcGFnZV90b2tlbhgDIAEoCRIRCglwYWdlX3NpemUYBCABKA0SMAoOcGFnZV9kaXJlY3Rpb24YBSABKA4yGC50YWlsb3IudjEuUGFnZURpcmVjdGlvbiKPAQokTGlzdENvbnRyb2xwbGFuZU1hY2hpbmVVc2Vyc1Jlc3BvbnNlEjkKDW1hY2hpbmVfdXNlcnMYASADKAsyIi50YWlsb3IudjEuQ29udHJvbHBsYW5lTWFjaGluZVVzZXISFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhMKC3RvdGFsX2NvdW50GAMgASgDIowBCiREZWxldGVDb250cm9scGxhbmVNYWNoaW5lVXNlclJlcXVlc3QSIQoPb3JnYW5pemF0aW9uX2lkGAEgASgJQgi6SAVyA7ABARIeCglmb2xkZXJfaWQYAiABKAlCC7pICNgBAXIDsAEBEiEKD21hY2hpbmVfdXNlcl9pZBgDIAEoCUIIukgFcgOwAQEiJwolRGVsZXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXNwb25zZWIGcHJvdG8z", [
438
+ const file_tailor_v1_auth = /* @__PURE__ */ fileDesc("ChR0YWlsb3IvdjEvYXV0aC5wcm90bxIJdGFpbG9yLnYxIpwBChhDcmVhdGVBdXRoU2VydmljZVJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIeChZwdWJsaXNoX3Nlc3Npb25fZXZlbnRzGAMgASgIIkkKGUNyZWF0ZUF1dGhTZXJ2aWNlUmVzcG9uc2USLAoMYXV0aF9zZXJ2aWNlGAEgASgLMhYudGFpbG9yLnYxLkF1dGhTZXJ2aWNlIpwBChhVcGRhdGVBdXRoU2VydmljZVJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIeChZwdWJsaXNoX3Nlc3Npb25fZXZlbnRzGAMgASgIIkkKGVVwZGF0ZUF1dGhTZXJ2aWNlUmVzcG9uc2USLAoMYXV0aF9zZXJ2aWNlGAEgASgLMhYudGFpbG9yLnYxLkF1dGhTZXJ2aWNlInwKGERlbGV0ZUF1dGhTZXJ2aWNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kIhsKGURlbGV0ZUF1dGhTZXJ2aWNlUmVzcG9uc2UieQoVR2V0QXV0aFNlcnZpY2VSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiRgoWR2V0QXV0aFNlcnZpY2VSZXNwb25zZRIsCgxhdXRoX3NlcnZpY2UYASABKAsyFi50YWlsb3IudjEuQXV0aFNlcnZpY2UikgEKF0xpc3RBdXRoU2VydmljZXNSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESEgoKcGFnZV90b2tlbhgCIAEoCRIRCglwYWdlX3NpemUYAyABKA0SMAoOcGFnZV9kaXJlY3Rpb24YBCABKA4yGC50YWlsb3IudjEuUGFnZURpcmVjdGlvbiJ3ChhMaXN0QXV0aFNlcnZpY2VzUmVzcG9uc2USLQoNYXV0aF9zZXJ2aWNlcxgBIAMoCzIWLnRhaWxvci52MS5BdXRoU2VydmljZRIXCg9uZXh0X3BhZ2VfdG9rZW4YAiABKAkSEwoLdG90YWxfY291bnQYAyABKAMirAEKGkNyZWF0ZUF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSLAoKaWRwX2NvbmZpZxgDIAEoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnIksKG0NyZWF0ZUF1dGhJRFBDb25maWdSZXNwb25zZRIsCgppZHBfY29uZmlnGAEgASgLMhgudGFpbG9yLnYxLkF1dGhJRFBDb25maWcirAEKGlVwZGF0ZUF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSLAoKaWRwX2NvbmZpZxgDIAEoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnIksKG1VwZGF0ZUF1dGhJRFBDb25maWdSZXNwb25zZRIsCgppZHBfY29uZmlnGAEgASgLMhgudGFpbG9yLnYxLkF1dGhJRFBDb25maWcitgEKGkRlbGV0ZUF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIdChtEZWxldGVBdXRoSURQQ29uZmlnUmVzcG9uc2UiswEKF0dldEF1dGhJRFBDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCJIChhHZXRBdXRoSURQQ29uZmlnUmVzcG9uc2USLAoKaWRwX2NvbmZpZxgBIAEoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnItYBChlMaXN0QXV0aElEUENvbmZpZ3NSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSEgoKcGFnZV90b2tlbhgDIAEoCRIRCglwYWdlX3NpemUYBCABKA0SMAoOcGFnZV9kaXJlY3Rpb24YBSABKA4yGC50YWlsb3IudjEuUGFnZURpcmVjdGlvbiJ5ChpMaXN0QXV0aElEUENvbmZpZ3NSZXNwb25zZRItCgtpZHBfY29uZmlncxgBIAMoCzIYLnRhaWxvci52MS5BdXRoSURQQ29uZmlnEhcKD25leHRfcGFnZV90b2tlbhgCIAEoCRITCgt0b3RhbF9jb3VudBgDIAEoAyLOAQoeQ3JlYXRlVXNlclByb2ZpbGVDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSSgocdXNlcl9wcm9maWxlX3Byb3ZpZGVyX2NvbmZpZxgDIAEoCzIkLnRhaWxvci52MS5Vc2VyUHJvZmlsZVByb3ZpZGVyQ29uZmlnIm0KH0NyZWF0ZVVzZXJQcm9maWxlQ29uZmlnUmVzcG9uc2USSgocdXNlcl9wcm9maWxlX3Byb3ZpZGVyX2NvbmZpZxgBIAEoCzIkLnRhaWxvci52MS5Vc2VyUHJvZmlsZVByb3ZpZGVyQ29uZmlnIs4BCh5VcGRhdGVVc2VyUHJvZmlsZUNvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBJKChx1c2VyX3Byb2ZpbGVfcHJvdmlkZXJfY29uZmlnGAMgASgLMiQudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcibQofVXBkYXRlVXNlclByb2ZpbGVDb25maWdSZXNwb25zZRJKChx1c2VyX3Byb2ZpbGVfcHJvdmlkZXJfY29uZmlnGAEgASgLMiQudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWciggEKHkRlbGV0ZVVzZXJQcm9maWxlQ29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kIiEKH0RlbGV0ZVVzZXJQcm9maWxlQ29uZmlnUmVzcG9uc2UifwobR2V0VXNlclByb2ZpbGVDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiagocR2V0VXNlclByb2ZpbGVDb25maWdSZXNwb25zZRJKChx1c2VyX3Byb2ZpbGVfcHJvdmlkZXJfY29uZmlnGAEgASgLMiQudGFpbG9yLnYxLlVzZXJQcm9maWxlUHJvdmlkZXJDb25maWcixgEKGUNyZWF0ZVRlbmFudENvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBJHChZ0ZW5hbnRfcHJvdmlkZXJfY29uZmlnGAMgASgLMh8udGFpbG9yLnYxLlRlbmFudFByb3ZpZGVyQ29uZmlnQga6SAPIAQEiXQoaQ3JlYXRlVGVuYW50Q29uZmlnUmVzcG9uc2USPwoWdGVuYW50X3Byb3ZpZGVyX2NvbmZpZxgBIAEoCzIfLnRhaWxvci52MS5UZW5hbnRQcm92aWRlckNvbmZpZyLGAQoZVXBkYXRlVGVuYW50Q29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEkcKFnRlbmFudF9wcm92aWRlcl9jb25maWcYAyABKAsyHy50YWlsb3IudjEuVGVuYW50UHJvdmlkZXJDb25maWdCBrpIA8gBASJdChpVcGRhdGVUZW5hbnRDb25maWdSZXNwb25zZRI/ChZ0ZW5hbnRfcHJvdmlkZXJfY29uZmlnGAEgASgLMh8udGFpbG9yLnYxLlRlbmFudFByb3ZpZGVyQ29uZmlnIn0KGURlbGV0ZVRlbmFudENvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIcChpEZWxldGVUZW5hbnRDb25maWdSZXNwb25zZSJ6ChZHZXRUZW5hbnRDb25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiWgoXR2V0VGVuYW50Q29uZmlnUmVzcG9uc2USPwoWdGVuYW50X3Byb3ZpZGVyX2NvbmZpZxgBIAEoCzIfLnRhaWxvci52MS5UZW5hbnRQcm92aWRlckNvbmZpZyKSAQogQ3JlYXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlcXVlc3QSNgoEbmFtZRgBIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBI2CgZzY29wZXMYAiADKA4yEy50YWlsb3IudjEuUEFUU2NvcGVCEbpIDpIBCwgBIgeCAQQQASAAIjkKIUNyZWF0ZVBlcnNvbmFsQWNjZXNzVG9rZW5SZXNwb25zZRIUCgxhY2Nlc3NfdG9rZW4YASABKAkiWgogRGVsZXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlcXVlc3QSNgoEbmFtZRgBIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIjCiFEZWxldGVQZXJzb25hbEFjY2Vzc1Rva2VuUmVzcG9uc2UiegofTGlzdFBlcnNvbmFsQWNjZXNzVG9rZW5zUmVxdWVzdBISCgpwYWdlX3Rva2VuGAEgASgJEhEKCXBhZ2Vfc2l6ZRgCIAEoDRIwCg5wYWdlX2RpcmVjdGlvbhgDIAEoDjIYLnRhaWxvci52MS5QYWdlRGlyZWN0aW9uIpABCiBMaXN0UGVyc29uYWxBY2Nlc3NUb2tlbnNSZXNwb25zZRI+ChZwZXJzb25hbF9hY2Nlc3NfdG9rZW5zGAEgAygLMh4udGFpbG9yLnYxLlBlcnNvbmFsQWNjZXNzVG9rZW4SFwoPbmV4dF9wYWdlX3Rva2VuGAIgASgJEhMKC3RvdGFsX2NvdW50GAMgASgDIqMDChxDcmVhdGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQwoOYXV0aF9uYW1lc3BhY2UYAiABKAlCK7pIKHImMiReKFthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0pPyQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIhCgphdHRyaWJ1dGVzGAQgAygJQg26SAqSAQciBXIDsAEBEnYKDWF0dHJpYnV0ZV9tYXAYBSADKAsyOS50YWlsb3IudjEuQ3JlYXRlQXV0aE1hY2hpbmVVc2VyUmVxdWVzdC5BdHRyaWJ1dGVNYXBFbnRyeUIkukghmgEeIhxyGjIYXlthLXpdWzAtOWEtekEtWl17MCw2Mn0kGksKEUF0dHJpYnV0ZU1hcEVudHJ5EgsKA2tleRgBIAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToCOAEiTQodQ3JlYXRlQXV0aE1hY2hpbmVVc2VyUmVzcG9uc2USLAoMbWFjaGluZV91c2VyGAEgASgLMhYudGFpbG9yLnYxLk1hY2hpbmVVc2VyIqADChxVcGRhdGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoOYXV0aF9uYW1lc3BhY2UYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIhCgphdHRyaWJ1dGVzGAQgAygJQg26SAqSAQciBXIDsAEBEnYKDWF0dHJpYnV0ZV9tYXAYBSADKAsyOS50YWlsb3IudjEuVXBkYXRlQXV0aE1hY2hpbmVVc2VyUmVxdWVzdC5BdHRyaWJ1dGVNYXBFbnRyeUIkukghmgEeIhxyGjIYXlthLXpdWzAtOWEtekEtWl17MCw2Mn0kGksKEUF0dHJpYnV0ZU1hcEVudHJ5EgsKA2tleRgBIAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToCOAEiTQodVXBkYXRlQXV0aE1hY2hpbmVVc2VyUmVzcG9uc2USLAoMbWFjaGluZV91c2VyGAEgASgLMhYudGFpbG9yLnYxLk1hY2hpbmVVc2VyIrgBChxEZWxldGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoOYXV0aF9uYW1lc3BhY2UYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIfCh1EZWxldGVBdXRoTWFjaGluZVVzZXJSZXNwb25zZSK1AQoZR2V0QXV0aE1hY2hpbmVVc2VyUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDmF1dGhfbmFtZXNwYWNlGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjYKBG5hbWUYAyABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiSgoaR2V0QXV0aE1hY2hpbmVVc2VyUmVzcG9uc2USLAoMbWFjaGluZV91c2VyGAEgASgLMhYudGFpbG9yLnYxLk1hY2hpbmVVc2VyItgBChtMaXN0QXV0aE1hY2hpbmVVc2Vyc1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5hdXRoX25hbWVzcGFjZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBISCgpwYWdlX3Rva2VuGAMgASgJEhEKCXBhZ2Vfc2l6ZRgEIAEoDRIwCg5wYWdlX2RpcmVjdGlvbhgFIAEoDjIYLnRhaWxvci52MS5QYWdlRGlyZWN0aW9uInsKHExpc3RBdXRoTWFjaGluZVVzZXJzUmVzcG9uc2USLQoNbWFjaGluZV91c2VycxgBIAMoCzIWLnRhaWxvci52MS5NYWNoaW5lVXNlchIXCg9uZXh0X3BhZ2VfdG9rZW4YAiABKAkSEwoLdG90YWxfY291bnQYAyABKAMirwEKG0NyZWF0ZUF1dGhTQ0lNQ29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEi4KC3NjaW1fY29uZmlnGAMgASgLMhkudGFpbG9yLnYxLkF1dGhTQ0lNQ29uZmlnIk4KHENyZWF0ZUF1dGhTQ0lNQ29uZmlnUmVzcG9uc2USLgoLc2NpbV9jb25maWcYASABKAsyGS50YWlsb3IudjEuQXV0aFNDSU1Db25maWcirwEKG1VwZGF0ZUF1dGhTQ0lNQ29uZmlnUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEi4KC3NjaW1fY29uZmlnGAMgASgLMhkudGFpbG9yLnYxLkF1dGhTQ0lNQ29uZmlnIk4KHFVwZGF0ZUF1dGhTQ0lNQ29uZmlnUmVzcG9uc2USLgoLc2NpbV9jb25maWcYASABKAsyGS50YWlsb3IudjEuQXV0aFNDSU1Db25maWcifAoYR2V0QXV0aFNDSU1Db25maWdSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiSwoZR2V0QXV0aFNDSU1Db25maWdSZXNwb25zZRIuCgtzY2ltX2NvbmZpZxgBIAEoCzIZLnRhaWxvci52MS5BdXRoU0NJTUNvbmZpZyJ/ChtEZWxldGVBdXRoU0NJTUNvbmZpZ1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCIeChxEZWxldGVBdXRoU0NJTUNvbmZpZ1Jlc3BvbnNlIrUBCh1DcmVhdGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjIKDXNjaW1fcmVzb3VyY2UYAyABKAsyGy50YWlsb3IudjEuQXV0aFNDSU1SZXNvdXJjZSJUCh5DcmVhdGVBdXRoU0NJTVJlc291cmNlUmVzcG9uc2USMgoNc2NpbV9yZXNvdXJjZRgBIAEoCzIbLnRhaWxvci52MS5BdXRoU0NJTVJlc291cmNlIrUBCh1VcGRhdGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjIKDXNjaW1fcmVzb3VyY2UYAyABKAsyGy50YWlsb3IudjEuQXV0aFNDSU1SZXNvdXJjZSJUCh5VcGRhdGVBdXRoU0NJTVJlc291cmNlUmVzcG9uc2USMgoNc2NpbV9yZXNvdXJjZRgBIAEoCzIbLnRhaWxvci52MS5BdXRoU0NJTVJlc291cmNlIo8BCh1EZWxldGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEgwKBG5hbWUYAyABKAkiIAoeRGVsZXRlQXV0aFNDSU1SZXNvdXJjZVJlc3BvbnNlIrYBChpHZXRBdXRoU0NJTVJlc291cmNlUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjYKBG5hbWUYAyABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQiUQobR2V0QXV0aFNDSU1SZXNvdXJjZVJlc3BvbnNlEjIKDXNjaW1fcmVzb3VyY2UYASABKAsyGy50YWlsb3IudjEuQXV0aFNDSU1SZXNvdXJjZSJ/ChtHZXRBdXRoU0NJTVJlc291cmNlc1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCJTChxHZXRBdXRoU0NJTVJlc291cmNlc1Jlc3BvbnNlEjMKDnNjaW1fcmVzb3VyY2VzGAEgAygLMhsudGFpbG9yLnYxLkF1dGhTQ0lNUmVzb3VyY2UipAEKFUNyZWF0ZUF1dGhIb29rUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEikKBGhvb2sYAyABKAsyEy50YWlsb3IudjEuQXV0aEhvb2tCBrpIA8gBASI7ChZDcmVhdGVBdXRoSG9va1Jlc3BvbnNlEiEKBGhvb2sYASABKAsyEy50YWlsb3IudjEuQXV0aEhvb2sipAEKFVVwZGF0ZUF1dGhIb29rUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEikKBGhvb2sYAyABKAsyEy50YWlsb3IudjEuQXV0aEhvb2tCBrpIA8gBASI7ChZVcGRhdGVBdXRoSG9va1Jlc3BvbnNlEiEKBGhvb2sYASABKAsyEy50YWlsb3IudjEuQXV0aEhvb2siswEKFURlbGV0ZUF1dGhIb29rUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkAKDm5hbWVzcGFjZV9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEjgKCmhvb2tfcG9pbnQYAyABKA4yGC50YWlsb3IudjEuQXV0aEhvb2tQb2ludEIKukgHggEEEAEgACIYChZEZWxldGVBdXRoSG9va1Jlc3BvbnNlIrABChJHZXRBdXRoSG9va1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBI4Cgpob29rX3BvaW50GAMgASgOMhgudGFpbG9yLnYxLkF1dGhIb29rUG9pbnRCCrpIB4IBBBABIAAiOAoTR2V0QXV0aEhvb2tSZXNwb25zZRIhCgRob29rGAEgASgLMhMudGFpbG9yLnYxLkF1dGhIb29rInQKG0NyZWF0ZUF1dGhDb25uZWN0aW9uUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEjUKCmNvbm5lY3Rpb24YAiABKAsyGS50YWlsb3IudjEuQXV0aENvbm5lY3Rpb25CBrpIA8gBASIeChxDcmVhdGVBdXRoQ29ubmVjdGlvblJlc3BvbnNlIpUBChpMaXN0QXV0aENvbm5lY3Rpb25zUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEhIKCnBhZ2VfdG9rZW4YAiABKAkSEQoJcGFnZV9zaXplGAMgASgNEjAKDnBhZ2VfZGlyZWN0aW9uGAQgASgOMhgudGFpbG9yLnYxLlBhZ2VEaXJlY3Rpb24iewobTGlzdEF1dGhDb25uZWN0aW9uc1Jlc3BvbnNlEi4KC2Nvbm5lY3Rpb25zGAEgAygLMhkudGFpbG9yLnYxLkF1dGhDb25uZWN0aW9uEhcKD25leHRfcGFnZV90b2tlbhgCIAEoCRITCgt0b3RhbF9jb3VudBgDIAEoAyKAAQobUmV2b2tlQXV0aENvbm5lY3Rpb25SZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQQoPY29ubmVjdGlvbl9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kIh4KHFJldm9rZUF1dGhDb25uZWN0aW9uUmVzcG9uc2Ui5gEKJFJlZ2lzdGVyQXV0aENvbm5lY3Rpb25TZXNzaW9uUmVxdWVzdBIeCgx3b3Jrc3BhY2VfaWQYASABKAlCCLpIBXIDsAEBEkEKD2Nvbm5lY3Rpb25fbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIUCgxhY2Nlc3NfdG9rZW4YAyABKAkSFQoNcmVmcmVzaF90b2tlbhgEIAEoCRIuCgpleHBpcmVzX2F0GAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcCInCiVSZWdpc3RlckF1dGhDb25uZWN0aW9uU2Vzc2lvblJlc3BvbnNlItcBCi5FeGNoYW5nZUF1dGhDb25uZWN0aW9uQXV0aG9yaXphdGlvbkNvZGVSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESQQoPY29ubmVjdGlvbl9uYW1lGAIgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEiMKEmF1dGhvcml6YXRpb25fY29kZRgDIAEoCUIHukgEcgIQARIdCgxyZWRpcmVjdF91cmkYBCABKAlCB7pIBHICEAEiMQovRXhjaGFuZ2VBdXRoQ29ubmVjdGlvbkF1dGhvcml6YXRpb25Db2RlUmVzcG9uc2UiiwEKHUNyZWF0ZUF1dGhPQXV0aDJDbGllbnRSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESFgoObmFtZXNwYWNlX25hbWUYAiABKAkSMgoNb2F1dGgyX2NsaWVudBgDIAEoCzIbLnRhaWxvci52MS5BdXRoT0F1dGgyQ2xpZW50IlQKHkNyZWF0ZUF1dGhPQXV0aDJDbGllbnRSZXNwb25zZRIyCg1vYXV0aDJfY2xpZW50GAEgASgLMhsudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQiiwEKHVVwZGF0ZUF1dGhPQXV0aDJDbGllbnRSZXF1ZXN0Eh4KDHdvcmtzcGFjZV9pZBgBIAEoCUIIukgFcgOwAQESFgoObmFtZXNwYWNlX25hbWUYAiABKAkSMgoNb2F1dGgyX2NsaWVudBgDIAEoCzIbLnRhaWxvci52MS5BdXRoT0F1dGgyQ2xpZW50IlQKHlVwZGF0ZUF1dGhPQXV0aDJDbGllbnRSZXNwb25zZRIyCg1vYXV0aDJfY2xpZW50GAEgASgLMhsudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQiZQodRGVsZXRlQXV0aE9BdXRoMkNsaWVudFJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARIWCg5uYW1lc3BhY2VfbmFtZRgCIAEoCRIMCgRuYW1lGAMgASgJIiAKHkRlbGV0ZUF1dGhPQXV0aDJDbGllbnRSZXNwb25zZSK2AQoaR2V0QXV0aE9BdXRoMkNsaWVudFJlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBI2CgRuYW1lGAMgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kIlEKG0dldEF1dGhPQXV0aDJDbGllbnRSZXNwb25zZRIyCg1vYXV0aDJfY2xpZW50GAEgASgLMhsudGFpbG9yLnYxLkF1dGhPQXV0aDJDbGllbnQirwEKHExpc3RBdXRoT0F1dGgyQ2xpZW50c1JlcXVlc3QSHgoMd29ya3NwYWNlX2lkGAEgASgJQgi6SAVyA7ABARIWCg5uYW1lc3BhY2VfbmFtZRgCIAEoCRISCgpwYWdlX3Rva2VuGAMgASgJEhEKCXBhZ2Vfc2l6ZRgEIAEoDRIwCg5wYWdlX2RpcmVjdGlvbhgFIAEoDjIYLnRhaWxvci52MS5QYWdlRGlyZWN0aW9uIoIBCh1MaXN0QXV0aE9BdXRoMkNsaWVudHNSZXNwb25zZRIzCg5vYXV0aDJfY2xpZW50cxgBIAMoCzIbLnRhaWxvci52MS5BdXRoT0F1dGgyQ2xpZW50EhcKD25leHRfcGFnZV90b2tlbhgCIAEoCRITCgt0b3RhbF9jb3VudBgDIAEoAyK2AQokQ3JlYXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXF1ZXN0EiEKD29yZ2FuaXphdGlvbl9pZBgBIAEoCUIIukgFcgOwAQESHgoJZm9sZGVyX2lkGAIgASgJQgu6SAjYAQFyA7ABARI2CgRuYW1lGAMgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEhMKC2Rlc2NyaXB0aW9uGAQgASgJImEKJUNyZWF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVzcG9uc2USOAoMbWFjaGluZV91c2VyGAEgASgLMiIudGFpbG9yLnYxLkNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyIvwBCiRVcGRhdGVDb250cm9scGxhbmVNYWNoaW5lVXNlclJlcXVlc3QSIQoPb3JnYW5pemF0aW9uX2lkGAEgASgJQgi6SAVyA7ABARIeCglmb2xkZXJfaWQYAiABKAlCC7pICNgBAXIDsAEBEiEKD21hY2hpbmVfdXNlcl9pZBgDIAEoCUIIukgFcgOwAQESOwoEbmFtZRgEIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJEgAiAEBEhgKC2Rlc2NyaXB0aW9uGAUgASgJSAGIAQFCBwoFX25hbWVCDgoMX2Rlc2NyaXB0aW9uImEKJVVwZGF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVzcG9uc2USOAoMbWFjaGluZV91c2VyGAEgASgLMiIudGFpbG9yLnYxLkNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyIokBCiFHZXRDb250cm9scGxhbmVNYWNoaW5lVXNlclJlcXVlc3QSIQoPb3JnYW5pemF0aW9uX2lkGAEgASgJQgi6SAVyA7ABARIeCglmb2xkZXJfaWQYAiABKAlCC7pICNgBAXIDsAEBEiEKD21hY2hpbmVfdXNlcl9pZBgDIAEoCUIIukgFcgOwAQEiXgoiR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXNwb25zZRI4CgxtYWNoaW5lX3VzZXIYASABKAsyIi50YWlsb3IudjEuQ29udHJvbHBsYW5lTWFjaGluZVVzZXIipAEKJ0dldENvbnRyb2xwbGFuZU1hY2hpbmVVc2VyQnlOYW1lUmVxdWVzdBIhCg9vcmdhbml6YXRpb25faWQYASABKAlCCLpIBXIDsAEBEh4KCWZvbGRlcl9pZBgCIAEoCUILukgI2AEBcgOwAQESNgoEbmFtZRgDIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJCJkCihHZXRDb250cm9scGxhbmVNYWNoaW5lVXNlckJ5TmFtZVJlc3BvbnNlEjgKDG1hY2hpbmVfdXNlchgBIAEoCzIiLnRhaWxvci52MS5Db250cm9scGxhbmVNYWNoaW5lVXNlciLBAQojTGlzdENvbnRyb2xwbGFuZU1hY2hpbmVVc2Vyc1JlcXVlc3QSIQoPb3JnYW5pemF0aW9uX2lkGAEgASgJQgi6SAVyA7ABARIeCglmb2xkZXJfaWQYAiABKAlCC7pICNgBAXIDsAEBEhIKCnBhZ2VfdG9rZW4YAyABKAkSEQoJcGFnZV9zaXplGAQgASgNEjAKDnBhZ2VfZGlyZWN0aW9uGAUgASgOMhgudGFpbG9yLnYxLlBhZ2VEaXJlY3Rpb24ijwEKJExpc3RDb250cm9scGxhbmVNYWNoaW5lVXNlcnNSZXNwb25zZRI5Cg1tYWNoaW5lX3VzZXJzGAEgAygLMiIudGFpbG9yLnYxLkNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyEhcKD25leHRfcGFnZV90b2tlbhgCIAEoCRITCgt0b3RhbF9jb3VudBgDIAEoAyKMAQokRGVsZXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXF1ZXN0EiEKD29yZ2FuaXphdGlvbl9pZBgBIAEoCUIIukgFcgOwAQESHgoJZm9sZGVyX2lkGAIgASgJQgu6SAjYAQFyA7ABARIhCg9tYWNoaW5lX3VzZXJfaWQYAyABKAlCCLpIBXIDsAEBIicKJURlbGV0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVzcG9uc2ViBnByb3RvMw", [
429
439
  file_buf_validate_validate,
430
440
  file_google_protobuf_struct,
431
441
  file_google_protobuf_timestamp,
@@ -456,7 +466,7 @@ const file_tailor_v1_events = /* @__PURE__ */ fileDesc("ChZ0YWlsb3IvdjEvZXZlbnRz
456
466
  /**
457
467
  * Describes the file tailor/v1/executor_resource.proto.
458
468
  */
459
- const file_tailor_v1_executor_resource = /* @__PURE__ */ fileDesc("CiF0YWlsb3IvdjEvZXhlY3V0b3JfcmVzb3VyY2UucHJvdG8SCXRhaWxvci52MSL9AgoQRXhlY3V0b3JFeGVjdXRvchI2CgRuYW1lGAEgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEhMKC2Rlc2NyaXB0aW9uGAIgASgJEkIKDHRyaWdnZXJfdHlwZRgDIAEoDjIeLnRhaWxvci52MS5FeGVjdXRvclRyaWdnZXJUeXBlQgy6SAmCAQYYARgCGAMSQAoOdHJpZ2dlcl9jb25maWcYBCABKAsyIC50YWlsb3IudjEuRXhlY3V0b3JUcmlnZ2VyQ29uZmlnQga6SAPIAQESRAoLdGFyZ2V0X3R5cGUYBSABKA4yHS50YWlsb3IudjEuRXhlY3V0b3JUYXJnZXRUeXBlQhC6SA2CAQoYARgCGAMYBBgFEj4KDXRhcmdldF9jb25maWcYBiABKAsyHy50YWlsb3IudjEuRXhlY3V0b3JUYXJnZXRDb25maWdCBrpIA8gBARIQCghkaXNhYmxlZBgHIAEoCCLrAQoVRXhlY3V0b3JUcmlnZ2VyQ29uZmlnEjwKCHNjaGVkdWxlGAEgASgLMigudGFpbG9yLnYxLkV4ZWN1dG9yVHJpZ2dlclNjaGVkdWxlQ29uZmlnSAASNgoFZXZlbnQYAiABKAsyJS50YWlsb3IudjEuRXhlY3V0b3JUcmlnZ2VyRXZlbnRDb25maWdIABJLChBpbmNvbWluZ193ZWJob29rGAMgASgLMi8udGFpbG9yLnYxLkV4ZWN1dG9yVHJpZ2dlckluY29taW5nV2ViaG9va0NvbmZpZ0gAQg8KBmNvbmZpZxIFukgCCAEiVgodRXhlY3V0b3JUcmlnZ2VyU2NoZWR1bGVDb25maWcSGQoIdGltZXpvbmUYASABKAlCB7pIBHICEAESGgoJZnJlcXVlbmN5GAIgASgJQge6SARyAhABIl8KGkV4ZWN1dG9yVHJpZ2dlckV2ZW50Q29uZmlnEhsKCmV2ZW50X3R5cGUYASABKAlCB7pIBHICEAESJAoJY29uZGl0aW9uGAIgASgLMhEudGFpbG9yLnYxLlNjcmlwdCI7CiRFeGVjdXRvclRyaWdnZXJJbmNvbWluZ1dlYmhvb2tDb25maWcSEwoGc2VjcmV0GAEgASgJQgPgQQMingIKFEV4ZWN1dG9yVGFyZ2V0Q29uZmlnEjMKB3dlYmhvb2sYASABKAsyIC50YWlsb3IudjEuRXhlY3V0b3JXZWJob29rQ29uZmlnSAASRgoOdGFpbG9yX2dyYXBocWwYAiABKAsyLC50YWlsb3IudjEuRXhlY3V0b3JUYXJnZXRUYWlsb3JHcmFwaHFsQ29uZmlnSAASOwoIZnVuY3Rpb24YAyABKAsyJy50YWlsb3IudjEuRXhlY3V0b3JUYXJnZXRGdW5jdGlvbkNvbmZpZ0gAEjsKCHdvcmtmbG93GAUgASgLMicudGFpbG9yLnYxLkV4ZWN1dG9yVGFyZ2V0V29ya2Zsb3dDb25maWdIAEIPCgZjb25maWcSBbpIAggBIrkBChVFeGVjdXRvcldlYmhvb2tDb25maWcSHgoDdXJsGAEgASgLMhEudGFpbG9yLnYxLlNjcmlwdBImCgZzZWNyZXQYAiABKAsyFi50YWlsb3IudjEuU2VjcmV0VmFsdWUSNwoHaGVhZGVycxgDIAMoCzImLnRhaWxvci52MS5FeGVjdXRvclRhcmdldFdlYmhvb2tIZWFkZXISHwoEYm9keRgEIAEoCzIRLnRhaWxvci52MS5TY3JpcHQikQEKG0V4ZWN1dG9yVGFyZ2V0V2ViaG9va0hlYWRlchIUCgNrZXkYASABKAlCB7pIBHICEAESHAoJcmF3X3ZhbHVlGAIgASgJQge6SARyAhABSAASLgoMc2VjcmV0X3ZhbHVlGAMgASgLMhYudGFpbG9yLnYxLlNlY3JldFZhbHVlSABCDgoFdmFsdWUSBbpIAggBIqUBCiFFeGVjdXRvclRhcmdldFRhaWxvckdyYXBocWxDb25maWcSGQoIYXBwX25hbWUYASABKAlCB7pIBHICEAESFgoFcXVlcnkYAiABKAlCB7pIBHICEAESJAoJdmFyaWFibGVzGAMgASgLMhEudGFpbG9yLnYxLlNjcmlwdBInCgdpbnZva2VyGAQgASgLMhYudGFpbG9yLnYxLkF1dGhJbnZva2VyIsUBChxFeGVjdXRvclRhcmdldEZ1bmN0aW9uQ29uZmlnEhUKBG5hbWUYASABKAlCB7pIBHICEAESDgoGc2NyaXB0GAIgASgJEiQKCXZhcmlhYmxlcxgDIAEoCzIRLnRhaWxvci52MS5TY3JpcHQSJwoHaW52b2tlchgEIAEoCzIWLnRhaWxvci52MS5BdXRoSW52b2tlchIgCgpzY3JpcHRfcmVmGAUgASgJQge6SARyAhABSACIAQFCDQoLX3NjcmlwdF9yZWYijQEKHEV4ZWN1dG9yVGFyZ2V0V29ya2Zsb3dDb25maWcSHgoNd29ya2Zsb3dfbmFtZRgBIAEoCUIHukgEcgIQARIkCgl2YXJpYWJsZXMYAiABKAsyES50YWlsb3IudjEuU2NyaXB0EicKB2ludm9rZXIYAyABKAsyFi50YWlsb3IudjEuQXV0aEludm9rZXIi3gIKC0V4ZWN1dG9ySm9iEgoKAmlkGAEgASgJEhUKDWV4ZWN1dG9yX25hbWUYAiABKAkSLAoGc3RhdHVzGAMgASgOMhwudGFpbG9yLnYxLkV4ZWN1dG9ySm9iU3RhdHVzEiYKBWFjdG9yGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIlCgRkYXRhGAUgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIdChVldmVudF9pZGVtcG90ZW5jeV9rZXkYBiABKAkSMAoMc2NoZWR1bGVkX2F0GAcgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgpjcmVhdGVkX2F0GAggASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgp1cGRhdGVkX2F0GAkgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcCLLAgoSRXhlY3V0b3JKb2JBdHRlbXB0EgoKAmlkGAEgASgJEg4KBmpvYl9pZBgCIAEoCRIsCgZzdGF0dXMYAyABKA4yHC50YWlsb3IudjEuRXhlY3V0b3JKb2JTdGF0dXMSDQoFZXJyb3IYBCABKAkSLgoKc3RhcnRlZF9hdBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASLwoLZmluaXNoZWRfYXQYBiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEi4KCmNyZWF0ZWRfYXQYByABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEi4KCnVwZGF0ZWRfYXQYCCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEhsKE29wZXJhdGlvbl9yZWZlcmVuY2UYCSABKAkiTwoXRXhlY3V0b3JJbmNvbWluZ1dlYmhvb2sSFQoNZXhlY3V0b3JfbmFtZRgBIAEoCRILCgN1cmwYAiABKAkSEAoIZGlzYWJsZWQYAyABKAgqrQEKE0V4ZWN1dG9yVHJpZ2dlclR5cGUSJQohRVhFQ1VUT1JfVFJJR0dFUl9UWVBFX1VOU1BFQ0lGSUVEEAASIgoeRVhFQ1VUT1JfVFJJR0dFUl9UWVBFX1NDSEVEVUxFEAESHwobRVhFQ1VUT1JfVFJJR0dFUl9UWVBFX0VWRU5UEAISKgomRVhFQ1VUT1JfVFJJR0dFUl9UWVBFX0lOQ09NSU5HX1dFQkhPT0sQAyryAQoSRXhlY3V0b3JUYXJnZXRUeXBlEiQKIEVYRUNVVE9SX1RBUkdFVF9UWVBFX1VOU1BFQ0lGSUVEEAASIAocRVhFQ1VUT1JfVEFSR0VUX1RZUEVfV0VCSE9PSxABEicKI0VYRUNVVE9SX1RBUkdFVF9UWVBFX1RBSUxPUl9HUkFQSFFMEAISIQodRVhFQ1VUT1JfVEFSR0VUX1RZUEVfRlVOQ1RJT04QAxIlCiFFWEVDVVRPUl9UQVJHRVRfVFlQRV9KT0JfRlVOQ1RJT04QBBIhCh1FWEVDVVRPUl9UQVJHRVRfVFlQRV9XT1JLRkxPVxAFKt0BChFFeGVjdXRvckpvYlN0YXR1cxIjCh9FWEVDVVRPUl9KT0JfU1RBVFVTX1VOU1BFQ0lGSUVEEAASHwobRVhFQ1VUT1JfSk9CX1NUQVRVU19QRU5ESU5HEAESHwobRVhFQ1VUT1JfSk9CX1NUQVRVU19SVU5OSU5HEAISHwobRVhFQ1VUT1JfSk9CX1NUQVRVU19TVUNDRVNTEAMSHgoaRVhFQ1VUT1JfSk9CX1NUQVRVU19GQUlMRUQQBBIgChxFWEVDVVRPUl9KT0JfU1RBVFVTX0NBTkNFTEVEEAViBnByb3RvMw", [
469
+ const file_tailor_v1_executor_resource = /* @__PURE__ */ fileDesc("CiF0YWlsb3IvdjEvZXhlY3V0b3JfcmVzb3VyY2UucHJvdG8SCXRhaWxvci52MSL9AgoQRXhlY3V0b3JFeGVjdXRvchI2CgRuYW1lGAEgASgJQii6SCVyIzIhXlthLXowLTldW2EtejAtOS1dezEsNjF9W2EtejAtOV0kEhMKC2Rlc2NyaXB0aW9uGAIgASgJEkIKDHRyaWdnZXJfdHlwZRgDIAEoDjIeLnRhaWxvci52MS5FeGVjdXRvclRyaWdnZXJUeXBlQgy6SAmCAQYYARgCGAMSQAoOdHJpZ2dlcl9jb25maWcYBCABKAsyIC50YWlsb3IudjEuRXhlY3V0b3JUcmlnZ2VyQ29uZmlnQga6SAPIAQESRAoLdGFyZ2V0X3R5cGUYBSABKA4yHS50YWlsb3IudjEuRXhlY3V0b3JUYXJnZXRUeXBlQhC6SA2CAQoYARgCGAMYBBgFEj4KDXRhcmdldF9jb25maWcYBiABKAsyHy50YWlsb3IudjEuRXhlY3V0b3JUYXJnZXRDb25maWdCBrpIA8gBARIQCghkaXNhYmxlZBgHIAEoCCLrAQoVRXhlY3V0b3JUcmlnZ2VyQ29uZmlnEjwKCHNjaGVkdWxlGAEgASgLMigudGFpbG9yLnYxLkV4ZWN1dG9yVHJpZ2dlclNjaGVkdWxlQ29uZmlnSAASNgoFZXZlbnQYAiABKAsyJS50YWlsb3IudjEuRXhlY3V0b3JUcmlnZ2VyRXZlbnRDb25maWdIABJLChBpbmNvbWluZ193ZWJob29rGAMgASgLMi8udGFpbG9yLnYxLkV4ZWN1dG9yVHJpZ2dlckluY29taW5nV2ViaG9va0NvbmZpZ0gAQg8KBmNvbmZpZxIFukgCCAEiVgodRXhlY3V0b3JUcmlnZ2VyU2NoZWR1bGVDb25maWcSGQoIdGltZXpvbmUYASABKAlCB7pIBHICEAESGgoJZnJlcXVlbmN5GAIgASgJQge6SARyAhABIswCChpFeGVjdXRvclRyaWdnZXJFdmVudENvbmZpZxIWCgpldmVudF90eXBlGAEgASgJQgIYARIoCgljb25kaXRpb24YAiABKAsyES50YWlsb3IudjEuU2NyaXB0QgIYARI6Cgh0YWlsb3JkYhgDIAEoCzImLnRhaWxvci52MS5FeGVjdXRvclRhaWxvckRCRXZlbnRDb25maWdIABIwCgNpZHAYBCABKAsyIS50YWlsb3IudjEuRXhlY3V0b3JJZFBFdmVudENvbmZpZ0gAEjIKBGF1dGgYBSABKAsyIi50YWlsb3IudjEuRXhlY3V0b3JBdXRoRXZlbnRDb25maWdIABI6CghwaXBlbGluZRgGIAEoCzImLnRhaWxvci52MS5FeGVjdXRvclBpcGVsaW5lRXZlbnRDb25maWdIAEIOCgx0eXBlZF9jb25maWci6QEKG0V4ZWN1dG9yVGFpbG9yREJFdmVudENvbmZpZxIuCgtldmVudF90eXBlcxgBIAMoCUIZukgWkgETCAEiD3INMgtedGFpbG9yZGJcLhJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIyCgl0eXBlX25hbWUYAyABKAlCH7pIHHIaMhheW0EtWl1bYS16QS1aMC05XXswLDYyfSQSJAoJY29uZGl0aW9uGAQgASgLMhEudGFpbG9yLnYxLlNjcmlwdCKrAQoWRXhlY3V0b3JJZFBFdmVudENvbmZpZxIpCgtldmVudF90eXBlcxgBIAMoCUIUukgRkgEOCAEiCnIIMgZeaWRwXC4SQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSJAoJY29uZGl0aW9uGAMgASgLMhEudGFpbG9yLnYxLlNjcmlwdCKtAQoXRXhlY3V0b3JBdXRoRXZlbnRDb25maWcSKgoLZXZlbnRfdHlwZXMYASADKAlCFbpIEpIBDwgBIgtyCTIHXmF1dGhcLhJACg5uYW1lc3BhY2VfbmFtZRgCIAEoCUIoukglciMyIV5bYS16MC05XVthLXowLTktXXsxLDYxfVthLXowLTldJBIkCgljb25kaXRpb24YAyABKAsyES50YWlsb3IudjEuU2NyaXB0ItUBChtFeGVjdXRvclBpcGVsaW5lRXZlbnRDb25maWcSLgoLZXZlbnRfdHlwZXMYASADKAlCGbpIFpIBEwgBIg9yDTILXnBpcGVsaW5lXC4SQAoObmFtZXNwYWNlX25hbWUYAiABKAlCKLpIJXIjMiFeW2EtejAtOV1bYS16MC05LV17MSw2MX1bYS16MC05XSQSHgoNcmVzb2x2ZXJfbmFtZRgDIAEoCUIHukgEcgIQARIkCgljb25kaXRpb24YBCABKAsyES50YWlsb3IudjEuU2NyaXB0IjsKJEV4ZWN1dG9yVHJpZ2dlckluY29taW5nV2ViaG9va0NvbmZpZxITCgZzZWNyZXQYASABKAlCA+BBAyKeAgoURXhlY3V0b3JUYXJnZXRDb25maWcSMwoHd2ViaG9vaxgBIAEoCzIgLnRhaWxvci52MS5FeGVjdXRvcldlYmhvb2tDb25maWdIABJGCg50YWlsb3JfZ3JhcGhxbBgCIAEoCzIsLnRhaWxvci52MS5FeGVjdXRvclRhcmdldFRhaWxvckdyYXBocWxDb25maWdIABI7CghmdW5jdGlvbhgDIAEoCzInLnRhaWxvci52MS5FeGVjdXRvclRhcmdldEZ1bmN0aW9uQ29uZmlnSAASOwoId29ya2Zsb3cYBSABKAsyJy50YWlsb3IudjEuRXhlY3V0b3JUYXJnZXRXb3JrZmxvd0NvbmZpZ0gAQg8KBmNvbmZpZxIFukgCCAEiuQEKFUV4ZWN1dG9yV2ViaG9va0NvbmZpZxIeCgN1cmwYASABKAsyES50YWlsb3IudjEuU2NyaXB0EiYKBnNlY3JldBgCIAEoCzIWLnRhaWxvci52MS5TZWNyZXRWYWx1ZRI3CgdoZWFkZXJzGAMgAygLMiYudGFpbG9yLnYxLkV4ZWN1dG9yVGFyZ2V0V2ViaG9va0hlYWRlchIfCgRib2R5GAQgASgLMhEudGFpbG9yLnYxLlNjcmlwdCKRAQobRXhlY3V0b3JUYXJnZXRXZWJob29rSGVhZGVyEhQKA2tleRgBIAEoCUIHukgEcgIQARIcCglyYXdfdmFsdWUYAiABKAlCB7pIBHICEAFIABIuCgxzZWNyZXRfdmFsdWUYAyABKAsyFi50YWlsb3IudjEuU2VjcmV0VmFsdWVIAEIOCgV2YWx1ZRIFukgCCAEipQEKIUV4ZWN1dG9yVGFyZ2V0VGFpbG9yR3JhcGhxbENvbmZpZxIZCghhcHBfbmFtZRgBIAEoCUIHukgEcgIQARIWCgVxdWVyeRgCIAEoCUIHukgEcgIQARIkCgl2YXJpYWJsZXMYAyABKAsyES50YWlsb3IudjEuU2NyaXB0EicKB2ludm9rZXIYBCABKAsyFi50YWlsb3IudjEuQXV0aEludm9rZXIixQEKHEV4ZWN1dG9yVGFyZ2V0RnVuY3Rpb25Db25maWcSFQoEbmFtZRgBIAEoCUIHukgEcgIQARIOCgZzY3JpcHQYAiABKAkSJAoJdmFyaWFibGVzGAMgASgLMhEudGFpbG9yLnYxLlNjcmlwdBInCgdpbnZva2VyGAQgASgLMhYudGFpbG9yLnYxLkF1dGhJbnZva2VyEiAKCnNjcmlwdF9yZWYYBSABKAlCB7pIBHICEAFIAIgBAUINCgtfc2NyaXB0X3JlZiKNAQocRXhlY3V0b3JUYXJnZXRXb3JrZmxvd0NvbmZpZxIeCg13b3JrZmxvd19uYW1lGAEgASgJQge6SARyAhABEiQKCXZhcmlhYmxlcxgCIAEoCzIRLnRhaWxvci52MS5TY3JpcHQSJwoHaW52b2tlchgDIAEoCzIWLnRhaWxvci52MS5BdXRoSW52b2tlciLeAgoLRXhlY3V0b3JKb2ISCgoCaWQYASABKAkSFQoNZXhlY3V0b3JfbmFtZRgCIAEoCRIsCgZzdGF0dXMYAyABKA4yHC50YWlsb3IudjEuRXhlY3V0b3JKb2JTdGF0dXMSJgoFYWN0b3IYBCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EiUKBGRhdGEYBSABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Eh0KFWV2ZW50X2lkZW1wb3RlbmN5X2tleRgGIAEoCRIwCgxzY2hlZHVsZWRfYXQYByABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEi4KCmNyZWF0ZWRfYXQYCCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEi4KCnVwZGF0ZWRfYXQYCSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wIssCChJFeGVjdXRvckpvYkF0dGVtcHQSCgoCaWQYASABKAkSDgoGam9iX2lkGAIgASgJEiwKBnN0YXR1cxgDIAEoDjIcLnRhaWxvci52MS5FeGVjdXRvckpvYlN0YXR1cxINCgVlcnJvchgEIAEoCRIuCgpzdGFydGVkX2F0GAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIvCgtmaW5pc2hlZF9hdBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASLgoKY3JlYXRlZF9hdBgHIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASLgoKdXBkYXRlZF9hdBgIIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASGwoTb3BlcmF0aW9uX3JlZmVyZW5jZRgJIAEoCSJPChdFeGVjdXRvckluY29taW5nV2ViaG9vaxIVCg1leGVjdXRvcl9uYW1lGAEgASgJEgsKA3VybBgCIAEoCRIQCghkaXNhYmxlZBgDIAEoCCqtAQoTRXhlY3V0b3JUcmlnZ2VyVHlwZRIlCiFFWEVDVVRPUl9UUklHR0VSX1RZUEVfVU5TUEVDSUZJRUQQABIiCh5FWEVDVVRPUl9UUklHR0VSX1RZUEVfU0NIRURVTEUQARIfChtFWEVDVVRPUl9UUklHR0VSX1RZUEVfRVZFTlQQAhIqCiZFWEVDVVRPUl9UUklHR0VSX1RZUEVfSU5DT01JTkdfV0VCSE9PSxADKvIBChJFeGVjdXRvclRhcmdldFR5cGUSJAogRVhFQ1VUT1JfVEFSR0VUX1RZUEVfVU5TUEVDSUZJRUQQABIgChxFWEVDVVRPUl9UQVJHRVRfVFlQRV9XRUJIT09LEAESJwojRVhFQ1VUT1JfVEFSR0VUX1RZUEVfVEFJTE9SX0dSQVBIUUwQAhIhCh1FWEVDVVRPUl9UQVJHRVRfVFlQRV9GVU5DVElPThADEiUKIUVYRUNVVE9SX1RBUkdFVF9UWVBFX0pPQl9GVU5DVElPThAEEiEKHUVYRUNVVE9SX1RBUkdFVF9UWVBFX1dPUktGTE9XEAUq3QEKEUV4ZWN1dG9ySm9iU3RhdHVzEiMKH0VYRUNVVE9SX0pPQl9TVEFUVVNfVU5TUEVDSUZJRUQQABIfChtFWEVDVVRPUl9KT0JfU1RBVFVTX1BFTkRJTkcQARIfChtFWEVDVVRPUl9KT0JfU1RBVFVTX1JVTk5JTkcQAhIfChtFWEVDVVRPUl9KT0JfU1RBVFVTX1NVQ0NFU1MQAxIeChpFWEVDVVRPUl9KT0JfU1RBVFVTX0ZBSUxFRBAEEiAKHEVYRUNVVE9SX0pPQl9TVEFUVVNfQ0FOQ0VMRUQQBWIGcHJvdG8z", [
460
470
  file_buf_validate_validate,
461
471
  file_google_api_field_behavior,
462
472
  file_google_protobuf_struct,
@@ -853,7 +863,7 @@ const file_tailor_v1_workspace = /* @__PURE__ */ fileDesc("Chl0YWlsb3IvdjEvd29ya
853
863
  /**
854
864
  * Describes the file tailor/v1/service.proto.
855
865
  */
856
- const file_tailor_v1_service = /* @__PURE__ */ fileDesc("Chd0YWlsb3IvdjEvc2VydmljZS5wcm90bxIJdGFpbG9yLnYxIg0KC1BpbmdSZXF1ZXN0Ig4KDFBpbmdSZXNwb25zZTKdugEKD09wZXJhdG9yU2VydmljZRI5CgRQaW5nEhYudGFpbG9yLnYxLlBpbmdSZXF1ZXN0GhcudGFpbG9yLnYxLlBpbmdSZXNwb25zZSIAEocBCh1MaXN0QXZhaWxhYmxlV29ya3NwYWNlUmVnaW9ucxIvLnRhaWxvci52MS5MaXN0QXZhaWxhYmxlV29ya3NwYWNlUmVnaW9uc1JlcXVlc3QaMC50YWlsb3IudjEuTGlzdEF2YWlsYWJsZVdvcmtzcGFjZVJlZ2lvbnNSZXNwb25zZSIDkAIBEloKD0NyZWF0ZVdvcmtzcGFjZRIhLnRhaWxvci52MS5DcmVhdGVXb3Jrc3BhY2VSZXF1ZXN0GiIudGFpbG9yLnYxLkNyZWF0ZVdvcmtzcGFjZVJlc3BvbnNlIgASWgoPVXBkYXRlV29ya3NwYWNlEiEudGFpbG9yLnYxLlVwZGF0ZVdvcmtzcGFjZVJlcXVlc3QaIi50YWlsb3IudjEuVXBkYXRlV29ya3NwYWNlUmVzcG9uc2UiABJaCg9EZWxldGVXb3Jrc3BhY2USIS50YWlsb3IudjEuRGVsZXRlV29ya3NwYWNlUmVxdWVzdBoiLnRhaWxvci52MS5EZWxldGVXb3Jrc3BhY2VSZXNwb25zZSIAEloKDkxpc3RXb3Jrc3BhY2VzEiAudGFpbG9yLnYxLkxpc3RXb3Jrc3BhY2VzUmVxdWVzdBohLnRhaWxvci52MS5MaXN0V29ya3NwYWNlc1Jlc3BvbnNlIgOQAgESfgoaTGlzdE9yZ2FuaXphdGlvbldvcmtzcGFjZXMSLC50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbldvcmtzcGFjZXNSZXF1ZXN0Gi0udGFpbG9yLnYxLkxpc3RPcmdhbml6YXRpb25Xb3Jrc3BhY2VzUmVzcG9uc2UiA5ACARJdChBSZXN0b3JlV29ya3NwYWNlEiIudGFpbG9yLnYxLlJlc3RvcmVXb3Jrc3BhY2VSZXF1ZXN0GiMudGFpbG9yLnYxLlJlc3RvcmVXb3Jrc3BhY2VSZXNwb25zZSIAElQKDEdldFdvcmtzcGFjZRIeLnRhaWxvci52MS5HZXRXb3Jrc3BhY2VSZXF1ZXN0Gh8udGFpbG9yLnYxLkdldFdvcmtzcGFjZVJlc3BvbnNlIgOQAgESfgoaTGlzdFdvcmtzcGFjZVBsYXRmb3JtVXNlcnMSLC50YWlsb3IudjEuTGlzdFdvcmtzcGFjZVBsYXRmb3JtVXNlcnNSZXF1ZXN0Gi0udGFpbG9yLnYxLkxpc3RXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJzUmVzcG9uc2UiA5ACARKlAQonTGlzdEF2YWlsYWJsZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJvbGVzEjkudGFpbG9yLnYxLkxpc3RBdmFpbGFibGVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSb2xlc1JlcXVlc3QaOi50YWlsb3IudjEuTGlzdEF2YWlsYWJsZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJvbGVzUmVzcG9uc2UiA5ACARJ+ChtJbnZpdGVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXISLS50YWlsb3IudjEuSW52aXRlV29ya3NwYWNlUGxhdGZvcm1Vc2VyUmVxdWVzdBouLnRhaWxvci52MS5JbnZpdGVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSZXNwb25zZSIAEn4KG1JlbW92ZVdvcmtzcGFjZVBsYXRmb3JtVXNlchItLnRhaWxvci52MS5SZW1vdmVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSZXF1ZXN0Gi4udGFpbG9yLnYxLlJlbW92ZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJlc3BvbnNlIgASfgobVXBkYXRlV29ya3NwYWNlUGxhdGZvcm1Vc2VyEi0udGFpbG9yLnYxLlVwZGF0ZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJlcXVlc3QaLi50YWlsb3IudjEuVXBkYXRlV29ya3NwYWNlUGxhdGZvcm1Vc2VyUmVzcG9uc2UiABJ4ChhHZXRXb3Jrc3BhY2VQbGF0Zm9ybVVzZXISKi50YWlsb3IudjEuR2V0V29ya3NwYWNlUGxhdGZvcm1Vc2VyUmVxdWVzdBorLnRhaWxvci52MS5HZXRXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSZXNwb25zZSIDkAIBEmAKEEdldFdvcmtzcGFjZVJvbGUSIi50YWlsb3IudjEuR2V0V29ya3NwYWNlUm9sZVJlcXVlc3QaIy50YWlsb3IudjEuR2V0V29ya3NwYWNlUm9sZVJlc3BvbnNlIgOQAgESYwoSVXBkYXRlT3JnYW5pemF0aW9uEiQudGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvblJlcXVlc3QaJS50YWlsb3IudjEuVXBkYXRlT3JnYW5pemF0aW9uUmVzcG9uc2UiABJdCg9HZXRPcmdhbml6YXRpb24SIS50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uUmVxdWVzdBoiLnRhaWxvci52MS5HZXRPcmdhbml6YXRpb25SZXNwb25zZSIDkAIBEmMKEUxpc3RPcmdhbml6YXRpb25zEiMudGFpbG9yLnYxLkxpc3RPcmdhbml6YXRpb25zUmVxdWVzdBokLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uc1Jlc3BvbnNlIgOQAgESbwoVTGlzdFVzZXJPcmdhbml6YXRpb25zEicudGFpbG9yLnYxLkxpc3RVc2VyT3JnYW5pemF0aW9uc1JlcXVlc3QaKC50YWlsb3IudjEuTGlzdFVzZXJPcmdhbml6YXRpb25zUmVzcG9uc2UiA5ACARJyChdHcmFudE9yZ2FuaXphdGlvbkFjY2VzcxIpLnRhaWxvci52MS5HcmFudE9yZ2FuaXphdGlvbkFjY2Vzc1JlcXVlc3QaKi50YWlsb3IudjEuR3JhbnRPcmdhbml6YXRpb25BY2Nlc3NSZXNwb25zZSIAEnUKGFVwZGF0ZU9yZ2FuaXphdGlvbkFjY2VzcxIqLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25BY2Nlc3NSZXF1ZXN0GisudGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvbkFjY2Vzc1Jlc3BvbnNlIgASdQoYUmV2b2tlT3JnYW5pemF0aW9uQWNjZXNzEioudGFpbG9yLnYxLlJldm9rZU9yZ2FuaXphdGlvbkFjY2Vzc1JlcXVlc3QaKy50YWlsb3IudjEuUmV2b2tlT3JnYW5pemF0aW9uQWNjZXNzUmVzcG9uc2UiABJ4ChhMaXN0T3JnYW5pemF0aW9uQWNjZXNzZXMSKi50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbkFjY2Vzc2VzUmVxdWVzdBorLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uQWNjZXNzZXNSZXNwb25zZSIDkAIBEm8KFUdldE9yZ2FuaXphdGlvbkFjY2VzcxInLnRhaWxvci52MS5HZXRPcmdhbml6YXRpb25BY2Nlc3NSZXF1ZXN0GigudGFpbG9yLnYxLkdldE9yZ2FuaXphdGlvbkFjY2Vzc1Jlc3BvbnNlIgOQAgESdQoYQ3JlYXRlT3JnYW5pemF0aW9uRm9sZGVyEioudGFpbG9yLnYxLkNyZWF0ZU9yZ2FuaXphdGlvbkZvbGRlclJlcXVlc3QaKy50YWlsb3IudjEuQ3JlYXRlT3JnYW5pemF0aW9uRm9sZGVyUmVzcG9uc2UiABJ1ChhVcGRhdGVPcmdhbml6YXRpb25Gb2xkZXISKi50YWlsb3IudjEuVXBkYXRlT3JnYW5pemF0aW9uRm9sZGVyUmVxdWVzdBorLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25Gb2xkZXJSZXNwb25zZSIAEnUKGERlbGV0ZU9yZ2FuaXphdGlvbkZvbGRlchIqLnRhaWxvci52MS5EZWxldGVPcmdhbml6YXRpb25Gb2xkZXJSZXF1ZXN0GisudGFpbG9yLnYxLkRlbGV0ZU9yZ2FuaXphdGlvbkZvbGRlclJlc3BvbnNlIgASbwoVR2V0T3JnYW5pemF0aW9uRm9sZGVyEicudGFpbG9yLnYxLkdldE9yZ2FuaXphdGlvbkZvbGRlclJlcXVlc3QaKC50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uRm9sZGVyUmVzcG9uc2UiA5ACARJ1ChdMaXN0T3JnYW5pemF0aW9uRm9sZGVycxIpLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uRm9sZGVyc1JlcXVlc3QaKi50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbkZvbGRlcnNSZXNwb25zZSIDkAIBEoQBCh1HcmFudE9yZ2FuaXphdGlvbkZvbGRlckFjY2VzcxIvLnRhaWxvci52MS5HcmFudE9yZ2FuaXphdGlvbkZvbGRlckFjY2Vzc1JlcXVlc3QaMC50YWlsb3IudjEuR3JhbnRPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIAEocBCh5VcGRhdGVPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3MSMC50YWlsb3IudjEuVXBkYXRlT3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzUmVxdWVzdBoxLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIAEocBCh5SZXZva2VPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3MSMC50YWlsb3IudjEuUmV2b2tlT3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzUmVxdWVzdBoxLnRhaWxvci52MS5SZXZva2VPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIAEooBCh5MaXN0T3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzZXMSMC50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbkZvbGRlckFjY2Vzc2VzUmVxdWVzdBoxLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzZXNSZXNwb25zZSIDkAIBEoEBChtHZXRPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3MSLS50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzUmVxdWVzdBouLnRhaWxvci52MS5HZXRPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIDkAIBEm8KFkNyZWF0ZU9yZ2FuaXphdGlvblRlYW0SKC50YWlsb3IudjEuQ3JlYXRlT3JnYW5pemF0aW9uVGVhbVJlcXVlc3QaKS50YWlsb3IudjEuQ3JlYXRlT3JnYW5pemF0aW9uVGVhbVJlc3BvbnNlIgASbwoWVXBkYXRlT3JnYW5pemF0aW9uVGVhbRIoLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25UZWFtUmVxdWVzdBopLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25UZWFtUmVzcG9uc2UiABJvChZEZWxldGVPcmdhbml6YXRpb25UZWFtEigudGFpbG9yLnYxLkRlbGV0ZU9yZ2FuaXphdGlvblRlYW1SZXF1ZXN0GikudGFpbG9yLnYxLkRlbGV0ZU9yZ2FuaXphdGlvblRlYW1SZXNwb25zZSIAEmkKE0dldE9yZ2FuaXphdGlvblRlYW0SJS50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbVJlcXVlc3QaJi50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbVJlc3BvbnNlIgOQAgESbwoVTGlzdE9yZ2FuaXphdGlvblRlYW1zEicudGFpbG9yLnYxLkxpc3RPcmdhbml6YXRpb25UZWFtc1JlcXVlc3QaKC50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvblRlYW1zUmVzcG9uc2UiA5ACARJ4ChlBZGRPcmdhbml6YXRpb25UZWFtTWVtYmVyEisudGFpbG9yLnYxLkFkZE9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXF1ZXN0GiwudGFpbG9yLnYxLkFkZE9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXNwb25zZSIAEoEBChxVcGRhdGVPcmdhbml6YXRpb25UZWFtTWVtYmVyEi4udGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXF1ZXN0Gi8udGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXNwb25zZSIAEoEBChxSZW1vdmVPcmdhbml6YXRpb25UZWFtTWVtYmVyEi4udGFpbG9yLnYxLlJlbW92ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXF1ZXN0Gi8udGFpbG9yLnYxLlJlbW92ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXNwb25zZSIAEoEBChtMaXN0T3JnYW5pemF0aW9uVGVhbU1lbWJlcnMSLS50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvblRlYW1NZW1iZXJzUmVxdWVzdBouLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uVGVhbU1lbWJlcnNSZXNwb25zZSIDkAIBEnsKGUdldE9yZ2FuaXphdGlvblRlYW1NZW1iZXISKy50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbU1lbWJlclJlcXVlc3QaLC50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbU1lbWJlclJlc3BvbnNlIgOQAgEScgoWR2V0UGxhdGZvcm1BY2NvdW50UGxhbhIoLnRhaWxvci52MS5HZXRQbGF0Zm9ybUFjY291bnRQbGFuUmVxdWVzdBopLnRhaWxvci52MS5HZXRQbGF0Zm9ybUFjY291bnRQbGFuUmVzcG9uc2UiA5ACARJgChFDcmVhdGVBcHBsaWNhdGlvbhIjLnRhaWxvci52MS5DcmVhdGVBcHBsaWNhdGlvblJlcXVlc3QaJC50YWlsb3IudjEuQ3JlYXRlQXBwbGljYXRpb25SZXNwb25zZSIAEmAKEVVwZGF0ZUFwcGxpY2F0aW9uEiMudGFpbG9yLnYxLlVwZGF0ZUFwcGxpY2F0aW9uUmVxdWVzdBokLnRhaWxvci52MS5VcGRhdGVBcHBsaWNhdGlvblJlc3BvbnNlIgASYAoRRGVsZXRlQXBwbGljYXRpb24SIy50YWlsb3IudjEuRGVsZXRlQXBwbGljYXRpb25SZXF1ZXN0GiQudGFpbG9yLnYxLkRlbGV0ZUFwcGxpY2F0aW9uUmVzcG9uc2UiABJgChBMaXN0QXBwbGljYXRpb25zEiIudGFpbG9yLnYxLkxpc3RBcHBsaWNhdGlvbnNSZXF1ZXN0GiMudGFpbG9yLnYxLkxpc3RBcHBsaWNhdGlvbnNSZXNwb25zZSIDkAIBEloKDkdldEFwcGxpY2F0aW9uEiAudGFpbG9yLnYxLkdldEFwcGxpY2F0aW9uUmVxdWVzdBohLnRhaWxvci52MS5HZXRBcHBsaWNhdGlvblJlc3BvbnNlIgOQAgESfgoaR2V0QXBwbGljYXRpb25TY2hlbWFIZWFsdGgSLC50YWlsb3IudjEuR2V0QXBwbGljYXRpb25TY2hlbWFIZWFsdGhSZXF1ZXN0Gi0udGFpbG9yLnYxLkdldEFwcGxpY2F0aW9uU2NoZW1hSGVhbHRoUmVzcG9uc2UiA5ACARJjChJDb21wb3NlVGFpbG9yREJTREwSJC50YWlsb3IudjEuQ29tcG9zZVRhaWxvckRCU0RMUmVxdWVzdBolLnRhaWxvci52MS5Db21wb3NlVGFpbG9yREJTRExSZXNwb25zZSIAEmwKFUNyZWF0ZVRhaWxvckRCU2VydmljZRInLnRhaWxvci52MS5DcmVhdGVUYWlsb3JEQlNlcnZpY2VSZXF1ZXN0GigudGFpbG9yLnYxLkNyZWF0ZVRhaWxvckRCU2VydmljZVJlc3BvbnNlIgASbAoVVXBkYXRlVGFpbG9yREJTZXJ2aWNlEicudGFpbG9yLnYxLlVwZGF0ZVRhaWxvckRCU2VydmljZVJlcXVlc3QaKC50YWlsb3IudjEuVXBkYXRlVGFpbG9yREJTZXJ2aWNlUmVzcG9uc2UiABJsChVEZWxldGVUYWlsb3JEQlNlcnZpY2USJy50YWlsb3IudjEuRGVsZXRlVGFpbG9yREJTZXJ2aWNlUmVxdWVzdBooLnRhaWxvci52MS5EZWxldGVUYWlsb3JEQlNlcnZpY2VSZXNwb25zZSIAEmYKEkdldFRhaWxvckRCU2VydmljZRIkLnRhaWxvci52MS5HZXRUYWlsb3JEQlNlcnZpY2VSZXF1ZXN0GiUudGFpbG9yLnYxLkdldFRhaWxvckRCU2VydmljZVJlc3BvbnNlIgOQAgESbAoUTGlzdFRhaWxvckRCU2VydmljZXMSJi50YWlsb3IudjEuTGlzdFRhaWxvckRCU2VydmljZXNSZXF1ZXN0GicudGFpbG9yLnYxLkxpc3RUYWlsb3JEQlNlcnZpY2VzUmVzcG9uc2UiA5ACARJjChJDcmVhdGVUYWlsb3JEQlR5cGUSJC50YWlsb3IudjEuQ3JlYXRlVGFpbG9yREJUeXBlUmVxdWVzdBolLnRhaWxvci52MS5DcmVhdGVUYWlsb3JEQlR5cGVSZXNwb25zZSIAEmMKElVwZGF0ZVRhaWxvckRCVHlwZRIkLnRhaWxvci52MS5VcGRhdGVUYWlsb3JEQlR5cGVSZXF1ZXN0GiUudGFpbG9yLnYxLlVwZGF0ZVRhaWxvckRCVHlwZVJlc3BvbnNlIgASYwoSRGVsZXRlVGFpbG9yREJUeXBlEiQudGFpbG9yLnYxLkRlbGV0ZVRhaWxvckRCVHlwZVJlcXVlc3QaJS50YWlsb3IudjEuRGVsZXRlVGFpbG9yREJUeXBlUmVzcG9uc2UiABJsChVUcnVuY2F0ZVRhaWxvckRCVHlwZXMSJy50YWlsb3IudjEuVHJ1bmNhdGVUYWlsb3JEQlR5cGVzUmVxdWVzdBooLnRhaWxvci52MS5UcnVuY2F0ZVRhaWxvckRCVHlwZXNSZXNwb25zZSIAEmkKFFRydW5jYXRlVGFpbG9yREJUeXBlEiYudGFpbG9yLnYxLlRydW5jYXRlVGFpbG9yREJUeXBlUmVxdWVzdBonLnRhaWxvci52MS5UcnVuY2F0ZVRhaWxvckRCVHlwZVJlc3BvbnNlIgASYwoRTGlzdFRhaWxvckRCVHlwZXMSIy50YWlsb3IudjEuTGlzdFRhaWxvckRCVHlwZXNSZXF1ZXN0GiQudGFpbG9yLnYxLkxpc3RUYWlsb3JEQlR5cGVzUmVzcG9uc2UiA5ACARJdCg9HZXRUYWlsb3JEQlR5cGUSIS50YWlsb3IudjEuR2V0VGFpbG9yREJUeXBlUmVxdWVzdBoiLnRhaWxvci52MS5HZXRUYWlsb3JEQlR5cGVSZXNwb25zZSIDkAIBEn4KG0NyZWF0ZVRhaWxvckRCR1FMUGVybWlzc2lvbhItLnRhaWxvci52MS5DcmVhdGVUYWlsb3JEQkdRTFBlcm1pc3Npb25SZXF1ZXN0Gi4udGFpbG9yLnYxLkNyZWF0ZVRhaWxvckRCR1FMUGVybWlzc2lvblJlc3BvbnNlIgASeAoYR2V0VGFpbG9yREJHUUxQZXJtaXNzaW9uEioudGFpbG9yLnYxLkdldFRhaWxvckRCR1FMUGVybWlzc2lvblJlcXVlc3QaKy50YWlsb3IudjEuR2V0VGFpbG9yREJHUUxQZXJtaXNzaW9uUmVzcG9uc2UiA5ACARJ+ChpMaXN0VGFpbG9yREJHUUxQZXJtaXNzaW9ucxIsLnRhaWxvci52MS5MaXN0VGFpbG9yREJHUUxQZXJtaXNzaW9uc1JlcXVlc3QaLS50YWlsb3IudjEuTGlzdFRhaWxvckRCR1FMUGVybWlzc2lvbnNSZXNwb25zZSIDkAIBEn4KG1VwZGF0ZVRhaWxvckRCR1FMUGVybWlzc2lvbhItLnRhaWxvci52MS5VcGRhdGVUYWlsb3JEQkdRTFBlcm1pc3Npb25SZXF1ZXN0Gi4udGFpbG9yLnYxLlVwZGF0ZVRhaWxvckRCR1FMUGVybWlzc2lvblJlc3BvbnNlIgASfgobRGVsZXRlVGFpbG9yREJHUUxQZXJtaXNzaW9uEi0udGFpbG9yLnYxLkRlbGV0ZVRhaWxvckRCR1FMUGVybWlzc2lvblJlcXVlc3QaLi50YWlsb3IudjEuRGVsZXRlVGFpbG9yREJHUUxQZXJtaXNzaW9uUmVzcG9uc2UiABJsChVDcmVhdGVQaXBlbGluZVNlcnZpY2USJy50YWlsb3IudjEuQ3JlYXRlUGlwZWxpbmVTZXJ2aWNlUmVxdWVzdBooLnRhaWxvci52MS5DcmVhdGVQaXBlbGluZVNlcnZpY2VSZXNwb25zZSIAEmwKFVVwZGF0ZVBpcGVsaW5lU2VydmljZRInLnRhaWxvci52MS5VcGRhdGVQaXBlbGluZVNlcnZpY2VSZXF1ZXN0GigudGFpbG9yLnYxLlVwZGF0ZVBpcGVsaW5lU2VydmljZVJlc3BvbnNlIgASbAoVRGVsZXRlUGlwZWxpbmVTZXJ2aWNlEicudGFpbG9yLnYxLkRlbGV0ZVBpcGVsaW5lU2VydmljZVJlcXVlc3QaKC50YWlsb3IudjEuRGVsZXRlUGlwZWxpbmVTZXJ2aWNlUmVzcG9uc2UiABJmChJHZXRQaXBlbGluZVNlcnZpY2USJC50YWlsb3IudjEuR2V0UGlwZWxpbmVTZXJ2aWNlUmVxdWVzdBolLnRhaWxvci52MS5HZXRQaXBlbGluZVNlcnZpY2VSZXNwb25zZSIDkAIBEmwKFExpc3RQaXBlbGluZVNlcnZpY2VzEiYudGFpbG9yLnYxLkxpc3RQaXBlbGluZVNlcnZpY2VzUmVxdWVzdBonLnRhaWxvci52MS5MaXN0UGlwZWxpbmVTZXJ2aWNlc1Jlc3BvbnNlIgOQAgESaQoTR2V0UGlwZWxpbmVSZXNvbHZlchIlLnRhaWxvci52MS5HZXRQaXBlbGluZVJlc29sdmVyUmVxdWVzdBomLnRhaWxvci52MS5HZXRQaXBlbGluZVJlc29sdmVyUmVzcG9uc2UiA5ACARJvChVMaXN0UGlwZWxpbmVSZXNvbHZlcnMSJy50YWlsb3IudjEuTGlzdFBpcGVsaW5lUmVzb2x2ZXJzUmVxdWVzdBooLnRhaWxvci52MS5MaXN0UGlwZWxpbmVSZXNvbHZlcnNSZXNwb25zZSIDkAIBEm8KFkNyZWF0ZVBpcGVsaW5lUmVzb2x2ZXISKC50YWlsb3IudjEuQ3JlYXRlUGlwZWxpbmVSZXNvbHZlclJlcXVlc3QaKS50YWlsb3IudjEuQ3JlYXRlUGlwZWxpbmVSZXNvbHZlclJlc3BvbnNlIgASbwoWVXBkYXRlUGlwZWxpbmVSZXNvbHZlchIoLnRhaWxvci52MS5VcGRhdGVQaXBlbGluZVJlc29sdmVyUmVxdWVzdBopLnRhaWxvci52MS5VcGRhdGVQaXBlbGluZVJlc29sdmVyUmVzcG9uc2UiABJvChZEZWxldGVQaXBlbGluZVJlc29sdmVyEigudGFpbG9yLnYxLkRlbGV0ZVBpcGVsaW5lUmVzb2x2ZXJSZXF1ZXN0GikudGFpbG9yLnYxLkRlbGV0ZVBpcGVsaW5lUmVzb2x2ZXJSZXNwb25zZSIAEmMKEkNvbXBvc2VQaXBlbGluZVNETBIkLnRhaWxvci52MS5Db21wb3NlUGlwZWxpbmVTRExSZXF1ZXN0GiUudGFpbG9yLnYxLkNvbXBvc2VQaXBlbGluZVNETFJlc3BvbnNlIgASnAEKJExpc3RQaXBlbGluZVJlc29sdmVyRXhlY3V0aW9uUmVzdWx0cxI2LnRhaWxvci52MS5MaXN0UGlwZWxpbmVSZXNvbHZlckV4ZWN1dGlvblJlc3VsdHNSZXF1ZXN0GjcudGFpbG9yLnYxLkxpc3RQaXBlbGluZVJlc29sdmVyRXhlY3V0aW9uUmVzdWx0c1Jlc3BvbnNlIgOQAgESlgEKIkdldFBpcGVsaW5lUmVzb2x2ZXJFeGVjdXRpb25SZXN1bHQSNC50YWlsb3IudjEuR2V0UGlwZWxpbmVSZXNvbHZlckV4ZWN1dGlvblJlc3VsdFJlcXVlc3QaNS50YWlsb3IudjEuR2V0UGlwZWxpbmVSZXNvbHZlckV4ZWN1dGlvblJlc3VsdFJlc3BvbnNlIgOQAgEScgoXUmVzdGFydFBpcGVsaW5lUmVzb2x2ZXISKS50YWlsb3IudjEuUmVzdGFydFBpcGVsaW5lUmVzb2x2ZXJSZXF1ZXN0GioudGFpbG9yLnYxLlJlc3RhcnRQaXBlbGluZVJlc29sdmVyUmVzcG9uc2UiABJvChZDcmVhdGVTdGF0ZWZsb3dTZXJ2aWNlEigudGFpbG9yLnYxLkNyZWF0ZVN0YXRlZmxvd1NlcnZpY2VSZXF1ZXN0GikudGFpbG9yLnYxLkNyZWF0ZVN0YXRlZmxvd1NlcnZpY2VSZXNwb25zZSIAEm8KFlVwZGF0ZVN0YXRlZmxvd1NlcnZpY2USKC50YWlsb3IudjEuVXBkYXRlU3RhdGVmbG93U2VydmljZVJlcXVlc3QaKS50YWlsb3IudjEuVXBkYXRlU3RhdGVmbG93U2VydmljZVJlc3BvbnNlIgASbwoWRGVsZXRlU3RhdGVmbG93U2VydmljZRIoLnRhaWxvci52MS5EZWxldGVTdGF0ZWZsb3dTZXJ2aWNlUmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVTdGF0ZWZsb3dTZXJ2aWNlUmVzcG9uc2UiABJpChNHZXRTdGF0ZWZsb3dTZXJ2aWNlEiUudGFpbG9yLnYxLkdldFN0YXRlZmxvd1NlcnZpY2VSZXF1ZXN0GiYudGFpbG9yLnYxLkdldFN0YXRlZmxvd1NlcnZpY2VSZXNwb25zZSIDkAIBEm8KFUxpc3RTdGF0ZWZsb3dTZXJ2aWNlcxInLnRhaWxvci52MS5MaXN0U3RhdGVmbG93U2VydmljZXNSZXF1ZXN0GigudGFpbG9yLnYxLkxpc3RTdGF0ZWZsb3dTZXJ2aWNlc1Jlc3BvbnNlIgOQAgESbwoWQ3JlYXRlRXhlY3V0b3JFeGVjdXRvchIoLnRhaWxvci52MS5DcmVhdGVFeGVjdXRvckV4ZWN1dG9yUmVxdWVzdBopLnRhaWxvci52MS5DcmVhdGVFeGVjdXRvckV4ZWN1dG9yUmVzcG9uc2UiABJvChZVcGRhdGVFeGVjdXRvckV4ZWN1dG9yEigudGFpbG9yLnYxLlVwZGF0ZUV4ZWN1dG9yRXhlY3V0b3JSZXF1ZXN0GikudGFpbG9yLnYxLlVwZGF0ZUV4ZWN1dG9yRXhlY3V0b3JSZXNwb25zZSIAEmkKE0dldEV4ZWN1dG9yRXhlY3V0b3ISJS50YWlsb3IudjEuR2V0RXhlY3V0b3JFeGVjdXRvclJlcXVlc3QaJi50YWlsb3IudjEuR2V0RXhlY3V0b3JFeGVjdXRvclJlc3BvbnNlIgOQAgESbwoWRGVsZXRlRXhlY3V0b3JFeGVjdXRvchIoLnRhaWxvci52MS5EZWxldGVFeGVjdXRvckV4ZWN1dG9yUmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVFeGVjdXRvckV4ZWN1dG9yUmVzcG9uc2UiABJvChVMaXN0RXhlY3V0b3JFeGVjdXRvcnMSJy50YWlsb3IudjEuTGlzdEV4ZWN1dG9yRXhlY3V0b3JzUmVxdWVzdBooLnRhaWxvci52MS5MaXN0RXhlY3V0b3JFeGVjdXRvcnNSZXNwb25zZSIDkAIBEloKDkdldEV4ZWN1dG9ySm9iEiAudGFpbG9yLnYxLkdldEV4ZWN1dG9ySm9iUmVxdWVzdBohLnRhaWxvci52MS5HZXRFeGVjdXRvckpvYlJlc3BvbnNlIgOQAgESYAoQTGlzdEV4ZWN1dG9ySm9icxIiLnRhaWxvci52MS5MaXN0RXhlY3V0b3JKb2JzUmVxdWVzdBojLnRhaWxvci52MS5MaXN0RXhlY3V0b3JKb2JzUmVzcG9uc2UiA5ACARJ1ChdMaXN0RXhlY3V0b3JKb2JBdHRlbXB0cxIpLnRhaWxvci52MS5MaXN0RXhlY3V0b3JKb2JBdHRlbXB0c1JlcXVlc3QaKi50YWlsb3IudjEuTGlzdEV4ZWN1dG9ySm9iQXR0ZW1wdHNSZXNwb25zZSIDkAIBEoQBChxMaXN0RXhlY3V0b3JJbmNvbWluZ1dlYmhvb2tzEi4udGFpbG9yLnYxLkxpc3RFeGVjdXRvckluY29taW5nV2ViaG9va3NSZXF1ZXN0Gi8udGFpbG9yLnYxLkxpc3RFeGVjdXRvckluY29taW5nV2ViaG9va3NSZXNwb25zZSIDkAIBEn4KGkdldEV4ZWN1dG9ySW5jb21pbmdXZWJob29rEiwudGFpbG9yLnYxLkdldEV4ZWN1dG9ySW5jb21pbmdXZWJob29rUmVxdWVzdBotLnRhaWxvci52MS5HZXRFeGVjdXRvckluY29taW5nV2ViaG9va1Jlc3BvbnNlIgOQAgESWgoPVHJpZ2dlckV4ZWN1dG9yEiEudGFpbG9yLnYxLlRyaWdnZXJFeGVjdXRvclJlcXVlc3QaIi50YWlsb3IudjEuVHJpZ2dlckV4ZWN1dG9yUmVzcG9uc2UiABJ1ChhDcmVhdGVTZWNyZXRNYW5hZ2VyVmF1bHQSKi50YWlsb3IudjEuQ3JlYXRlU2VjcmV0TWFuYWdlclZhdWx0UmVxdWVzdBorLnRhaWxvci52MS5DcmVhdGVTZWNyZXRNYW5hZ2VyVmF1bHRSZXNwb25zZSIAEm8KFUdldFNlY3JldE1hbmFnZXJWYXVsdBInLnRhaWxvci52MS5HZXRTZWNyZXRNYW5hZ2VyVmF1bHRSZXF1ZXN0GigudGFpbG9yLnYxLkdldFNlY3JldE1hbmFnZXJWYXVsdFJlc3BvbnNlIgOQAgESdQoYRGVsZXRlU2VjcmV0TWFuYWdlclZhdWx0EioudGFpbG9yLnYxLkRlbGV0ZVNlY3JldE1hbmFnZXJWYXVsdFJlcXVlc3QaKy50YWlsb3IudjEuRGVsZXRlU2VjcmV0TWFuYWdlclZhdWx0UmVzcG9uc2UiABJ1ChdMaXN0U2VjcmV0TWFuYWdlclZhdWx0cxIpLnRhaWxvci52MS5MaXN0U2VjcmV0TWFuYWdlclZhdWx0c1JlcXVlc3QaKi50YWlsb3IudjEuTGlzdFNlY3JldE1hbmFnZXJWYXVsdHNSZXNwb25zZSIDkAIBEngKGUNyZWF0ZVNlY3JldE1hbmFnZXJTZWNyZXQSKy50YWlsb3IudjEuQ3JlYXRlU2VjcmV0TWFuYWdlclNlY3JldFJlcXVlc3QaLC50YWlsb3IudjEuQ3JlYXRlU2VjcmV0TWFuYWdlclNlY3JldFJlc3BvbnNlIgASeAoZVXBkYXRlU2VjcmV0TWFuYWdlclNlY3JldBIrLnRhaWxvci52MS5VcGRhdGVTZWNyZXRNYW5hZ2VyU2VjcmV0UmVxdWVzdBosLnRhaWxvci52MS5VcGRhdGVTZWNyZXRNYW5hZ2VyU2VjcmV0UmVzcG9uc2UiABJyChZHZXRTZWNyZXRNYW5hZ2VyU2VjcmV0EigudGFpbG9yLnYxLkdldFNlY3JldE1hbmFnZXJTZWNyZXRSZXF1ZXN0GikudGFpbG9yLnYxLkdldFNlY3JldE1hbmFnZXJTZWNyZXRSZXNwb25zZSIDkAIBEngKGURlbGV0ZVNlY3JldE1hbmFnZXJTZWNyZXQSKy50YWlsb3IudjEuRGVsZXRlU2VjcmV0TWFuYWdlclNlY3JldFJlcXVlc3QaLC50YWlsb3IudjEuRGVsZXRlU2VjcmV0TWFuYWdlclNlY3JldFJlc3BvbnNlIgASeAoYTGlzdFNlY3JldE1hbmFnZXJTZWNyZXRzEioudGFpbG9yLnYxLkxpc3RTZWNyZXRNYW5hZ2VyU2VjcmV0c1JlcXVlc3QaKy50YWlsb3IudjEuTGlzdFNlY3JldE1hbmFnZXJTZWNyZXRzUmVzcG9uc2UiA5ACARJgChFDcmVhdGVBdXRoU2VydmljZRIjLnRhaWxvci52MS5DcmVhdGVBdXRoU2VydmljZVJlcXVlc3QaJC50YWlsb3IudjEuQ3JlYXRlQXV0aFNlcnZpY2VSZXNwb25zZSIAEmAKEVVwZGF0ZUF1dGhTZXJ2aWNlEiMudGFpbG9yLnYxLlVwZGF0ZUF1dGhTZXJ2aWNlUmVxdWVzdBokLnRhaWxvci52MS5VcGRhdGVBdXRoU2VydmljZVJlc3BvbnNlIgASYAoRRGVsZXRlQXV0aFNlcnZpY2USIy50YWlsb3IudjEuRGVsZXRlQXV0aFNlcnZpY2VSZXF1ZXN0GiQudGFpbG9yLnYxLkRlbGV0ZUF1dGhTZXJ2aWNlUmVzcG9uc2UiABJaCg5HZXRBdXRoU2VydmljZRIgLnRhaWxvci52MS5HZXRBdXRoU2VydmljZVJlcXVlc3QaIS50YWlsb3IudjEuR2V0QXV0aFNlcnZpY2VSZXNwb25zZSIDkAIBEmAKEExpc3RBdXRoU2VydmljZXMSIi50YWlsb3IudjEuTGlzdEF1dGhTZXJ2aWNlc1JlcXVlc3QaIy50YWlsb3IudjEuTGlzdEF1dGhTZXJ2aWNlc1Jlc3BvbnNlIgOQAgESZgoTQ3JlYXRlQXV0aElEUENvbmZpZxIlLnRhaWxvci52MS5DcmVhdGVBdXRoSURQQ29uZmlnUmVxdWVzdBomLnRhaWxvci52MS5DcmVhdGVBdXRoSURQQ29uZmlnUmVzcG9uc2UiABJmChNVcGRhdGVBdXRoSURQQ29uZmlnEiUudGFpbG9yLnYxLlVwZGF0ZUF1dGhJRFBDb25maWdSZXF1ZXN0GiYudGFpbG9yLnYxLlVwZGF0ZUF1dGhJRFBDb25maWdSZXNwb25zZSIAEmYKE0RlbGV0ZUF1dGhJRFBDb25maWcSJS50YWlsb3IudjEuRGVsZXRlQXV0aElEUENvbmZpZ1JlcXVlc3QaJi50YWlsb3IudjEuRGVsZXRlQXV0aElEUENvbmZpZ1Jlc3BvbnNlIgASYAoQR2V0QXV0aElEUENvbmZpZxIiLnRhaWxvci52MS5HZXRBdXRoSURQQ29uZmlnUmVxdWVzdBojLnRhaWxvci52MS5HZXRBdXRoSURQQ29uZmlnUmVzcG9uc2UiA5ACARJmChJMaXN0QXV0aElEUENvbmZpZ3MSJC50YWlsb3IudjEuTGlzdEF1dGhJRFBDb25maWdzUmVxdWVzdBolLnRhaWxvci52MS5MaXN0QXV0aElEUENvbmZpZ3NSZXNwb25zZSIDkAIBEnIKF0NyZWF0ZVVzZXJQcm9maWxlQ29uZmlnEikudGFpbG9yLnYxLkNyZWF0ZVVzZXJQcm9maWxlQ29uZmlnUmVxdWVzdBoqLnRhaWxvci52MS5DcmVhdGVVc2VyUHJvZmlsZUNvbmZpZ1Jlc3BvbnNlIgAScgoXVXBkYXRlVXNlclByb2ZpbGVDb25maWcSKS50YWlsb3IudjEuVXBkYXRlVXNlclByb2ZpbGVDb25maWdSZXF1ZXN0GioudGFpbG9yLnYxLlVwZGF0ZVVzZXJQcm9maWxlQ29uZmlnUmVzcG9uc2UiABJyChdEZWxldGVVc2VyUHJvZmlsZUNvbmZpZxIpLnRhaWxvci52MS5EZWxldGVVc2VyUHJvZmlsZUNvbmZpZ1JlcXVlc3QaKi50YWlsb3IudjEuRGVsZXRlVXNlclByb2ZpbGVDb25maWdSZXNwb25zZSIAEmwKFEdldFVzZXJQcm9maWxlQ29uZmlnEiYudGFpbG9yLnYxLkdldFVzZXJQcm9maWxlQ29uZmlnUmVxdWVzdBonLnRhaWxvci52MS5HZXRVc2VyUHJvZmlsZUNvbmZpZ1Jlc3BvbnNlIgOQAgESYwoSQ3JlYXRlVGVuYW50Q29uZmlnEiQudGFpbG9yLnYxLkNyZWF0ZVRlbmFudENvbmZpZ1JlcXVlc3QaJS50YWlsb3IudjEuQ3JlYXRlVGVuYW50Q29uZmlnUmVzcG9uc2UiABJjChJVcGRhdGVUZW5hbnRDb25maWcSJC50YWlsb3IudjEuVXBkYXRlVGVuYW50Q29uZmlnUmVxdWVzdBolLnRhaWxvci52MS5VcGRhdGVUZW5hbnRDb25maWdSZXNwb25zZSIAEmMKEkRlbGV0ZVRlbmFudENvbmZpZxIkLnRhaWxvci52MS5EZWxldGVUZW5hbnRDb25maWdSZXF1ZXN0GiUudGFpbG9yLnYxLkRlbGV0ZVRlbmFudENvbmZpZ1Jlc3BvbnNlIgASXQoPR2V0VGVuYW50Q29uZmlnEiEudGFpbG9yLnYxLkdldFRlbmFudENvbmZpZ1JlcXVlc3QaIi50YWlsb3IudjEuR2V0VGVuYW50Q29uZmlnUmVzcG9uc2UiA5ACARJ4ChlDcmVhdGVQZXJzb25hbEFjY2Vzc1Rva2VuEisudGFpbG9yLnYxLkNyZWF0ZVBlcnNvbmFsQWNjZXNzVG9rZW5SZXF1ZXN0GiwudGFpbG9yLnYxLkNyZWF0ZVBlcnNvbmFsQWNjZXNzVG9rZW5SZXNwb25zZSIAEngKGURlbGV0ZVBlcnNvbmFsQWNjZXNzVG9rZW4SKy50YWlsb3IudjEuRGVsZXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlcXVlc3QaLC50YWlsb3IudjEuRGVsZXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlc3BvbnNlIgASeAoYTGlzdFBlcnNvbmFsQWNjZXNzVG9rZW5zEioudGFpbG9yLnYxLkxpc3RQZXJzb25hbEFjY2Vzc1Rva2Vuc1JlcXVlc3QaKy50YWlsb3IudjEuTGlzdFBlcnNvbmFsQWNjZXNzVG9rZW5zUmVzcG9uc2UiA5ACARJsChVDcmVhdGVBdXRoTWFjaGluZVVzZXISJy50YWlsb3IudjEuQ3JlYXRlQXV0aE1hY2hpbmVVc2VyUmVxdWVzdBooLnRhaWxvci52MS5DcmVhdGVBdXRoTWFjaGluZVVzZXJSZXNwb25zZSIAEmwKFVVwZGF0ZUF1dGhNYWNoaW5lVXNlchInLnRhaWxvci52MS5VcGRhdGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0GigudGFpbG9yLnYxLlVwZGF0ZUF1dGhNYWNoaW5lVXNlclJlc3BvbnNlIgASbAoVRGVsZXRlQXV0aE1hY2hpbmVVc2VyEicudGFpbG9yLnYxLkRlbGV0ZUF1dGhNYWNoaW5lVXNlclJlcXVlc3QaKC50YWlsb3IudjEuRGVsZXRlQXV0aE1hY2hpbmVVc2VyUmVzcG9uc2UiABJmChJHZXRBdXRoTWFjaGluZVVzZXISJC50YWlsb3IudjEuR2V0QXV0aE1hY2hpbmVVc2VyUmVxdWVzdBolLnRhaWxvci52MS5HZXRBdXRoTWFjaGluZVVzZXJSZXNwb25zZSIDkAIBEmwKFExpc3RBdXRoTWFjaGluZVVzZXJzEiYudGFpbG9yLnYxLkxpc3RBdXRoTWFjaGluZVVzZXJzUmVxdWVzdBonLnRhaWxvci52MS5MaXN0QXV0aE1hY2hpbmVVc2Vyc1Jlc3BvbnNlIgOQAgESaQoUQ3JlYXRlQXV0aFNDSU1Db25maWcSJi50YWlsb3IudjEuQ3JlYXRlQXV0aFNDSU1Db25maWdSZXF1ZXN0GicudGFpbG9yLnYxLkNyZWF0ZUF1dGhTQ0lNQ29uZmlnUmVzcG9uc2UiABJpChRVcGRhdGVBdXRoU0NJTUNvbmZpZxImLnRhaWxvci52MS5VcGRhdGVBdXRoU0NJTUNvbmZpZ1JlcXVlc3QaJy50YWlsb3IudjEuVXBkYXRlQXV0aFNDSU1Db25maWdSZXNwb25zZSIAEmkKFERlbGV0ZUF1dGhTQ0lNQ29uZmlnEiYudGFpbG9yLnYxLkRlbGV0ZUF1dGhTQ0lNQ29uZmlnUmVxdWVzdBonLnRhaWxvci52MS5EZWxldGVBdXRoU0NJTUNvbmZpZ1Jlc3BvbnNlIgASYwoRR2V0QXV0aFNDSU1Db25maWcSIy50YWlsb3IudjEuR2V0QXV0aFNDSU1Db25maWdSZXF1ZXN0GiQudGFpbG9yLnYxLkdldEF1dGhTQ0lNQ29uZmlnUmVzcG9uc2UiA5ACARJvChZDcmVhdGVBdXRoU0NJTVJlc291cmNlEigudGFpbG9yLnYxLkNyZWF0ZUF1dGhTQ0lNUmVzb3VyY2VSZXF1ZXN0GikudGFpbG9yLnYxLkNyZWF0ZUF1dGhTQ0lNUmVzb3VyY2VSZXNwb25zZSIAEm8KFlVwZGF0ZUF1dGhTQ0lNUmVzb3VyY2USKC50YWlsb3IudjEuVXBkYXRlQXV0aFNDSU1SZXNvdXJjZVJlcXVlc3QaKS50YWlsb3IudjEuVXBkYXRlQXV0aFNDSU1SZXNvdXJjZVJlc3BvbnNlIgASbwoWRGVsZXRlQXV0aFNDSU1SZXNvdXJjZRIoLnRhaWxvci52MS5EZWxldGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVBdXRoU0NJTVJlc291cmNlUmVzcG9uc2UiABJpChNHZXRBdXRoU0NJTVJlc291cmNlEiUudGFpbG9yLnYxLkdldEF1dGhTQ0lNUmVzb3VyY2VSZXF1ZXN0GiYudGFpbG9yLnYxLkdldEF1dGhTQ0lNUmVzb3VyY2VSZXNwb25zZSIDkAIBEmwKFEdldEF1dGhTQ0lNUmVzb3VyY2VzEiYudGFpbG9yLnYxLkdldEF1dGhTQ0lNUmVzb3VyY2VzUmVxdWVzdBonLnRhaWxvci52MS5HZXRBdXRoU0NJTVJlc291cmNlc1Jlc3BvbnNlIgOQAgESaQoUQ3JlYXRlQXV0aENvbm5lY3Rpb24SJi50YWlsb3IudjEuQ3JlYXRlQXV0aENvbm5lY3Rpb25SZXF1ZXN0GicudGFpbG9yLnYxLkNyZWF0ZUF1dGhDb25uZWN0aW9uUmVzcG9uc2UiABJpChNMaXN0QXV0aENvbm5lY3Rpb25zEiUudGFpbG9yLnYxLkxpc3RBdXRoQ29ubmVjdGlvbnNSZXF1ZXN0GiYudGFpbG9yLnYxLkxpc3RBdXRoQ29ubmVjdGlvbnNSZXNwb25zZSIDkAIBEmkKFFJldm9rZUF1dGhDb25uZWN0aW9uEiYudGFpbG9yLnYxLlJldm9rZUF1dGhDb25uZWN0aW9uUmVxdWVzdBonLnRhaWxvci52MS5SZXZva2VBdXRoQ29ubmVjdGlvblJlc3BvbnNlIgAShAEKHVJlZ2lzdGVyQXV0aENvbm5lY3Rpb25TZXNzaW9uEi8udGFpbG9yLnYxLlJlZ2lzdGVyQXV0aENvbm5lY3Rpb25TZXNzaW9uUmVxdWVzdBowLnRhaWxvci52MS5SZWdpc3RlckF1dGhDb25uZWN0aW9uU2Vzc2lvblJlc3BvbnNlIgASogEKJ0V4Y2hhbmdlQXV0aENvbm5lY3Rpb25BdXRob3JpemF0aW9uQ29kZRI5LnRhaWxvci52MS5FeGNoYW5nZUF1dGhDb25uZWN0aW9uQXV0aG9yaXphdGlvbkNvZGVSZXF1ZXN0GjoudGFpbG9yLnYxLkV4Y2hhbmdlQXV0aENvbm5lY3Rpb25BdXRob3JpemF0aW9uQ29kZVJlc3BvbnNlIgASbwoWQ3JlYXRlQXV0aE9BdXRoMkNsaWVudBIoLnRhaWxvci52MS5DcmVhdGVBdXRoT0F1dGgyQ2xpZW50UmVxdWVzdBopLnRhaWxvci52MS5DcmVhdGVBdXRoT0F1dGgyQ2xpZW50UmVzcG9uc2UiABJvChZVcGRhdGVBdXRoT0F1dGgyQ2xpZW50EigudGFpbG9yLnYxLlVwZGF0ZUF1dGhPQXV0aDJDbGllbnRSZXF1ZXN0GikudGFpbG9yLnYxLlVwZGF0ZUF1dGhPQXV0aDJDbGllbnRSZXNwb25zZSIAEm8KFkRlbGV0ZUF1dGhPQXV0aDJDbGllbnQSKC50YWlsb3IudjEuRGVsZXRlQXV0aE9BdXRoMkNsaWVudFJlcXVlc3QaKS50YWlsb3IudjEuRGVsZXRlQXV0aE9BdXRoMkNsaWVudFJlc3BvbnNlIgASaQoTR2V0QXV0aE9BdXRoMkNsaWVudBIlLnRhaWxvci52MS5HZXRBdXRoT0F1dGgyQ2xpZW50UmVxdWVzdBomLnRhaWxvci52MS5HZXRBdXRoT0F1dGgyQ2xpZW50UmVzcG9uc2UiA5ACARJvChVMaXN0QXV0aE9BdXRoMkNsaWVudHMSJy50YWlsb3IudjEuTGlzdEF1dGhPQXV0aDJDbGllbnRzUmVxdWVzdBooLnRhaWxvci52MS5MaXN0QXV0aE9BdXRoMkNsaWVudHNSZXNwb25zZSIDkAIBEmkKE0xpc3REYXRhcGxhbmVFdmVudHMSJS50YWlsb3IudjEuTGlzdERhdGFwbGFuZUV2ZW50c1JlcXVlc3QaJi50YWlsb3IudjEuTGlzdERhdGFwbGFuZUV2ZW50c1Jlc3BvbnNlIgOQAgEShAEKHExpc3RDb250cm9scGxhbmVBY3Rpdml0eUxvZ3MSLi50YWlsb3IudjEuTGlzdENvbnRyb2xwbGFuZUFjdGl2aXR5TG9nc1JlcXVlc3QaLy50YWlsb3IudjEuTGlzdENvbnRyb2xwbGFuZUFjdGl2aXR5TG9nc1Jlc3BvbnNlIgOQAgESVwoOVGVzdEV4ZWNTY3JpcHQSIC50YWlsb3IudjEuVGVzdEV4ZWNTY3JpcHRSZXF1ZXN0GiEudGFpbG9yLnYxLlRlc3RFeGVjU2NyaXB0UmVzcG9uc2UiABJsChRHZXRGdW5jdGlvbkV4ZWN1dGlvbhImLnRhaWxvci52MS5HZXRGdW5jdGlvbkV4ZWN1dGlvblJlcXVlc3QaJy50YWlsb3IudjEuR2V0RnVuY3Rpb25FeGVjdXRpb25SZXNwb25zZSIDkAIBEnIKFkxpc3RGdW5jdGlvbkV4ZWN1dGlvbnMSKC50YWlsb3IudjEuTGlzdEZ1bmN0aW9uRXhlY3V0aW9uc1JlcXVlc3QaKS50YWlsb3IudjEuTGlzdEZ1bmN0aW9uRXhlY3V0aW9uc1Jlc3BvbnNlIgOQAgEScQoWQ3JlYXRlRnVuY3Rpb25SZWdpc3RyeRIoLnRhaWxvci52MS5DcmVhdGVGdW5jdGlvblJlZ2lzdHJ5UmVxdWVzdBopLnRhaWxvci52MS5DcmVhdGVGdW5jdGlvblJlZ2lzdHJ5UmVzcG9uc2UiACgBEnEKFlVwZGF0ZUZ1bmN0aW9uUmVnaXN0cnkSKC50YWlsb3IudjEuVXBkYXRlRnVuY3Rpb25SZWdpc3RyeVJlcXVlc3QaKS50YWlsb3IudjEuVXBkYXRlRnVuY3Rpb25SZWdpc3RyeVJlc3BvbnNlIgAoARJpChNHZXRGdW5jdGlvblJlZ2lzdHJ5EiUudGFpbG9yLnYxLkdldEZ1bmN0aW9uUmVnaXN0cnlSZXF1ZXN0GiYudGFpbG9yLnYxLkdldEZ1bmN0aW9uUmVnaXN0cnlSZXNwb25zZSIDkAIBEnIKFkxpc3RGdW5jdGlvblJlZ2lzdHJpZXMSKC50YWlsb3IudjEuTGlzdEZ1bmN0aW9uUmVnaXN0cmllc1JlcXVlc3QaKS50YWlsb3IudjEuTGlzdEZ1bmN0aW9uUmVnaXN0cmllc1Jlc3BvbnNlIgOQAgESbwoWRGVsZXRlRnVuY3Rpb25SZWdpc3RyeRIoLnRhaWxvci52MS5EZWxldGVGdW5jdGlvblJlZ2lzdHJ5UmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVGdW5jdGlvblJlZ2lzdHJ5UmVzcG9uc2UiABKMAQoeRG93bmxvYWRGdW5jdGlvblJlZ2lzdHJ5U2NyaXB0EjAudGFpbG9yLnYxLkRvd25sb2FkRnVuY3Rpb25SZWdpc3RyeVNjcmlwdFJlcXVlc3QaMS50YWlsb3IudjEuRG93bmxvYWRGdW5jdGlvblJlZ2lzdHJ5U2NyaXB0UmVzcG9uc2UiA5ACATABEnIKFkxpc3RNZXRlclJlcXVlc3RDb3VudHMSKC50YWlsb3IudjEuTGlzdE1ldGVyUmVxdWVzdENvdW50c1JlcXVlc3QaKS50YWlsb3IudjEuTGlzdE1ldGVyUmVxdWVzdENvdW50c1Jlc3BvbnNlIgOQAgESeAoYTGlzdE1ldGVyRXhlY3V0aW9uQ291bnRzEioudGFpbG9yLnYxLkxpc3RNZXRlckV4ZWN1dGlvbkNvdW50c1JlcXVlc3QaKy50YWlsb3IudjEuTGlzdE1ldGVyRXhlY3V0aW9uQ291bnRzUmVzcG9uc2UiA5ACARJsChRMaXN0TWV0ZXJFdmVudENvdW50cxImLnRhaWxvci52MS5MaXN0TWV0ZXJFdmVudENvdW50c1JlcXVlc3QaJy50YWlsb3IudjEuTGlzdE1ldGVyRXZlbnRDb3VudHNSZXNwb25zZSIDkAIBEl0KD0xpc3RJZFBTZXJ2aWNlcxIhLnRhaWxvci52MS5MaXN0SWRQU2VydmljZXNSZXF1ZXN0GiIudGFpbG9yLnYxLkxpc3RJZFBTZXJ2aWNlc1Jlc3BvbnNlIgOQAgESXQoQQ3JlYXRlSWRQU2VydmljZRIiLnRhaWxvci52MS5DcmVhdGVJZFBTZXJ2aWNlUmVxdWVzdBojLnRhaWxvci52MS5DcmVhdGVJZFBTZXJ2aWNlUmVzcG9uc2UiABJdChBVcGRhdGVJZFBTZXJ2aWNlEiIudGFpbG9yLnYxLlVwZGF0ZUlkUFNlcnZpY2VSZXF1ZXN0GiMudGFpbG9yLnYxLlVwZGF0ZUlkUFNlcnZpY2VSZXNwb25zZSIAEl0KEERlbGV0ZUlkUFNlcnZpY2USIi50YWlsb3IudjEuRGVsZXRlSWRQU2VydmljZVJlcXVlc3QaIy50YWlsb3IudjEuRGVsZXRlSWRQU2VydmljZVJlc3BvbnNlIgASVwoNR2V0SWRQU2VydmljZRIfLnRhaWxvci52MS5HZXRJZFBTZXJ2aWNlUmVxdWVzdBogLnRhaWxvci52MS5HZXRJZFBTZXJ2aWNlUmVzcG9uc2UiA5ACARJaCg5MaXN0SWRQQ2xpZW50cxIgLnRhaWxvci52MS5MaXN0SWRQQ2xpZW50c1JlcXVlc3QaIS50YWlsb3IudjEuTGlzdElkUENsaWVudHNSZXNwb25zZSIDkAIBEloKD0NyZWF0ZUlkUENsaWVudBIhLnRhaWxvci52MS5DcmVhdGVJZFBDbGllbnRSZXF1ZXN0GiIudGFpbG9yLnYxLkNyZWF0ZUlkUENsaWVudFJlc3BvbnNlIgASWgoPRGVsZXRlSWRQQ2xpZW50EiEudGFpbG9yLnYxLkRlbGV0ZUlkUENsaWVudFJlcXVlc3QaIi50YWlsb3IudjEuRGVsZXRlSWRQQ2xpZW50UmVzcG9uc2UiABJUCgxHZXRJZFBDbGllbnQSHi50YWlsb3IudjEuR2V0SWRQQ2xpZW50UmVxdWVzdBofLnRhaWxvci52MS5HZXRJZFBDbGllbnRSZXNwb25zZSIDkAIBEmYKE0NyZWF0ZVN0YXRpY1dlYnNpdGUSJS50YWlsb3IudjEuQ3JlYXRlU3RhdGljV2Vic2l0ZVJlcXVlc3QaJi50YWlsb3IudjEuQ3JlYXRlU3RhdGljV2Vic2l0ZVJlc3BvbnNlIgASZgoTVXBkYXRlU3RhdGljV2Vic2l0ZRIlLnRhaWxvci52MS5VcGRhdGVTdGF0aWNXZWJzaXRlUmVxdWVzdBomLnRhaWxvci52MS5VcGRhdGVTdGF0aWNXZWJzaXRlUmVzcG9uc2UiABJmChNEZWxldGVTdGF0aWNXZWJzaXRlEiUudGFpbG9yLnYxLkRlbGV0ZVN0YXRpY1dlYnNpdGVSZXF1ZXN0GiYudGFpbG9yLnYxLkRlbGV0ZVN0YXRpY1dlYnNpdGVSZXNwb25zZSIAEmAKEEdldFN0YXRpY1dlYnNpdGUSIi50YWlsb3IudjEuR2V0U3RhdGljV2Vic2l0ZVJlcXVlc3QaIy50YWlsb3IudjEuR2V0U3RhdGljV2Vic2l0ZVJlc3BvbnNlIgOQAgESZgoSTGlzdFN0YXRpY1dlYnNpdGVzEiQudGFpbG9yLnYxLkxpc3RTdGF0aWNXZWJzaXRlc1JlcXVlc3QaJS50YWlsb3IudjEuTGlzdFN0YXRpY1dlYnNpdGVzUmVzcG9uc2UiA5ACARJdChBDcmVhdGVEZXBsb3ltZW50EiIudGFpbG9yLnYxLkNyZWF0ZURlcGxveW1lbnRSZXF1ZXN0GiMudGFpbG9yLnYxLkNyZWF0ZURlcGxveW1lbnRSZXNwb25zZSIAEk0KClVwbG9hZEZpbGUSHC50YWlsb3IudjEuVXBsb2FkRmlsZVJlcXVlc3QaHS50YWlsb3IudjEuVXBsb2FkRmlsZVJlc3BvbnNlIgAoARJgChFQdWJsaXNoRGVwbG95bWVudBIjLnRhaWxvci52MS5QdWJsaXNoRGVwbG95bWVudFJlcXVlc3QaJC50YWlsb3IudjEuUHVibGlzaERlcGxveW1lbnRSZXNwb25zZSIAElcKDkNyZWF0ZVdvcmtmbG93EiAudGFpbG9yLnYxLkNyZWF0ZVdvcmtmbG93UmVxdWVzdBohLnRhaWxvci52MS5DcmVhdGVXb3JrZmxvd1Jlc3BvbnNlIgASVwoOVXBkYXRlV29ya2Zsb3cSIC50YWlsb3IudjEuVXBkYXRlV29ya2Zsb3dSZXF1ZXN0GiEudGFpbG9yLnYxLlVwZGF0ZVdvcmtmbG93UmVzcG9uc2UiABJXCg5EZWxldGVXb3JrZmxvdxIgLnRhaWxvci52MS5EZWxldGVXb3JrZmxvd1JlcXVlc3QaIS50YWlsb3IudjEuRGVsZXRlV29ya2Zsb3dSZXNwb25zZSIAElEKC0dldFdvcmtmbG93Eh0udGFpbG9yLnYxLkdldFdvcmtmbG93UmVxdWVzdBoeLnRhaWxvci52MS5HZXRXb3JrZmxvd1Jlc3BvbnNlIgOQAgESYwoRR2V0V29ya2Zsb3dCeU5hbWUSIy50YWlsb3IudjEuR2V0V29ya2Zsb3dCeU5hbWVSZXF1ZXN0GiQudGFpbG9yLnYxLkdldFdvcmtmbG93QnlOYW1lUmVzcG9uc2UiA5ACARJXCg1MaXN0V29ya2Zsb3dzEh8udGFpbG9yLnYxLkxpc3RXb3JrZmxvd3NSZXF1ZXN0GiAudGFpbG9yLnYxLkxpc3RXb3JrZmxvd3NSZXNwb25zZSIDkAIBEngKGUNyZWF0ZVdvcmtmbG93Sm9iRnVuY3Rpb24SKy50YWlsb3IudjEuQ3JlYXRlV29ya2Zsb3dKb2JGdW5jdGlvblJlcXVlc3QaLC50YWlsb3IudjEuQ3JlYXRlV29ya2Zsb3dKb2JGdW5jdGlvblJlc3BvbnNlIgASeAoZVXBkYXRlV29ya2Zsb3dKb2JGdW5jdGlvbhIrLnRhaWxvci52MS5VcGRhdGVXb3JrZmxvd0pvYkZ1bmN0aW9uUmVxdWVzdBosLnRhaWxvci52MS5VcGRhdGVXb3JrZmxvd0pvYkZ1bmN0aW9uUmVzcG9uc2UiABJyChZHZXRXb3JrZmxvd0pvYkZ1bmN0aW9uEigudGFpbG9yLnYxLkdldFdvcmtmbG93Sm9iRnVuY3Rpb25SZXF1ZXN0GikudGFpbG9yLnYxLkdldFdvcmtmbG93Sm9iRnVuY3Rpb25SZXNwb25zZSIDkAIBEoQBChxHZXRXb3JrZmxvd0pvYkZ1bmN0aW9uQnlOYW1lEi4udGFpbG9yLnYxLkdldFdvcmtmbG93Sm9iRnVuY3Rpb25CeU5hbWVSZXF1ZXN0Gi8udGFpbG9yLnYxLkdldFdvcmtmbG93Sm9iRnVuY3Rpb25CeU5hbWVSZXNwb25zZSIDkAIBEngKGExpc3RXb3JrZmxvd0pvYkZ1bmN0aW9ucxIqLnRhaWxvci52MS5MaXN0V29ya2Zsb3dKb2JGdW5jdGlvbnNSZXF1ZXN0GisudGFpbG9yLnYxLkxpc3RXb3JrZmxvd0pvYkZ1bmN0aW9uc1Jlc3BvbnNlIgOQAgESbAoUR2V0V29ya2Zsb3dFeGVjdXRpb24SJi50YWlsb3IudjEuR2V0V29ya2Zsb3dFeGVjdXRpb25SZXF1ZXN0GicudGFpbG9yLnYxLkdldFdvcmtmbG93RXhlY3V0aW9uUmVzcG9uc2UiA5ACARJyChZMaXN0V29ya2Zsb3dFeGVjdXRpb25zEigudGFpbG9yLnYxLkxpc3RXb3JrZmxvd0V4ZWN1dGlvbnNSZXF1ZXN0GikudGFpbG9yLnYxLkxpc3RXb3JrZmxvd0V4ZWN1dGlvbnNSZXNwb25zZSIDkAIBEmAKEVRlc3RTdGFydFdvcmtmbG93EiMudGFpbG9yLnYxLlRlc3RTdGFydFdvcmtmbG93UmVxdWVzdBokLnRhaWxvci52MS5UZXN0U3RhcnRXb3JrZmxvd1Jlc3BvbnNlIgASYwoSVGVzdFJlc3VtZVdvcmtmbG93EiQudGFpbG9yLnYxLlRlc3RSZXN1bWVXb3JrZmxvd1JlcXVlc3QaJS50YWlsb3IudjEuVGVzdFJlc3VtZVdvcmtmbG93UmVzcG9uc2UiABJOCgtTZXRNZXRhZGF0YRIdLnRhaWxvci52MS5TZXRNZXRhZGF0YVJlcXVlc3QaHi50YWlsb3IudjEuU2V0TWV0YWRhdGFSZXNwb25zZSIAElEKC0dldE1ldGFkYXRhEh0udGFpbG9yLnYxLkdldE1ldGFkYXRhUmVxdWVzdBoeLnRhaWxvci52MS5HZXRNZXRhZGF0YVJlc3BvbnNlIgOQAgEShAEKHUNyZWF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyEi8udGFpbG9yLnYxLkNyZWF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVxdWVzdBowLnRhaWxvci52MS5DcmVhdGVDb250cm9scGxhbmVNYWNoaW5lVXNlclJlc3BvbnNlIgAShAEKHVVwZGF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyEi8udGFpbG9yLnYxLlVwZGF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVxdWVzdBowLnRhaWxvci52MS5VcGRhdGVDb250cm9scGxhbmVNYWNoaW5lVXNlclJlc3BvbnNlIgASfgoaR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXISLC50YWlsb3IudjEuR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXF1ZXN0Gi0udGFpbG9yLnYxLkdldENvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVzcG9uc2UiA5ACARKQAQogR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJCeU5hbWUSMi50YWlsb3IudjEuR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJCeU5hbWVSZXF1ZXN0GjMudGFpbG9yLnYxLkdldENvbnRyb2xwbGFuZU1hY2hpbmVVc2VyQnlOYW1lUmVzcG9uc2UiA5ACARKEAQocTGlzdENvbnRyb2xwbGFuZU1hY2hpbmVVc2VycxIuLnRhaWxvci52MS5MaXN0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJzUmVxdWVzdBovLnRhaWxvci52MS5MaXN0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJzUmVzcG9uc2UiA5ACARKEAQodRGVsZXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXISLy50YWlsb3IudjEuRGVsZXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXF1ZXN0GjAudGFpbG9yLnYxLkRlbGV0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVzcG9uc2UiABJsChVDcmVhdGVUZWxlbWV0cnlFeHBvcnQSJy50YWlsb3IudjEuQ3JlYXRlVGVsZW1ldHJ5RXhwb3J0UmVxdWVzdBooLnRhaWxvci52MS5DcmVhdGVUZWxlbWV0cnlFeHBvcnRSZXNwb25zZSIAEmwKFVVwZGF0ZVRlbGVtZXRyeUV4cG9ydBInLnRhaWxvci52MS5VcGRhdGVUZWxlbWV0cnlFeHBvcnRSZXF1ZXN0GigudGFpbG9yLnYxLlVwZGF0ZVRlbGVtZXRyeUV4cG9ydFJlc3BvbnNlIgASZgoSR2V0VGVsZW1ldHJ5RXhwb3J0EiQudGFpbG9yLnYxLkdldFRlbGVtZXRyeUV4cG9ydFJlcXVlc3QaJS50YWlsb3IudjEuR2V0VGVsZW1ldHJ5RXhwb3J0UmVzcG9uc2UiA5ACARJsChRMaXN0VGVsZW1ldHJ5RXhwb3J0cxImLnRhaWxvci52MS5MaXN0VGVsZW1ldHJ5RXhwb3J0c1JlcXVlc3QaJy50YWlsb3IudjEuTGlzdFRlbGVtZXRyeUV4cG9ydHNSZXNwb25zZSIDkAIBEmwKFURlbGV0ZVRlbGVtZXRyeUV4cG9ydBInLnRhaWxvci52MS5EZWxldGVUZWxlbWV0cnlFeHBvcnRSZXF1ZXN0GigudGFpbG9yLnYxLkRlbGV0ZVRlbGVtZXRyeUV4cG9ydFJlc3BvbnNlIgASZgoTVGVzdFRlbGVtZXRyeUV4cG9ydBIlLnRhaWxvci52MS5UZXN0VGVsZW1ldHJ5RXhwb3J0UmVxdWVzdBomLnRhaWxvci52MS5UZXN0VGVsZW1ldHJ5RXhwb3J0UmVzcG9uc2UiAGIGcHJvdG8z", [
866
+ const file_tailor_v1_service = /* @__PURE__ */ fileDesc("Chd0YWlsb3IvdjEvc2VydmljZS5wcm90bxIJdGFpbG9yLnYxIg0KC1BpbmdSZXF1ZXN0Ig4KDFBpbmdSZXNwb25zZTL7vAEKD09wZXJhdG9yU2VydmljZRI5CgRQaW5nEhYudGFpbG9yLnYxLlBpbmdSZXF1ZXN0GhcudGFpbG9yLnYxLlBpbmdSZXNwb25zZSIAEocBCh1MaXN0QXZhaWxhYmxlV29ya3NwYWNlUmVnaW9ucxIvLnRhaWxvci52MS5MaXN0QXZhaWxhYmxlV29ya3NwYWNlUmVnaW9uc1JlcXVlc3QaMC50YWlsb3IudjEuTGlzdEF2YWlsYWJsZVdvcmtzcGFjZVJlZ2lvbnNSZXNwb25zZSIDkAIBEloKD0NyZWF0ZVdvcmtzcGFjZRIhLnRhaWxvci52MS5DcmVhdGVXb3Jrc3BhY2VSZXF1ZXN0GiIudGFpbG9yLnYxLkNyZWF0ZVdvcmtzcGFjZVJlc3BvbnNlIgASWgoPVXBkYXRlV29ya3NwYWNlEiEudGFpbG9yLnYxLlVwZGF0ZVdvcmtzcGFjZVJlcXVlc3QaIi50YWlsb3IudjEuVXBkYXRlV29ya3NwYWNlUmVzcG9uc2UiABJaCg9EZWxldGVXb3Jrc3BhY2USIS50YWlsb3IudjEuRGVsZXRlV29ya3NwYWNlUmVxdWVzdBoiLnRhaWxvci52MS5EZWxldGVXb3Jrc3BhY2VSZXNwb25zZSIAEloKDkxpc3RXb3Jrc3BhY2VzEiAudGFpbG9yLnYxLkxpc3RXb3Jrc3BhY2VzUmVxdWVzdBohLnRhaWxvci52MS5MaXN0V29ya3NwYWNlc1Jlc3BvbnNlIgOQAgESfgoaTGlzdE9yZ2FuaXphdGlvbldvcmtzcGFjZXMSLC50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbldvcmtzcGFjZXNSZXF1ZXN0Gi0udGFpbG9yLnYxLkxpc3RPcmdhbml6YXRpb25Xb3Jrc3BhY2VzUmVzcG9uc2UiA5ACARJdChBSZXN0b3JlV29ya3NwYWNlEiIudGFpbG9yLnYxLlJlc3RvcmVXb3Jrc3BhY2VSZXF1ZXN0GiMudGFpbG9yLnYxLlJlc3RvcmVXb3Jrc3BhY2VSZXNwb25zZSIAElQKDEdldFdvcmtzcGFjZRIeLnRhaWxvci52MS5HZXRXb3Jrc3BhY2VSZXF1ZXN0Gh8udGFpbG9yLnYxLkdldFdvcmtzcGFjZVJlc3BvbnNlIgOQAgESfgoaTGlzdFdvcmtzcGFjZVBsYXRmb3JtVXNlcnMSLC50YWlsb3IudjEuTGlzdFdvcmtzcGFjZVBsYXRmb3JtVXNlcnNSZXF1ZXN0Gi0udGFpbG9yLnYxLkxpc3RXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJzUmVzcG9uc2UiA5ACARKlAQonTGlzdEF2YWlsYWJsZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJvbGVzEjkudGFpbG9yLnYxLkxpc3RBdmFpbGFibGVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSb2xlc1JlcXVlc3QaOi50YWlsb3IudjEuTGlzdEF2YWlsYWJsZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJvbGVzUmVzcG9uc2UiA5ACARJ+ChtJbnZpdGVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXISLS50YWlsb3IudjEuSW52aXRlV29ya3NwYWNlUGxhdGZvcm1Vc2VyUmVxdWVzdBouLnRhaWxvci52MS5JbnZpdGVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSZXNwb25zZSIAEn4KG1JlbW92ZVdvcmtzcGFjZVBsYXRmb3JtVXNlchItLnRhaWxvci52MS5SZW1vdmVXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSZXF1ZXN0Gi4udGFpbG9yLnYxLlJlbW92ZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJlc3BvbnNlIgASfgobVXBkYXRlV29ya3NwYWNlUGxhdGZvcm1Vc2VyEi0udGFpbG9yLnYxLlVwZGF0ZVdvcmtzcGFjZVBsYXRmb3JtVXNlclJlcXVlc3QaLi50YWlsb3IudjEuVXBkYXRlV29ya3NwYWNlUGxhdGZvcm1Vc2VyUmVzcG9uc2UiABJ4ChhHZXRXb3Jrc3BhY2VQbGF0Zm9ybVVzZXISKi50YWlsb3IudjEuR2V0V29ya3NwYWNlUGxhdGZvcm1Vc2VyUmVxdWVzdBorLnRhaWxvci52MS5HZXRXb3Jrc3BhY2VQbGF0Zm9ybVVzZXJSZXNwb25zZSIDkAIBEmAKEEdldFdvcmtzcGFjZVJvbGUSIi50YWlsb3IudjEuR2V0V29ya3NwYWNlUm9sZVJlcXVlc3QaIy50YWlsb3IudjEuR2V0V29ya3NwYWNlUm9sZVJlc3BvbnNlIgOQAgESYwoSVXBkYXRlT3JnYW5pemF0aW9uEiQudGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvblJlcXVlc3QaJS50YWlsb3IudjEuVXBkYXRlT3JnYW5pemF0aW9uUmVzcG9uc2UiABJdCg9HZXRPcmdhbml6YXRpb24SIS50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uUmVxdWVzdBoiLnRhaWxvci52MS5HZXRPcmdhbml6YXRpb25SZXNwb25zZSIDkAIBEmMKEUxpc3RPcmdhbml6YXRpb25zEiMudGFpbG9yLnYxLkxpc3RPcmdhbml6YXRpb25zUmVxdWVzdBokLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uc1Jlc3BvbnNlIgOQAgESbwoVTGlzdFVzZXJPcmdhbml6YXRpb25zEicudGFpbG9yLnYxLkxpc3RVc2VyT3JnYW5pemF0aW9uc1JlcXVlc3QaKC50YWlsb3IudjEuTGlzdFVzZXJPcmdhbml6YXRpb25zUmVzcG9uc2UiA5ACARJyChdHcmFudE9yZ2FuaXphdGlvbkFjY2VzcxIpLnRhaWxvci52MS5HcmFudE9yZ2FuaXphdGlvbkFjY2Vzc1JlcXVlc3QaKi50YWlsb3IudjEuR3JhbnRPcmdhbml6YXRpb25BY2Nlc3NSZXNwb25zZSIAEnUKGFVwZGF0ZU9yZ2FuaXphdGlvbkFjY2VzcxIqLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25BY2Nlc3NSZXF1ZXN0GisudGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvbkFjY2Vzc1Jlc3BvbnNlIgASdQoYUmV2b2tlT3JnYW5pemF0aW9uQWNjZXNzEioudGFpbG9yLnYxLlJldm9rZU9yZ2FuaXphdGlvbkFjY2Vzc1JlcXVlc3QaKy50YWlsb3IudjEuUmV2b2tlT3JnYW5pemF0aW9uQWNjZXNzUmVzcG9uc2UiABJ4ChhMaXN0T3JnYW5pemF0aW9uQWNjZXNzZXMSKi50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbkFjY2Vzc2VzUmVxdWVzdBorLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uQWNjZXNzZXNSZXNwb25zZSIDkAIBEm8KFUdldE9yZ2FuaXphdGlvbkFjY2VzcxInLnRhaWxvci52MS5HZXRPcmdhbml6YXRpb25BY2Nlc3NSZXF1ZXN0GigudGFpbG9yLnYxLkdldE9yZ2FuaXphdGlvbkFjY2Vzc1Jlc3BvbnNlIgOQAgESdQoYQ3JlYXRlT3JnYW5pemF0aW9uRm9sZGVyEioudGFpbG9yLnYxLkNyZWF0ZU9yZ2FuaXphdGlvbkZvbGRlclJlcXVlc3QaKy50YWlsb3IudjEuQ3JlYXRlT3JnYW5pemF0aW9uRm9sZGVyUmVzcG9uc2UiABJ1ChhVcGRhdGVPcmdhbml6YXRpb25Gb2xkZXISKi50YWlsb3IudjEuVXBkYXRlT3JnYW5pemF0aW9uRm9sZGVyUmVxdWVzdBorLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25Gb2xkZXJSZXNwb25zZSIAEnUKGERlbGV0ZU9yZ2FuaXphdGlvbkZvbGRlchIqLnRhaWxvci52MS5EZWxldGVPcmdhbml6YXRpb25Gb2xkZXJSZXF1ZXN0GisudGFpbG9yLnYxLkRlbGV0ZU9yZ2FuaXphdGlvbkZvbGRlclJlc3BvbnNlIgASbwoVR2V0T3JnYW5pemF0aW9uRm9sZGVyEicudGFpbG9yLnYxLkdldE9yZ2FuaXphdGlvbkZvbGRlclJlcXVlc3QaKC50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uRm9sZGVyUmVzcG9uc2UiA5ACARJ1ChdMaXN0T3JnYW5pemF0aW9uRm9sZGVycxIpLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uRm9sZGVyc1JlcXVlc3QaKi50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbkZvbGRlcnNSZXNwb25zZSIDkAIBEoQBCh1HcmFudE9yZ2FuaXphdGlvbkZvbGRlckFjY2VzcxIvLnRhaWxvci52MS5HcmFudE9yZ2FuaXphdGlvbkZvbGRlckFjY2Vzc1JlcXVlc3QaMC50YWlsb3IudjEuR3JhbnRPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIAEocBCh5VcGRhdGVPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3MSMC50YWlsb3IudjEuVXBkYXRlT3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzUmVxdWVzdBoxLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIAEocBCh5SZXZva2VPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3MSMC50YWlsb3IudjEuUmV2b2tlT3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzUmVxdWVzdBoxLnRhaWxvci52MS5SZXZva2VPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIAEooBCh5MaXN0T3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzZXMSMC50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvbkZvbGRlckFjY2Vzc2VzUmVxdWVzdBoxLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzZXNSZXNwb25zZSIDkAIBEoEBChtHZXRPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3MSLS50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uRm9sZGVyQWNjZXNzUmVxdWVzdBouLnRhaWxvci52MS5HZXRPcmdhbml6YXRpb25Gb2xkZXJBY2Nlc3NSZXNwb25zZSIDkAIBEm8KFkNyZWF0ZU9yZ2FuaXphdGlvblRlYW0SKC50YWlsb3IudjEuQ3JlYXRlT3JnYW5pemF0aW9uVGVhbVJlcXVlc3QaKS50YWlsb3IudjEuQ3JlYXRlT3JnYW5pemF0aW9uVGVhbVJlc3BvbnNlIgASbwoWVXBkYXRlT3JnYW5pemF0aW9uVGVhbRIoLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25UZWFtUmVxdWVzdBopLnRhaWxvci52MS5VcGRhdGVPcmdhbml6YXRpb25UZWFtUmVzcG9uc2UiABJvChZEZWxldGVPcmdhbml6YXRpb25UZWFtEigudGFpbG9yLnYxLkRlbGV0ZU9yZ2FuaXphdGlvblRlYW1SZXF1ZXN0GikudGFpbG9yLnYxLkRlbGV0ZU9yZ2FuaXphdGlvblRlYW1SZXNwb25zZSIAEmkKE0dldE9yZ2FuaXphdGlvblRlYW0SJS50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbVJlcXVlc3QaJi50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbVJlc3BvbnNlIgOQAgESbwoVTGlzdE9yZ2FuaXphdGlvblRlYW1zEicudGFpbG9yLnYxLkxpc3RPcmdhbml6YXRpb25UZWFtc1JlcXVlc3QaKC50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvblRlYW1zUmVzcG9uc2UiA5ACARJ4ChlBZGRPcmdhbml6YXRpb25UZWFtTWVtYmVyEisudGFpbG9yLnYxLkFkZE9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXF1ZXN0GiwudGFpbG9yLnYxLkFkZE9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXNwb25zZSIAEoEBChxVcGRhdGVPcmdhbml6YXRpb25UZWFtTWVtYmVyEi4udGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXF1ZXN0Gi8udGFpbG9yLnYxLlVwZGF0ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXNwb25zZSIAEoEBChxSZW1vdmVPcmdhbml6YXRpb25UZWFtTWVtYmVyEi4udGFpbG9yLnYxLlJlbW92ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXF1ZXN0Gi8udGFpbG9yLnYxLlJlbW92ZU9yZ2FuaXphdGlvblRlYW1NZW1iZXJSZXNwb25zZSIAEoEBChtMaXN0T3JnYW5pemF0aW9uVGVhbU1lbWJlcnMSLS50YWlsb3IudjEuTGlzdE9yZ2FuaXphdGlvblRlYW1NZW1iZXJzUmVxdWVzdBouLnRhaWxvci52MS5MaXN0T3JnYW5pemF0aW9uVGVhbU1lbWJlcnNSZXNwb25zZSIDkAIBEnsKGUdldE9yZ2FuaXphdGlvblRlYW1NZW1iZXISKy50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbU1lbWJlclJlcXVlc3QaLC50YWlsb3IudjEuR2V0T3JnYW5pemF0aW9uVGVhbU1lbWJlclJlc3BvbnNlIgOQAgEScgoWR2V0UGxhdGZvcm1BY2NvdW50UGxhbhIoLnRhaWxvci52MS5HZXRQbGF0Zm9ybUFjY291bnRQbGFuUmVxdWVzdBopLnRhaWxvci52MS5HZXRQbGF0Zm9ybUFjY291bnRQbGFuUmVzcG9uc2UiA5ACARJgChFDcmVhdGVBcHBsaWNhdGlvbhIjLnRhaWxvci52MS5DcmVhdGVBcHBsaWNhdGlvblJlcXVlc3QaJC50YWlsb3IudjEuQ3JlYXRlQXBwbGljYXRpb25SZXNwb25zZSIAEmAKEVVwZGF0ZUFwcGxpY2F0aW9uEiMudGFpbG9yLnYxLlVwZGF0ZUFwcGxpY2F0aW9uUmVxdWVzdBokLnRhaWxvci52MS5VcGRhdGVBcHBsaWNhdGlvblJlc3BvbnNlIgASYAoRRGVsZXRlQXBwbGljYXRpb24SIy50YWlsb3IudjEuRGVsZXRlQXBwbGljYXRpb25SZXF1ZXN0GiQudGFpbG9yLnYxLkRlbGV0ZUFwcGxpY2F0aW9uUmVzcG9uc2UiABJgChBMaXN0QXBwbGljYXRpb25zEiIudGFpbG9yLnYxLkxpc3RBcHBsaWNhdGlvbnNSZXF1ZXN0GiMudGFpbG9yLnYxLkxpc3RBcHBsaWNhdGlvbnNSZXNwb25zZSIDkAIBEloKDkdldEFwcGxpY2F0aW9uEiAudGFpbG9yLnYxLkdldEFwcGxpY2F0aW9uUmVxdWVzdBohLnRhaWxvci52MS5HZXRBcHBsaWNhdGlvblJlc3BvbnNlIgOQAgESfgoaR2V0QXBwbGljYXRpb25TY2hlbWFIZWFsdGgSLC50YWlsb3IudjEuR2V0QXBwbGljYXRpb25TY2hlbWFIZWFsdGhSZXF1ZXN0Gi0udGFpbG9yLnYxLkdldEFwcGxpY2F0aW9uU2NoZW1hSGVhbHRoUmVzcG9uc2UiA5ACARJjChJDb21wb3NlVGFpbG9yREJTREwSJC50YWlsb3IudjEuQ29tcG9zZVRhaWxvckRCU0RMUmVxdWVzdBolLnRhaWxvci52MS5Db21wb3NlVGFpbG9yREJTRExSZXNwb25zZSIAEmwKFUNyZWF0ZVRhaWxvckRCU2VydmljZRInLnRhaWxvci52MS5DcmVhdGVUYWlsb3JEQlNlcnZpY2VSZXF1ZXN0GigudGFpbG9yLnYxLkNyZWF0ZVRhaWxvckRCU2VydmljZVJlc3BvbnNlIgASbAoVVXBkYXRlVGFpbG9yREJTZXJ2aWNlEicudGFpbG9yLnYxLlVwZGF0ZVRhaWxvckRCU2VydmljZVJlcXVlc3QaKC50YWlsb3IudjEuVXBkYXRlVGFpbG9yREJTZXJ2aWNlUmVzcG9uc2UiABJsChVEZWxldGVUYWlsb3JEQlNlcnZpY2USJy50YWlsb3IudjEuRGVsZXRlVGFpbG9yREJTZXJ2aWNlUmVxdWVzdBooLnRhaWxvci52MS5EZWxldGVUYWlsb3JEQlNlcnZpY2VSZXNwb25zZSIAEmYKEkdldFRhaWxvckRCU2VydmljZRIkLnRhaWxvci52MS5HZXRUYWlsb3JEQlNlcnZpY2VSZXF1ZXN0GiUudGFpbG9yLnYxLkdldFRhaWxvckRCU2VydmljZVJlc3BvbnNlIgOQAgESbAoUTGlzdFRhaWxvckRCU2VydmljZXMSJi50YWlsb3IudjEuTGlzdFRhaWxvckRCU2VydmljZXNSZXF1ZXN0GicudGFpbG9yLnYxLkxpc3RUYWlsb3JEQlNlcnZpY2VzUmVzcG9uc2UiA5ACARJjChJDcmVhdGVUYWlsb3JEQlR5cGUSJC50YWlsb3IudjEuQ3JlYXRlVGFpbG9yREJUeXBlUmVxdWVzdBolLnRhaWxvci52MS5DcmVhdGVUYWlsb3JEQlR5cGVSZXNwb25zZSIAEmMKElVwZGF0ZVRhaWxvckRCVHlwZRIkLnRhaWxvci52MS5VcGRhdGVUYWlsb3JEQlR5cGVSZXF1ZXN0GiUudGFpbG9yLnYxLlVwZGF0ZVRhaWxvckRCVHlwZVJlc3BvbnNlIgASYwoSRGVsZXRlVGFpbG9yREJUeXBlEiQudGFpbG9yLnYxLkRlbGV0ZVRhaWxvckRCVHlwZVJlcXVlc3QaJS50YWlsb3IudjEuRGVsZXRlVGFpbG9yREJUeXBlUmVzcG9uc2UiABJsChVUcnVuY2F0ZVRhaWxvckRCVHlwZXMSJy50YWlsb3IudjEuVHJ1bmNhdGVUYWlsb3JEQlR5cGVzUmVxdWVzdBooLnRhaWxvci52MS5UcnVuY2F0ZVRhaWxvckRCVHlwZXNSZXNwb25zZSIAEmkKFFRydW5jYXRlVGFpbG9yREJUeXBlEiYudGFpbG9yLnYxLlRydW5jYXRlVGFpbG9yREJUeXBlUmVxdWVzdBonLnRhaWxvci52MS5UcnVuY2F0ZVRhaWxvckRCVHlwZVJlc3BvbnNlIgASYwoRTGlzdFRhaWxvckRCVHlwZXMSIy50YWlsb3IudjEuTGlzdFRhaWxvckRCVHlwZXNSZXF1ZXN0GiQudGFpbG9yLnYxLkxpc3RUYWlsb3JEQlR5cGVzUmVzcG9uc2UiA5ACARJdCg9HZXRUYWlsb3JEQlR5cGUSIS50YWlsb3IudjEuR2V0VGFpbG9yREJUeXBlUmVxdWVzdBoiLnRhaWxvci52MS5HZXRUYWlsb3JEQlR5cGVSZXNwb25zZSIDkAIBEn4KG0NyZWF0ZVRhaWxvckRCR1FMUGVybWlzc2lvbhItLnRhaWxvci52MS5DcmVhdGVUYWlsb3JEQkdRTFBlcm1pc3Npb25SZXF1ZXN0Gi4udGFpbG9yLnYxLkNyZWF0ZVRhaWxvckRCR1FMUGVybWlzc2lvblJlc3BvbnNlIgASeAoYR2V0VGFpbG9yREJHUUxQZXJtaXNzaW9uEioudGFpbG9yLnYxLkdldFRhaWxvckRCR1FMUGVybWlzc2lvblJlcXVlc3QaKy50YWlsb3IudjEuR2V0VGFpbG9yREJHUUxQZXJtaXNzaW9uUmVzcG9uc2UiA5ACARJ+ChpMaXN0VGFpbG9yREJHUUxQZXJtaXNzaW9ucxIsLnRhaWxvci52MS5MaXN0VGFpbG9yREJHUUxQZXJtaXNzaW9uc1JlcXVlc3QaLS50YWlsb3IudjEuTGlzdFRhaWxvckRCR1FMUGVybWlzc2lvbnNSZXNwb25zZSIDkAIBEn4KG1VwZGF0ZVRhaWxvckRCR1FMUGVybWlzc2lvbhItLnRhaWxvci52MS5VcGRhdGVUYWlsb3JEQkdRTFBlcm1pc3Npb25SZXF1ZXN0Gi4udGFpbG9yLnYxLlVwZGF0ZVRhaWxvckRCR1FMUGVybWlzc2lvblJlc3BvbnNlIgASfgobRGVsZXRlVGFpbG9yREJHUUxQZXJtaXNzaW9uEi0udGFpbG9yLnYxLkRlbGV0ZVRhaWxvckRCR1FMUGVybWlzc2lvblJlcXVlc3QaLi50YWlsb3IudjEuRGVsZXRlVGFpbG9yREJHUUxQZXJtaXNzaW9uUmVzcG9uc2UiABJsChVDcmVhdGVQaXBlbGluZVNlcnZpY2USJy50YWlsb3IudjEuQ3JlYXRlUGlwZWxpbmVTZXJ2aWNlUmVxdWVzdBooLnRhaWxvci52MS5DcmVhdGVQaXBlbGluZVNlcnZpY2VSZXNwb25zZSIAEmwKFVVwZGF0ZVBpcGVsaW5lU2VydmljZRInLnRhaWxvci52MS5VcGRhdGVQaXBlbGluZVNlcnZpY2VSZXF1ZXN0GigudGFpbG9yLnYxLlVwZGF0ZVBpcGVsaW5lU2VydmljZVJlc3BvbnNlIgASbAoVRGVsZXRlUGlwZWxpbmVTZXJ2aWNlEicudGFpbG9yLnYxLkRlbGV0ZVBpcGVsaW5lU2VydmljZVJlcXVlc3QaKC50YWlsb3IudjEuRGVsZXRlUGlwZWxpbmVTZXJ2aWNlUmVzcG9uc2UiABJmChJHZXRQaXBlbGluZVNlcnZpY2USJC50YWlsb3IudjEuR2V0UGlwZWxpbmVTZXJ2aWNlUmVxdWVzdBolLnRhaWxvci52MS5HZXRQaXBlbGluZVNlcnZpY2VSZXNwb25zZSIDkAIBEmwKFExpc3RQaXBlbGluZVNlcnZpY2VzEiYudGFpbG9yLnYxLkxpc3RQaXBlbGluZVNlcnZpY2VzUmVxdWVzdBonLnRhaWxvci52MS5MaXN0UGlwZWxpbmVTZXJ2aWNlc1Jlc3BvbnNlIgOQAgESaQoTR2V0UGlwZWxpbmVSZXNvbHZlchIlLnRhaWxvci52MS5HZXRQaXBlbGluZVJlc29sdmVyUmVxdWVzdBomLnRhaWxvci52MS5HZXRQaXBlbGluZVJlc29sdmVyUmVzcG9uc2UiA5ACARJvChVMaXN0UGlwZWxpbmVSZXNvbHZlcnMSJy50YWlsb3IudjEuTGlzdFBpcGVsaW5lUmVzb2x2ZXJzUmVxdWVzdBooLnRhaWxvci52MS5MaXN0UGlwZWxpbmVSZXNvbHZlcnNSZXNwb25zZSIDkAIBEm8KFkNyZWF0ZVBpcGVsaW5lUmVzb2x2ZXISKC50YWlsb3IudjEuQ3JlYXRlUGlwZWxpbmVSZXNvbHZlclJlcXVlc3QaKS50YWlsb3IudjEuQ3JlYXRlUGlwZWxpbmVSZXNvbHZlclJlc3BvbnNlIgASbwoWVXBkYXRlUGlwZWxpbmVSZXNvbHZlchIoLnRhaWxvci52MS5VcGRhdGVQaXBlbGluZVJlc29sdmVyUmVxdWVzdBopLnRhaWxvci52MS5VcGRhdGVQaXBlbGluZVJlc29sdmVyUmVzcG9uc2UiABJvChZEZWxldGVQaXBlbGluZVJlc29sdmVyEigudGFpbG9yLnYxLkRlbGV0ZVBpcGVsaW5lUmVzb2x2ZXJSZXF1ZXN0GikudGFpbG9yLnYxLkRlbGV0ZVBpcGVsaW5lUmVzb2x2ZXJSZXNwb25zZSIAEmMKEkNvbXBvc2VQaXBlbGluZVNETBIkLnRhaWxvci52MS5Db21wb3NlUGlwZWxpbmVTRExSZXF1ZXN0GiUudGFpbG9yLnYxLkNvbXBvc2VQaXBlbGluZVNETFJlc3BvbnNlIgASnAEKJExpc3RQaXBlbGluZVJlc29sdmVyRXhlY3V0aW9uUmVzdWx0cxI2LnRhaWxvci52MS5MaXN0UGlwZWxpbmVSZXNvbHZlckV4ZWN1dGlvblJlc3VsdHNSZXF1ZXN0GjcudGFpbG9yLnYxLkxpc3RQaXBlbGluZVJlc29sdmVyRXhlY3V0aW9uUmVzdWx0c1Jlc3BvbnNlIgOQAgESlgEKIkdldFBpcGVsaW5lUmVzb2x2ZXJFeGVjdXRpb25SZXN1bHQSNC50YWlsb3IudjEuR2V0UGlwZWxpbmVSZXNvbHZlckV4ZWN1dGlvblJlc3VsdFJlcXVlc3QaNS50YWlsb3IudjEuR2V0UGlwZWxpbmVSZXNvbHZlckV4ZWN1dGlvblJlc3VsdFJlc3BvbnNlIgOQAgEScgoXUmVzdGFydFBpcGVsaW5lUmVzb2x2ZXISKS50YWlsb3IudjEuUmVzdGFydFBpcGVsaW5lUmVzb2x2ZXJSZXF1ZXN0GioudGFpbG9yLnYxLlJlc3RhcnRQaXBlbGluZVJlc29sdmVyUmVzcG9uc2UiABJvChZDcmVhdGVTdGF0ZWZsb3dTZXJ2aWNlEigudGFpbG9yLnYxLkNyZWF0ZVN0YXRlZmxvd1NlcnZpY2VSZXF1ZXN0GikudGFpbG9yLnYxLkNyZWF0ZVN0YXRlZmxvd1NlcnZpY2VSZXNwb25zZSIAEm8KFlVwZGF0ZVN0YXRlZmxvd1NlcnZpY2USKC50YWlsb3IudjEuVXBkYXRlU3RhdGVmbG93U2VydmljZVJlcXVlc3QaKS50YWlsb3IudjEuVXBkYXRlU3RhdGVmbG93U2VydmljZVJlc3BvbnNlIgASbwoWRGVsZXRlU3RhdGVmbG93U2VydmljZRIoLnRhaWxvci52MS5EZWxldGVTdGF0ZWZsb3dTZXJ2aWNlUmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVTdGF0ZWZsb3dTZXJ2aWNlUmVzcG9uc2UiABJpChNHZXRTdGF0ZWZsb3dTZXJ2aWNlEiUudGFpbG9yLnYxLkdldFN0YXRlZmxvd1NlcnZpY2VSZXF1ZXN0GiYudGFpbG9yLnYxLkdldFN0YXRlZmxvd1NlcnZpY2VSZXNwb25zZSIDkAIBEm8KFUxpc3RTdGF0ZWZsb3dTZXJ2aWNlcxInLnRhaWxvci52MS5MaXN0U3RhdGVmbG93U2VydmljZXNSZXF1ZXN0GigudGFpbG9yLnYxLkxpc3RTdGF0ZWZsb3dTZXJ2aWNlc1Jlc3BvbnNlIgOQAgESbwoWQ3JlYXRlRXhlY3V0b3JFeGVjdXRvchIoLnRhaWxvci52MS5DcmVhdGVFeGVjdXRvckV4ZWN1dG9yUmVxdWVzdBopLnRhaWxvci52MS5DcmVhdGVFeGVjdXRvckV4ZWN1dG9yUmVzcG9uc2UiABJvChZVcGRhdGVFeGVjdXRvckV4ZWN1dG9yEigudGFpbG9yLnYxLlVwZGF0ZUV4ZWN1dG9yRXhlY3V0b3JSZXF1ZXN0GikudGFpbG9yLnYxLlVwZGF0ZUV4ZWN1dG9yRXhlY3V0b3JSZXNwb25zZSIAEmkKE0dldEV4ZWN1dG9yRXhlY3V0b3ISJS50YWlsb3IudjEuR2V0RXhlY3V0b3JFeGVjdXRvclJlcXVlc3QaJi50YWlsb3IudjEuR2V0RXhlY3V0b3JFeGVjdXRvclJlc3BvbnNlIgOQAgESbwoWRGVsZXRlRXhlY3V0b3JFeGVjdXRvchIoLnRhaWxvci52MS5EZWxldGVFeGVjdXRvckV4ZWN1dG9yUmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVFeGVjdXRvckV4ZWN1dG9yUmVzcG9uc2UiABJvChVMaXN0RXhlY3V0b3JFeGVjdXRvcnMSJy50YWlsb3IudjEuTGlzdEV4ZWN1dG9yRXhlY3V0b3JzUmVxdWVzdBooLnRhaWxvci52MS5MaXN0RXhlY3V0b3JFeGVjdXRvcnNSZXNwb25zZSIDkAIBEloKDkdldEV4ZWN1dG9ySm9iEiAudGFpbG9yLnYxLkdldEV4ZWN1dG9ySm9iUmVxdWVzdBohLnRhaWxvci52MS5HZXRFeGVjdXRvckpvYlJlc3BvbnNlIgOQAgESYAoQTGlzdEV4ZWN1dG9ySm9icxIiLnRhaWxvci52MS5MaXN0RXhlY3V0b3JKb2JzUmVxdWVzdBojLnRhaWxvci52MS5MaXN0RXhlY3V0b3JKb2JzUmVzcG9uc2UiA5ACARJ1ChdMaXN0RXhlY3V0b3JKb2JBdHRlbXB0cxIpLnRhaWxvci52MS5MaXN0RXhlY3V0b3JKb2JBdHRlbXB0c1JlcXVlc3QaKi50YWlsb3IudjEuTGlzdEV4ZWN1dG9ySm9iQXR0ZW1wdHNSZXNwb25zZSIDkAIBEoQBChxMaXN0RXhlY3V0b3JJbmNvbWluZ1dlYmhvb2tzEi4udGFpbG9yLnYxLkxpc3RFeGVjdXRvckluY29taW5nV2ViaG9va3NSZXF1ZXN0Gi8udGFpbG9yLnYxLkxpc3RFeGVjdXRvckluY29taW5nV2ViaG9va3NSZXNwb25zZSIDkAIBEn4KGkdldEV4ZWN1dG9ySW5jb21pbmdXZWJob29rEiwudGFpbG9yLnYxLkdldEV4ZWN1dG9ySW5jb21pbmdXZWJob29rUmVxdWVzdBotLnRhaWxvci52MS5HZXRFeGVjdXRvckluY29taW5nV2ViaG9va1Jlc3BvbnNlIgOQAgESWgoPVHJpZ2dlckV4ZWN1dG9yEiEudGFpbG9yLnYxLlRyaWdnZXJFeGVjdXRvclJlcXVlc3QaIi50YWlsb3IudjEuVHJpZ2dlckV4ZWN1dG9yUmVzcG9uc2UiABJ1ChhDcmVhdGVTZWNyZXRNYW5hZ2VyVmF1bHQSKi50YWlsb3IudjEuQ3JlYXRlU2VjcmV0TWFuYWdlclZhdWx0UmVxdWVzdBorLnRhaWxvci52MS5DcmVhdGVTZWNyZXRNYW5hZ2VyVmF1bHRSZXNwb25zZSIAEm8KFUdldFNlY3JldE1hbmFnZXJWYXVsdBInLnRhaWxvci52MS5HZXRTZWNyZXRNYW5hZ2VyVmF1bHRSZXF1ZXN0GigudGFpbG9yLnYxLkdldFNlY3JldE1hbmFnZXJWYXVsdFJlc3BvbnNlIgOQAgESdQoYRGVsZXRlU2VjcmV0TWFuYWdlclZhdWx0EioudGFpbG9yLnYxLkRlbGV0ZVNlY3JldE1hbmFnZXJWYXVsdFJlcXVlc3QaKy50YWlsb3IudjEuRGVsZXRlU2VjcmV0TWFuYWdlclZhdWx0UmVzcG9uc2UiABJ1ChdMaXN0U2VjcmV0TWFuYWdlclZhdWx0cxIpLnRhaWxvci52MS5MaXN0U2VjcmV0TWFuYWdlclZhdWx0c1JlcXVlc3QaKi50YWlsb3IudjEuTGlzdFNlY3JldE1hbmFnZXJWYXVsdHNSZXNwb25zZSIDkAIBEngKGUNyZWF0ZVNlY3JldE1hbmFnZXJTZWNyZXQSKy50YWlsb3IudjEuQ3JlYXRlU2VjcmV0TWFuYWdlclNlY3JldFJlcXVlc3QaLC50YWlsb3IudjEuQ3JlYXRlU2VjcmV0TWFuYWdlclNlY3JldFJlc3BvbnNlIgASeAoZVXBkYXRlU2VjcmV0TWFuYWdlclNlY3JldBIrLnRhaWxvci52MS5VcGRhdGVTZWNyZXRNYW5hZ2VyU2VjcmV0UmVxdWVzdBosLnRhaWxvci52MS5VcGRhdGVTZWNyZXRNYW5hZ2VyU2VjcmV0UmVzcG9uc2UiABJyChZHZXRTZWNyZXRNYW5hZ2VyU2VjcmV0EigudGFpbG9yLnYxLkdldFNlY3JldE1hbmFnZXJTZWNyZXRSZXF1ZXN0GikudGFpbG9yLnYxLkdldFNlY3JldE1hbmFnZXJTZWNyZXRSZXNwb25zZSIDkAIBEngKGURlbGV0ZVNlY3JldE1hbmFnZXJTZWNyZXQSKy50YWlsb3IudjEuRGVsZXRlU2VjcmV0TWFuYWdlclNlY3JldFJlcXVlc3QaLC50YWlsb3IudjEuRGVsZXRlU2VjcmV0TWFuYWdlclNlY3JldFJlc3BvbnNlIgASeAoYTGlzdFNlY3JldE1hbmFnZXJTZWNyZXRzEioudGFpbG9yLnYxLkxpc3RTZWNyZXRNYW5hZ2VyU2VjcmV0c1JlcXVlc3QaKy50YWlsb3IudjEuTGlzdFNlY3JldE1hbmFnZXJTZWNyZXRzUmVzcG9uc2UiA5ACARJgChFDcmVhdGVBdXRoU2VydmljZRIjLnRhaWxvci52MS5DcmVhdGVBdXRoU2VydmljZVJlcXVlc3QaJC50YWlsb3IudjEuQ3JlYXRlQXV0aFNlcnZpY2VSZXNwb25zZSIAEmAKEVVwZGF0ZUF1dGhTZXJ2aWNlEiMudGFpbG9yLnYxLlVwZGF0ZUF1dGhTZXJ2aWNlUmVxdWVzdBokLnRhaWxvci52MS5VcGRhdGVBdXRoU2VydmljZVJlc3BvbnNlIgASYAoRRGVsZXRlQXV0aFNlcnZpY2USIy50YWlsb3IudjEuRGVsZXRlQXV0aFNlcnZpY2VSZXF1ZXN0GiQudGFpbG9yLnYxLkRlbGV0ZUF1dGhTZXJ2aWNlUmVzcG9uc2UiABJaCg5HZXRBdXRoU2VydmljZRIgLnRhaWxvci52MS5HZXRBdXRoU2VydmljZVJlcXVlc3QaIS50YWlsb3IudjEuR2V0QXV0aFNlcnZpY2VSZXNwb25zZSIDkAIBEmAKEExpc3RBdXRoU2VydmljZXMSIi50YWlsb3IudjEuTGlzdEF1dGhTZXJ2aWNlc1JlcXVlc3QaIy50YWlsb3IudjEuTGlzdEF1dGhTZXJ2aWNlc1Jlc3BvbnNlIgOQAgESZgoTQ3JlYXRlQXV0aElEUENvbmZpZxIlLnRhaWxvci52MS5DcmVhdGVBdXRoSURQQ29uZmlnUmVxdWVzdBomLnRhaWxvci52MS5DcmVhdGVBdXRoSURQQ29uZmlnUmVzcG9uc2UiABJmChNVcGRhdGVBdXRoSURQQ29uZmlnEiUudGFpbG9yLnYxLlVwZGF0ZUF1dGhJRFBDb25maWdSZXF1ZXN0GiYudGFpbG9yLnYxLlVwZGF0ZUF1dGhJRFBDb25maWdSZXNwb25zZSIAEmYKE0RlbGV0ZUF1dGhJRFBDb25maWcSJS50YWlsb3IudjEuRGVsZXRlQXV0aElEUENvbmZpZ1JlcXVlc3QaJi50YWlsb3IudjEuRGVsZXRlQXV0aElEUENvbmZpZ1Jlc3BvbnNlIgASYAoQR2V0QXV0aElEUENvbmZpZxIiLnRhaWxvci52MS5HZXRBdXRoSURQQ29uZmlnUmVxdWVzdBojLnRhaWxvci52MS5HZXRBdXRoSURQQ29uZmlnUmVzcG9uc2UiA5ACARJmChJMaXN0QXV0aElEUENvbmZpZ3MSJC50YWlsb3IudjEuTGlzdEF1dGhJRFBDb25maWdzUmVxdWVzdBolLnRhaWxvci52MS5MaXN0QXV0aElEUENvbmZpZ3NSZXNwb25zZSIDkAIBEnIKF0NyZWF0ZVVzZXJQcm9maWxlQ29uZmlnEikudGFpbG9yLnYxLkNyZWF0ZVVzZXJQcm9maWxlQ29uZmlnUmVxdWVzdBoqLnRhaWxvci52MS5DcmVhdGVVc2VyUHJvZmlsZUNvbmZpZ1Jlc3BvbnNlIgAScgoXVXBkYXRlVXNlclByb2ZpbGVDb25maWcSKS50YWlsb3IudjEuVXBkYXRlVXNlclByb2ZpbGVDb25maWdSZXF1ZXN0GioudGFpbG9yLnYxLlVwZGF0ZVVzZXJQcm9maWxlQ29uZmlnUmVzcG9uc2UiABJyChdEZWxldGVVc2VyUHJvZmlsZUNvbmZpZxIpLnRhaWxvci52MS5EZWxldGVVc2VyUHJvZmlsZUNvbmZpZ1JlcXVlc3QaKi50YWlsb3IudjEuRGVsZXRlVXNlclByb2ZpbGVDb25maWdSZXNwb25zZSIAEmwKFEdldFVzZXJQcm9maWxlQ29uZmlnEiYudGFpbG9yLnYxLkdldFVzZXJQcm9maWxlQ29uZmlnUmVxdWVzdBonLnRhaWxvci52MS5HZXRVc2VyUHJvZmlsZUNvbmZpZ1Jlc3BvbnNlIgOQAgESYwoSQ3JlYXRlVGVuYW50Q29uZmlnEiQudGFpbG9yLnYxLkNyZWF0ZVRlbmFudENvbmZpZ1JlcXVlc3QaJS50YWlsb3IudjEuQ3JlYXRlVGVuYW50Q29uZmlnUmVzcG9uc2UiABJjChJVcGRhdGVUZW5hbnRDb25maWcSJC50YWlsb3IudjEuVXBkYXRlVGVuYW50Q29uZmlnUmVxdWVzdBolLnRhaWxvci52MS5VcGRhdGVUZW5hbnRDb25maWdSZXNwb25zZSIAEmMKEkRlbGV0ZVRlbmFudENvbmZpZxIkLnRhaWxvci52MS5EZWxldGVUZW5hbnRDb25maWdSZXF1ZXN0GiUudGFpbG9yLnYxLkRlbGV0ZVRlbmFudENvbmZpZ1Jlc3BvbnNlIgASXQoPR2V0VGVuYW50Q29uZmlnEiEudGFpbG9yLnYxLkdldFRlbmFudENvbmZpZ1JlcXVlc3QaIi50YWlsb3IudjEuR2V0VGVuYW50Q29uZmlnUmVzcG9uc2UiA5ACARJ4ChlDcmVhdGVQZXJzb25hbEFjY2Vzc1Rva2VuEisudGFpbG9yLnYxLkNyZWF0ZVBlcnNvbmFsQWNjZXNzVG9rZW5SZXF1ZXN0GiwudGFpbG9yLnYxLkNyZWF0ZVBlcnNvbmFsQWNjZXNzVG9rZW5SZXNwb25zZSIAEngKGURlbGV0ZVBlcnNvbmFsQWNjZXNzVG9rZW4SKy50YWlsb3IudjEuRGVsZXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlcXVlc3QaLC50YWlsb3IudjEuRGVsZXRlUGVyc29uYWxBY2Nlc3NUb2tlblJlc3BvbnNlIgASeAoYTGlzdFBlcnNvbmFsQWNjZXNzVG9rZW5zEioudGFpbG9yLnYxLkxpc3RQZXJzb25hbEFjY2Vzc1Rva2Vuc1JlcXVlc3QaKy50YWlsb3IudjEuTGlzdFBlcnNvbmFsQWNjZXNzVG9rZW5zUmVzcG9uc2UiA5ACARJsChVDcmVhdGVBdXRoTWFjaGluZVVzZXISJy50YWlsb3IudjEuQ3JlYXRlQXV0aE1hY2hpbmVVc2VyUmVxdWVzdBooLnRhaWxvci52MS5DcmVhdGVBdXRoTWFjaGluZVVzZXJSZXNwb25zZSIAEmwKFVVwZGF0ZUF1dGhNYWNoaW5lVXNlchInLnRhaWxvci52MS5VcGRhdGVBdXRoTWFjaGluZVVzZXJSZXF1ZXN0GigudGFpbG9yLnYxLlVwZGF0ZUF1dGhNYWNoaW5lVXNlclJlc3BvbnNlIgASbAoVRGVsZXRlQXV0aE1hY2hpbmVVc2VyEicudGFpbG9yLnYxLkRlbGV0ZUF1dGhNYWNoaW5lVXNlclJlcXVlc3QaKC50YWlsb3IudjEuRGVsZXRlQXV0aE1hY2hpbmVVc2VyUmVzcG9uc2UiABJmChJHZXRBdXRoTWFjaGluZVVzZXISJC50YWlsb3IudjEuR2V0QXV0aE1hY2hpbmVVc2VyUmVxdWVzdBolLnRhaWxvci52MS5HZXRBdXRoTWFjaGluZVVzZXJSZXNwb25zZSIDkAIBEmwKFExpc3RBdXRoTWFjaGluZVVzZXJzEiYudGFpbG9yLnYxLkxpc3RBdXRoTWFjaGluZVVzZXJzUmVxdWVzdBonLnRhaWxvci52MS5MaXN0QXV0aE1hY2hpbmVVc2Vyc1Jlc3BvbnNlIgOQAgESaQoUQ3JlYXRlQXV0aFNDSU1Db25maWcSJi50YWlsb3IudjEuQ3JlYXRlQXV0aFNDSU1Db25maWdSZXF1ZXN0GicudGFpbG9yLnYxLkNyZWF0ZUF1dGhTQ0lNQ29uZmlnUmVzcG9uc2UiABJpChRVcGRhdGVBdXRoU0NJTUNvbmZpZxImLnRhaWxvci52MS5VcGRhdGVBdXRoU0NJTUNvbmZpZ1JlcXVlc3QaJy50YWlsb3IudjEuVXBkYXRlQXV0aFNDSU1Db25maWdSZXNwb25zZSIAEmkKFERlbGV0ZUF1dGhTQ0lNQ29uZmlnEiYudGFpbG9yLnYxLkRlbGV0ZUF1dGhTQ0lNQ29uZmlnUmVxdWVzdBonLnRhaWxvci52MS5EZWxldGVBdXRoU0NJTUNvbmZpZ1Jlc3BvbnNlIgASYwoRR2V0QXV0aFNDSU1Db25maWcSIy50YWlsb3IudjEuR2V0QXV0aFNDSU1Db25maWdSZXF1ZXN0GiQudGFpbG9yLnYxLkdldEF1dGhTQ0lNQ29uZmlnUmVzcG9uc2UiA5ACARJvChZDcmVhdGVBdXRoU0NJTVJlc291cmNlEigudGFpbG9yLnYxLkNyZWF0ZUF1dGhTQ0lNUmVzb3VyY2VSZXF1ZXN0GikudGFpbG9yLnYxLkNyZWF0ZUF1dGhTQ0lNUmVzb3VyY2VSZXNwb25zZSIAEm8KFlVwZGF0ZUF1dGhTQ0lNUmVzb3VyY2USKC50YWlsb3IudjEuVXBkYXRlQXV0aFNDSU1SZXNvdXJjZVJlcXVlc3QaKS50YWlsb3IudjEuVXBkYXRlQXV0aFNDSU1SZXNvdXJjZVJlc3BvbnNlIgASbwoWRGVsZXRlQXV0aFNDSU1SZXNvdXJjZRIoLnRhaWxvci52MS5EZWxldGVBdXRoU0NJTVJlc291cmNlUmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVBdXRoU0NJTVJlc291cmNlUmVzcG9uc2UiABJpChNHZXRBdXRoU0NJTVJlc291cmNlEiUudGFpbG9yLnYxLkdldEF1dGhTQ0lNUmVzb3VyY2VSZXF1ZXN0GiYudGFpbG9yLnYxLkdldEF1dGhTQ0lNUmVzb3VyY2VSZXNwb25zZSIDkAIBEmwKFEdldEF1dGhTQ0lNUmVzb3VyY2VzEiYudGFpbG9yLnYxLkdldEF1dGhTQ0lNUmVzb3VyY2VzUmVxdWVzdBonLnRhaWxvci52MS5HZXRBdXRoU0NJTVJlc291cmNlc1Jlc3BvbnNlIgOQAgESVwoOQ3JlYXRlQXV0aEhvb2sSIC50YWlsb3IudjEuQ3JlYXRlQXV0aEhvb2tSZXF1ZXN0GiEudGFpbG9yLnYxLkNyZWF0ZUF1dGhIb29rUmVzcG9uc2UiABJXCg5VcGRhdGVBdXRoSG9vaxIgLnRhaWxvci52MS5VcGRhdGVBdXRoSG9va1JlcXVlc3QaIS50YWlsb3IudjEuVXBkYXRlQXV0aEhvb2tSZXNwb25zZSIAElcKDkRlbGV0ZUF1dGhIb29rEiAudGFpbG9yLnYxLkRlbGV0ZUF1dGhIb29rUmVxdWVzdBohLnRhaWxvci52MS5EZWxldGVBdXRoSG9va1Jlc3BvbnNlIgASUQoLR2V0QXV0aEhvb2sSHS50YWlsb3IudjEuR2V0QXV0aEhvb2tSZXF1ZXN0Gh4udGFpbG9yLnYxLkdldEF1dGhIb29rUmVzcG9uc2UiA5ACARJpChRDcmVhdGVBdXRoQ29ubmVjdGlvbhImLnRhaWxvci52MS5DcmVhdGVBdXRoQ29ubmVjdGlvblJlcXVlc3QaJy50YWlsb3IudjEuQ3JlYXRlQXV0aENvbm5lY3Rpb25SZXNwb25zZSIAEmkKE0xpc3RBdXRoQ29ubmVjdGlvbnMSJS50YWlsb3IudjEuTGlzdEF1dGhDb25uZWN0aW9uc1JlcXVlc3QaJi50YWlsb3IudjEuTGlzdEF1dGhDb25uZWN0aW9uc1Jlc3BvbnNlIgOQAgESaQoUUmV2b2tlQXV0aENvbm5lY3Rpb24SJi50YWlsb3IudjEuUmV2b2tlQXV0aENvbm5lY3Rpb25SZXF1ZXN0GicudGFpbG9yLnYxLlJldm9rZUF1dGhDb25uZWN0aW9uUmVzcG9uc2UiABKEAQodUmVnaXN0ZXJBdXRoQ29ubmVjdGlvblNlc3Npb24SLy50YWlsb3IudjEuUmVnaXN0ZXJBdXRoQ29ubmVjdGlvblNlc3Npb25SZXF1ZXN0GjAudGFpbG9yLnYxLlJlZ2lzdGVyQXV0aENvbm5lY3Rpb25TZXNzaW9uUmVzcG9uc2UiABKiAQonRXhjaGFuZ2VBdXRoQ29ubmVjdGlvbkF1dGhvcml6YXRpb25Db2RlEjkudGFpbG9yLnYxLkV4Y2hhbmdlQXV0aENvbm5lY3Rpb25BdXRob3JpemF0aW9uQ29kZVJlcXVlc3QaOi50YWlsb3IudjEuRXhjaGFuZ2VBdXRoQ29ubmVjdGlvbkF1dGhvcml6YXRpb25Db2RlUmVzcG9uc2UiABJvChZDcmVhdGVBdXRoT0F1dGgyQ2xpZW50EigudGFpbG9yLnYxLkNyZWF0ZUF1dGhPQXV0aDJDbGllbnRSZXF1ZXN0GikudGFpbG9yLnYxLkNyZWF0ZUF1dGhPQXV0aDJDbGllbnRSZXNwb25zZSIAEm8KFlVwZGF0ZUF1dGhPQXV0aDJDbGllbnQSKC50YWlsb3IudjEuVXBkYXRlQXV0aE9BdXRoMkNsaWVudFJlcXVlc3QaKS50YWlsb3IudjEuVXBkYXRlQXV0aE9BdXRoMkNsaWVudFJlc3BvbnNlIgASbwoWRGVsZXRlQXV0aE9BdXRoMkNsaWVudBIoLnRhaWxvci52MS5EZWxldGVBdXRoT0F1dGgyQ2xpZW50UmVxdWVzdBopLnRhaWxvci52MS5EZWxldGVBdXRoT0F1dGgyQ2xpZW50UmVzcG9uc2UiABJpChNHZXRBdXRoT0F1dGgyQ2xpZW50EiUudGFpbG9yLnYxLkdldEF1dGhPQXV0aDJDbGllbnRSZXF1ZXN0GiYudGFpbG9yLnYxLkdldEF1dGhPQXV0aDJDbGllbnRSZXNwb25zZSIDkAIBEm8KFUxpc3RBdXRoT0F1dGgyQ2xpZW50cxInLnRhaWxvci52MS5MaXN0QXV0aE9BdXRoMkNsaWVudHNSZXF1ZXN0GigudGFpbG9yLnYxLkxpc3RBdXRoT0F1dGgyQ2xpZW50c1Jlc3BvbnNlIgOQAgESaQoTTGlzdERhdGFwbGFuZUV2ZW50cxIlLnRhaWxvci52MS5MaXN0RGF0YXBsYW5lRXZlbnRzUmVxdWVzdBomLnRhaWxvci52MS5MaXN0RGF0YXBsYW5lRXZlbnRzUmVzcG9uc2UiA5ACARKEAQocTGlzdENvbnRyb2xwbGFuZUFjdGl2aXR5TG9ncxIuLnRhaWxvci52MS5MaXN0Q29udHJvbHBsYW5lQWN0aXZpdHlMb2dzUmVxdWVzdBovLnRhaWxvci52MS5MaXN0Q29udHJvbHBsYW5lQWN0aXZpdHlMb2dzUmVzcG9uc2UiA5ACARJXCg5UZXN0RXhlY1NjcmlwdBIgLnRhaWxvci52MS5UZXN0RXhlY1NjcmlwdFJlcXVlc3QaIS50YWlsb3IudjEuVGVzdEV4ZWNTY3JpcHRSZXNwb25zZSIAEmwKFEdldEZ1bmN0aW9uRXhlY3V0aW9uEiYudGFpbG9yLnYxLkdldEZ1bmN0aW9uRXhlY3V0aW9uUmVxdWVzdBonLnRhaWxvci52MS5HZXRGdW5jdGlvbkV4ZWN1dGlvblJlc3BvbnNlIgOQAgEScgoWTGlzdEZ1bmN0aW9uRXhlY3V0aW9ucxIoLnRhaWxvci52MS5MaXN0RnVuY3Rpb25FeGVjdXRpb25zUmVxdWVzdBopLnRhaWxvci52MS5MaXN0RnVuY3Rpb25FeGVjdXRpb25zUmVzcG9uc2UiA5ACARJxChZDcmVhdGVGdW5jdGlvblJlZ2lzdHJ5EigudGFpbG9yLnYxLkNyZWF0ZUZ1bmN0aW9uUmVnaXN0cnlSZXF1ZXN0GikudGFpbG9yLnYxLkNyZWF0ZUZ1bmN0aW9uUmVnaXN0cnlSZXNwb25zZSIAKAEScQoWVXBkYXRlRnVuY3Rpb25SZWdpc3RyeRIoLnRhaWxvci52MS5VcGRhdGVGdW5jdGlvblJlZ2lzdHJ5UmVxdWVzdBopLnRhaWxvci52MS5VcGRhdGVGdW5jdGlvblJlZ2lzdHJ5UmVzcG9uc2UiACgBEmkKE0dldEZ1bmN0aW9uUmVnaXN0cnkSJS50YWlsb3IudjEuR2V0RnVuY3Rpb25SZWdpc3RyeVJlcXVlc3QaJi50YWlsb3IudjEuR2V0RnVuY3Rpb25SZWdpc3RyeVJlc3BvbnNlIgOQAgEScgoWTGlzdEZ1bmN0aW9uUmVnaXN0cmllcxIoLnRhaWxvci52MS5MaXN0RnVuY3Rpb25SZWdpc3RyaWVzUmVxdWVzdBopLnRhaWxvci52MS5MaXN0RnVuY3Rpb25SZWdpc3RyaWVzUmVzcG9uc2UiA5ACARJvChZEZWxldGVGdW5jdGlvblJlZ2lzdHJ5EigudGFpbG9yLnYxLkRlbGV0ZUZ1bmN0aW9uUmVnaXN0cnlSZXF1ZXN0GikudGFpbG9yLnYxLkRlbGV0ZUZ1bmN0aW9uUmVnaXN0cnlSZXNwb25zZSIAEowBCh5Eb3dubG9hZEZ1bmN0aW9uUmVnaXN0cnlTY3JpcHQSMC50YWlsb3IudjEuRG93bmxvYWRGdW5jdGlvblJlZ2lzdHJ5U2NyaXB0UmVxdWVzdBoxLnRhaWxvci52MS5Eb3dubG9hZEZ1bmN0aW9uUmVnaXN0cnlTY3JpcHRSZXNwb25zZSIDkAIBMAEScgoWTGlzdE1ldGVyUmVxdWVzdENvdW50cxIoLnRhaWxvci52MS5MaXN0TWV0ZXJSZXF1ZXN0Q291bnRzUmVxdWVzdBopLnRhaWxvci52MS5MaXN0TWV0ZXJSZXF1ZXN0Q291bnRzUmVzcG9uc2UiA5ACARJ4ChhMaXN0TWV0ZXJFeGVjdXRpb25Db3VudHMSKi50YWlsb3IudjEuTGlzdE1ldGVyRXhlY3V0aW9uQ291bnRzUmVxdWVzdBorLnRhaWxvci52MS5MaXN0TWV0ZXJFeGVjdXRpb25Db3VudHNSZXNwb25zZSIDkAIBEmwKFExpc3RNZXRlckV2ZW50Q291bnRzEiYudGFpbG9yLnYxLkxpc3RNZXRlckV2ZW50Q291bnRzUmVxdWVzdBonLnRhaWxvci52MS5MaXN0TWV0ZXJFdmVudENvdW50c1Jlc3BvbnNlIgOQAgESXQoPTGlzdElkUFNlcnZpY2VzEiEudGFpbG9yLnYxLkxpc3RJZFBTZXJ2aWNlc1JlcXVlc3QaIi50YWlsb3IudjEuTGlzdElkUFNlcnZpY2VzUmVzcG9uc2UiA5ACARJdChBDcmVhdGVJZFBTZXJ2aWNlEiIudGFpbG9yLnYxLkNyZWF0ZUlkUFNlcnZpY2VSZXF1ZXN0GiMudGFpbG9yLnYxLkNyZWF0ZUlkUFNlcnZpY2VSZXNwb25zZSIAEl0KEFVwZGF0ZUlkUFNlcnZpY2USIi50YWlsb3IudjEuVXBkYXRlSWRQU2VydmljZVJlcXVlc3QaIy50YWlsb3IudjEuVXBkYXRlSWRQU2VydmljZVJlc3BvbnNlIgASXQoQRGVsZXRlSWRQU2VydmljZRIiLnRhaWxvci52MS5EZWxldGVJZFBTZXJ2aWNlUmVxdWVzdBojLnRhaWxvci52MS5EZWxldGVJZFBTZXJ2aWNlUmVzcG9uc2UiABJXCg1HZXRJZFBTZXJ2aWNlEh8udGFpbG9yLnYxLkdldElkUFNlcnZpY2VSZXF1ZXN0GiAudGFpbG9yLnYxLkdldElkUFNlcnZpY2VSZXNwb25zZSIDkAIBEloKDkxpc3RJZFBDbGllbnRzEiAudGFpbG9yLnYxLkxpc3RJZFBDbGllbnRzUmVxdWVzdBohLnRhaWxvci52MS5MaXN0SWRQQ2xpZW50c1Jlc3BvbnNlIgOQAgESWgoPQ3JlYXRlSWRQQ2xpZW50EiEudGFpbG9yLnYxLkNyZWF0ZUlkUENsaWVudFJlcXVlc3QaIi50YWlsb3IudjEuQ3JlYXRlSWRQQ2xpZW50UmVzcG9uc2UiABJaCg9EZWxldGVJZFBDbGllbnQSIS50YWlsb3IudjEuRGVsZXRlSWRQQ2xpZW50UmVxdWVzdBoiLnRhaWxvci52MS5EZWxldGVJZFBDbGllbnRSZXNwb25zZSIAElQKDEdldElkUENsaWVudBIeLnRhaWxvci52MS5HZXRJZFBDbGllbnRSZXF1ZXN0Gh8udGFpbG9yLnYxLkdldElkUENsaWVudFJlc3BvbnNlIgOQAgESZgoTQ3JlYXRlU3RhdGljV2Vic2l0ZRIlLnRhaWxvci52MS5DcmVhdGVTdGF0aWNXZWJzaXRlUmVxdWVzdBomLnRhaWxvci52MS5DcmVhdGVTdGF0aWNXZWJzaXRlUmVzcG9uc2UiABJmChNVcGRhdGVTdGF0aWNXZWJzaXRlEiUudGFpbG9yLnYxLlVwZGF0ZVN0YXRpY1dlYnNpdGVSZXF1ZXN0GiYudGFpbG9yLnYxLlVwZGF0ZVN0YXRpY1dlYnNpdGVSZXNwb25zZSIAEmYKE0RlbGV0ZVN0YXRpY1dlYnNpdGUSJS50YWlsb3IudjEuRGVsZXRlU3RhdGljV2Vic2l0ZVJlcXVlc3QaJi50YWlsb3IudjEuRGVsZXRlU3RhdGljV2Vic2l0ZVJlc3BvbnNlIgASYAoQR2V0U3RhdGljV2Vic2l0ZRIiLnRhaWxvci52MS5HZXRTdGF0aWNXZWJzaXRlUmVxdWVzdBojLnRhaWxvci52MS5HZXRTdGF0aWNXZWJzaXRlUmVzcG9uc2UiA5ACARJmChJMaXN0U3RhdGljV2Vic2l0ZXMSJC50YWlsb3IudjEuTGlzdFN0YXRpY1dlYnNpdGVzUmVxdWVzdBolLnRhaWxvci52MS5MaXN0U3RhdGljV2Vic2l0ZXNSZXNwb25zZSIDkAIBEl0KEENyZWF0ZURlcGxveW1lbnQSIi50YWlsb3IudjEuQ3JlYXRlRGVwbG95bWVudFJlcXVlc3QaIy50YWlsb3IudjEuQ3JlYXRlRGVwbG95bWVudFJlc3BvbnNlIgASTQoKVXBsb2FkRmlsZRIcLnRhaWxvci52MS5VcGxvYWRGaWxlUmVxdWVzdBodLnRhaWxvci52MS5VcGxvYWRGaWxlUmVzcG9uc2UiACgBEmAKEVB1Ymxpc2hEZXBsb3ltZW50EiMudGFpbG9yLnYxLlB1Ymxpc2hEZXBsb3ltZW50UmVxdWVzdBokLnRhaWxvci52MS5QdWJsaXNoRGVwbG95bWVudFJlc3BvbnNlIgASVwoOQ3JlYXRlV29ya2Zsb3cSIC50YWlsb3IudjEuQ3JlYXRlV29ya2Zsb3dSZXF1ZXN0GiEudGFpbG9yLnYxLkNyZWF0ZVdvcmtmbG93UmVzcG9uc2UiABJXCg5VcGRhdGVXb3JrZmxvdxIgLnRhaWxvci52MS5VcGRhdGVXb3JrZmxvd1JlcXVlc3QaIS50YWlsb3IudjEuVXBkYXRlV29ya2Zsb3dSZXNwb25zZSIAElcKDkRlbGV0ZVdvcmtmbG93EiAudGFpbG9yLnYxLkRlbGV0ZVdvcmtmbG93UmVxdWVzdBohLnRhaWxvci52MS5EZWxldGVXb3JrZmxvd1Jlc3BvbnNlIgASUQoLR2V0V29ya2Zsb3cSHS50YWlsb3IudjEuR2V0V29ya2Zsb3dSZXF1ZXN0Gh4udGFpbG9yLnYxLkdldFdvcmtmbG93UmVzcG9uc2UiA5ACARJjChFHZXRXb3JrZmxvd0J5TmFtZRIjLnRhaWxvci52MS5HZXRXb3JrZmxvd0J5TmFtZVJlcXVlc3QaJC50YWlsb3IudjEuR2V0V29ya2Zsb3dCeU5hbWVSZXNwb25zZSIDkAIBElcKDUxpc3RXb3JrZmxvd3MSHy50YWlsb3IudjEuTGlzdFdvcmtmbG93c1JlcXVlc3QaIC50YWlsb3IudjEuTGlzdFdvcmtmbG93c1Jlc3BvbnNlIgOQAgESeAoZQ3JlYXRlV29ya2Zsb3dKb2JGdW5jdGlvbhIrLnRhaWxvci52MS5DcmVhdGVXb3JrZmxvd0pvYkZ1bmN0aW9uUmVxdWVzdBosLnRhaWxvci52MS5DcmVhdGVXb3JrZmxvd0pvYkZ1bmN0aW9uUmVzcG9uc2UiABJ4ChlVcGRhdGVXb3JrZmxvd0pvYkZ1bmN0aW9uEisudGFpbG9yLnYxLlVwZGF0ZVdvcmtmbG93Sm9iRnVuY3Rpb25SZXF1ZXN0GiwudGFpbG9yLnYxLlVwZGF0ZVdvcmtmbG93Sm9iRnVuY3Rpb25SZXNwb25zZSIAEnIKFkdldFdvcmtmbG93Sm9iRnVuY3Rpb24SKC50YWlsb3IudjEuR2V0V29ya2Zsb3dKb2JGdW5jdGlvblJlcXVlc3QaKS50YWlsb3IudjEuR2V0V29ya2Zsb3dKb2JGdW5jdGlvblJlc3BvbnNlIgOQAgEShAEKHEdldFdvcmtmbG93Sm9iRnVuY3Rpb25CeU5hbWUSLi50YWlsb3IudjEuR2V0V29ya2Zsb3dKb2JGdW5jdGlvbkJ5TmFtZVJlcXVlc3QaLy50YWlsb3IudjEuR2V0V29ya2Zsb3dKb2JGdW5jdGlvbkJ5TmFtZVJlc3BvbnNlIgOQAgESeAoYTGlzdFdvcmtmbG93Sm9iRnVuY3Rpb25zEioudGFpbG9yLnYxLkxpc3RXb3JrZmxvd0pvYkZ1bmN0aW9uc1JlcXVlc3QaKy50YWlsb3IudjEuTGlzdFdvcmtmbG93Sm9iRnVuY3Rpb25zUmVzcG9uc2UiA5ACARJsChRHZXRXb3JrZmxvd0V4ZWN1dGlvbhImLnRhaWxvci52MS5HZXRXb3JrZmxvd0V4ZWN1dGlvblJlcXVlc3QaJy50YWlsb3IudjEuR2V0V29ya2Zsb3dFeGVjdXRpb25SZXNwb25zZSIDkAIBEnIKFkxpc3RXb3JrZmxvd0V4ZWN1dGlvbnMSKC50YWlsb3IudjEuTGlzdFdvcmtmbG93RXhlY3V0aW9uc1JlcXVlc3QaKS50YWlsb3IudjEuTGlzdFdvcmtmbG93RXhlY3V0aW9uc1Jlc3BvbnNlIgOQAgESYAoRVGVzdFN0YXJ0V29ya2Zsb3cSIy50YWlsb3IudjEuVGVzdFN0YXJ0V29ya2Zsb3dSZXF1ZXN0GiQudGFpbG9yLnYxLlRlc3RTdGFydFdvcmtmbG93UmVzcG9uc2UiABJjChJUZXN0UmVzdW1lV29ya2Zsb3cSJC50YWlsb3IudjEuVGVzdFJlc3VtZVdvcmtmbG93UmVxdWVzdBolLnRhaWxvci52MS5UZXN0UmVzdW1lV29ya2Zsb3dSZXNwb25zZSIAEk4KC1NldE1ldGFkYXRhEh0udGFpbG9yLnYxLlNldE1ldGFkYXRhUmVxdWVzdBoeLnRhaWxvci52MS5TZXRNZXRhZGF0YVJlc3BvbnNlIgASUQoLR2V0TWV0YWRhdGESHS50YWlsb3IudjEuR2V0TWV0YWRhdGFSZXF1ZXN0Gh4udGFpbG9yLnYxLkdldE1ldGFkYXRhUmVzcG9uc2UiA5ACARKEAQodQ3JlYXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXISLy50YWlsb3IudjEuQ3JlYXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXF1ZXN0GjAudGFpbG9yLnYxLkNyZWF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVzcG9uc2UiABKEAQodVXBkYXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXISLy50YWlsb3IudjEuVXBkYXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXF1ZXN0GjAudGFpbG9yLnYxLlVwZGF0ZUNvbnRyb2xwbGFuZU1hY2hpbmVVc2VyUmVzcG9uc2UiABJ+ChpHZXRDb250cm9scGxhbmVNYWNoaW5lVXNlchIsLnRhaWxvci52MS5HZXRDb250cm9scGxhbmVNYWNoaW5lVXNlclJlcXVlc3QaLS50YWlsb3IudjEuR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXNwb25zZSIDkAIBEpABCiBHZXRDb250cm9scGxhbmVNYWNoaW5lVXNlckJ5TmFtZRIyLnRhaWxvci52MS5HZXRDb250cm9scGxhbmVNYWNoaW5lVXNlckJ5TmFtZVJlcXVlc3QaMy50YWlsb3IudjEuR2V0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJCeU5hbWVSZXNwb25zZSIDkAIBEoQBChxMaXN0Q29udHJvbHBsYW5lTWFjaGluZVVzZXJzEi4udGFpbG9yLnYxLkxpc3RDb250cm9scGxhbmVNYWNoaW5lVXNlcnNSZXF1ZXN0Gi8udGFpbG9yLnYxLkxpc3RDb250cm9scGxhbmVNYWNoaW5lVXNlcnNSZXNwb25zZSIDkAIBEoQBCh1EZWxldGVDb250cm9scGxhbmVNYWNoaW5lVXNlchIvLnRhaWxvci52MS5EZWxldGVDb250cm9scGxhbmVNYWNoaW5lVXNlclJlcXVlc3QaMC50YWlsb3IudjEuRGVsZXRlQ29udHJvbHBsYW5lTWFjaGluZVVzZXJSZXNwb25zZSIAEmwKFUNyZWF0ZVRlbGVtZXRyeUV4cG9ydBInLnRhaWxvci52MS5DcmVhdGVUZWxlbWV0cnlFeHBvcnRSZXF1ZXN0GigudGFpbG9yLnYxLkNyZWF0ZVRlbGVtZXRyeUV4cG9ydFJlc3BvbnNlIgASbAoVVXBkYXRlVGVsZW1ldHJ5RXhwb3J0EicudGFpbG9yLnYxLlVwZGF0ZVRlbGVtZXRyeUV4cG9ydFJlcXVlc3QaKC50YWlsb3IudjEuVXBkYXRlVGVsZW1ldHJ5RXhwb3J0UmVzcG9uc2UiABJmChJHZXRUZWxlbWV0cnlFeHBvcnQSJC50YWlsb3IudjEuR2V0VGVsZW1ldHJ5RXhwb3J0UmVxdWVzdBolLnRhaWxvci52MS5HZXRUZWxlbWV0cnlFeHBvcnRSZXNwb25zZSIDkAIBEmwKFExpc3RUZWxlbWV0cnlFeHBvcnRzEiYudGFpbG9yLnYxLkxpc3RUZWxlbWV0cnlFeHBvcnRzUmVxdWVzdBonLnRhaWxvci52MS5MaXN0VGVsZW1ldHJ5RXhwb3J0c1Jlc3BvbnNlIgOQAgESbAoVRGVsZXRlVGVsZW1ldHJ5RXhwb3J0EicudGFpbG9yLnYxLkRlbGV0ZVRlbGVtZXRyeUV4cG9ydFJlcXVlc3QaKC50YWlsb3IudjEuRGVsZXRlVGVsZW1ldHJ5RXhwb3J0UmVzcG9uc2UiABJmChNUZXN0VGVsZW1ldHJ5RXhwb3J0EiUudGFpbG9yLnYxLlRlc3RUZWxlbWV0cnlFeHBvcnRSZXF1ZXN0GiYudGFpbG9yLnYxLlRlc3RUZWxlbWV0cnlFeHBvcnRSZXNwb25zZSIAYgZwcm90bzM", [
857
867
  file_tailor_v1_application,
858
868
  file_tailor_v1_auth,
859
869
  file_tailor_v1_events,
@@ -2044,6 +2054,20 @@ function toCamelCase(str) {
2044
2054
  return result.charAt(0).toLowerCase() + result.slice(1);
2045
2055
  }
2046
2056
 
2057
+ //#endregion
2058
+ //#region src/cli/services/stale-cleanup.ts
2059
+ /**
2060
+ * Remove stale `.entry.js` files from the output directory.
2061
+ *
2062
+ * Must be called before parallel bundling; concurrent builds
2063
+ * sharing the same output directory would otherwise conflict.
2064
+ * @param outputDir - Directory to clean
2065
+ */
2066
+ async function removeStaleEntryFiles(outputDir) {
2067
+ const files = await fs.readdir(outputDir);
2068
+ await Promise.all(files.filter((file) => file.endsWith(".entry.js")).map((file) => fs.rm(path.join(outputDir, file), { force: true })));
2069
+ }
2070
+
2047
2071
  //#endregion
2048
2072
  //#region src/cli/services/file-loader.ts
2049
2073
  const DEFAULT_IGNORE_PATTERNS = ["**/*.test.ts", "**/*.spec.ts"];
@@ -2078,1232 +2102,1228 @@ function loadFilesWithIgnores(config) {
2078
2102
  }
2079
2103
 
2080
2104
  //#endregion
2081
- //#region src/parser/service/tailordb/hooks-validate-precompiled-expr.ts
2082
- const PRECOMPILED_EXPR_KEY = "__precompiledScriptExpr";
2105
+ //#region src/cli/services/workflow/ast-utils.ts
2083
2106
  /**
2084
- * Attach a precompiled script expression to a function object.
2085
- * @param fn - Function metadata object.
2086
- * @param expr - Precompiled script expression.
2107
+ * Check if a module source is from the Tailor SDK package (including subpaths)
2108
+ * @param source - Module source string
2109
+ * @returns True if the source is from the Tailor SDK package
2087
2110
  */
2088
- function setPrecompiledScriptExpr(fn, expr) {
2089
- fn[PRECOMPILED_EXPR_KEY] = expr;
2111
+ function isTailorSdkSource(source) {
2112
+ return /^@tailor-platform\/sdk(\/|$)/.test(source);
2090
2113
  }
2091
2114
  /**
2092
- * Read a precompiled script expression from a function object.
2093
- * @param fn - Function metadata object.
2094
- * @returns Precompiled script expression if attached.
2115
+ * Get the source string from a dynamic import or require call
2116
+ * @param node - AST node to inspect
2117
+ * @returns Resolved import/require source string or null
2095
2118
  */
2096
- function getPrecompiledScriptExpr(fn) {
2097
- const value = fn[PRECOMPILED_EXPR_KEY];
2098
- return typeof value === "string" ? value : void 0;
2119
+ function getImportSource(node) {
2120
+ if (!node) return null;
2121
+ if (node.type === "ImportExpression") {
2122
+ const source = node.source;
2123
+ if (source.type === "Literal" && typeof source.value === "string") return source.value;
2124
+ }
2125
+ if (node.type === "CallExpression") {
2126
+ const callExpr = node;
2127
+ if (callExpr.callee.type === "Identifier" && callExpr.callee.name === "require") {
2128
+ const arg = callExpr.arguments[0];
2129
+ if (arg && "type" in arg && arg.type === "Literal" && "value" in arg && typeof arg.value === "string") return arg.value;
2130
+ }
2131
+ }
2132
+ return null;
2099
2133
  }
2100
-
2101
- //#endregion
2102
- //#region src/parser/service/tailordb/field.ts
2103
- const tailorUserMap = `{ id: user.id, type: user.type, workspaceId: user.workspace_id, attributes: user.attribute_map, attributeList: user.attributes }`;
2104
2134
  /**
2105
- * Convert a function to a string representation.
2106
- * Handles method shorthand syntax (e.g., `create() { ... }`) by converting it to
2107
- * a function expression (e.g., `function create() { ... }`).
2108
- * @param fn - Function to stringify
2109
- * @returns Stringified function source
2135
+ * Unwrap AwaitExpression to get the inner expression
2136
+ * @param node - AST expression node
2137
+ * @returns Inner expression if node is an AwaitExpression
2110
2138
  */
2111
- const stringifyFunction = (fn) => {
2112
- const src = fn.toString().trim();
2113
- if (/^[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/.test(src) && !src.startsWith("function") && !src.startsWith("(") && !src.includes("=>")) return `function ${src}`;
2114
- return src;
2115
- };
2139
+ function unwrapAwait(node) {
2140
+ if (node?.type === "AwaitExpression") return node.argument;
2141
+ return node;
2142
+ }
2116
2143
  /**
2117
- * Convert a hook function to a script expression.
2118
- * @param fn - Hook function
2119
- * @returns JavaScript expression calling the hook
2144
+ * Check if a node is a string literal
2145
+ * @param node - AST expression node
2146
+ * @returns True if node is a string literal
2120
2147
  */
2121
- const convertHookToExpr = (fn) => {
2122
- const precompiledExpr = getPrecompiledScriptExpr(fn);
2123
- if (precompiledExpr) return precompiledExpr;
2124
- return `(${stringifyFunction(fn)})({ value: _value, data: _data, user: ${tailorUserMap} })`;
2125
- };
2148
+ function isStringLiteral(node) {
2149
+ return node?.type === "Literal" && typeof node.value === "string";
2150
+ }
2126
2151
  /**
2127
- * Parse TailorDBField into OperatorFieldConfig.
2128
- * This transforms user-defined functions into script expressions.
2129
- * @param field - TailorDB field definition
2130
- * @returns Parsed operator field configuration
2152
+ * Check if a node is a function expression (arrow or regular)
2153
+ * @param node - AST expression node
2154
+ * @returns True if node is a function expression
2131
2155
  */
2132
- function parseFieldConfig(field) {
2133
- const metadata = field.metadata;
2134
- const fieldType = field.type;
2135
- const rawRelation = field.rawRelation;
2136
- const nestedFields = field.fields;
2137
- return {
2138
- type: fieldType,
2139
- ...metadata,
2140
- rawRelation,
2141
- ...fieldType === "nested" && nestedFields && Object.keys(nestedFields).length > 0 ? { fields: Object.entries(nestedFields).reduce((acc, [key, nestedField]) => {
2142
- acc[key] = parseFieldConfig(nestedField);
2143
- return acc;
2144
- }, {}) } : {},
2145
- validate: metadata.validate?.map((v) => {
2146
- const { fn, message } = typeof v === "function" ? {
2147
- fn: v,
2148
- message: `failed by \`${v.toString().trim()}\``
2149
- } : {
2150
- fn: v[0],
2151
- message: v[1]
2152
- };
2153
- return {
2154
- script: { expr: getPrecompiledScriptExpr(fn) ?? `(${fn.toString().trim()})({ value: _value, data: _data, user: ${tailorUserMap} })` },
2155
- errorMessage: message
2156
- };
2157
- }),
2158
- hooks: metadata.hooks ? {
2159
- create: metadata.hooks.create ? { expr: convertHookToExpr(metadata.hooks.create) } : void 0,
2160
- update: metadata.hooks.update ? { expr: convertHookToExpr(metadata.hooks.update) } : void 0
2161
- } : void 0,
2162
- serial: metadata.serial ? {
2163
- start: metadata.serial.start,
2164
- maxValue: metadata.serial.maxValue,
2165
- format: "format" in metadata.serial ? metadata.serial.format : void 0
2166
- } : void 0
2167
- };
2168
- }
2169
-
2170
- //#endregion
2171
- //#region src/parser/service/tailordb/permission.ts
2172
- const operatorMap = {
2173
- "=": "eq",
2174
- "!=": "ne",
2175
- in: "in",
2176
- "not in": "nin",
2177
- hasAny: "hasAny",
2178
- "not hasAny": "nhasAny"
2179
- };
2180
- function normalizeOperand(operand) {
2181
- if (typeof operand === "object" && "user" in operand) return { user: operand.user === "id" ? "_id" : operand.user };
2182
- return operand;
2183
- }
2184
- function normalizeConditions(conditions) {
2185
- return conditions.map((cond) => {
2186
- const [left, operator, right] = cond;
2187
- return [
2188
- normalizeOperand(left),
2189
- operatorMap[operator],
2190
- normalizeOperand(right)
2191
- ];
2192
- });
2193
- }
2194
- function isObjectFormat(p) {
2195
- return typeof p === "object" && p !== null && "conditions" in p;
2196
- }
2197
- function isSingleArrayConditionFormat(cond) {
2198
- return cond.length >= 2 && typeof cond[1] === "string";
2156
+ function isFunctionExpression(node) {
2157
+ return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
2199
2158
  }
2200
2159
  /**
2201
- * Normalize record-level permissions into a standard structure.
2202
- * @param permission - Tailor type permission
2203
- * @returns Normalized record permissions
2160
+ * Find a property in an object expression
2161
+ * @param properties - Object properties to search
2162
+ * @param name - Property name to find
2163
+ * @returns Found property info or null
2204
2164
  */
2205
- function normalizePermission(permission) {
2206
- return Object.keys(permission).reduce((acc, action) => {
2207
- acc[action] = permission[action].map((p) => normalizeActionPermission(p));
2208
- return acc;
2209
- }, {});
2165
+ function findProperty(properties, name) {
2166
+ for (const prop of properties) if (prop.type === "Property") {
2167
+ const objProp = prop;
2168
+ if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === name) return {
2169
+ key: objProp.key,
2170
+ value: objProp.value,
2171
+ start: objProp.start,
2172
+ end: objProp.end
2173
+ };
2174
+ }
2175
+ return null;
2210
2176
  }
2211
2177
  /**
2212
- * Normalize GraphQL permissions into a standard structure.
2213
- * @param permission - Tailor GQL permission
2214
- * @returns Normalized GQL permissions
2178
+ * Apply string replacements to source code
2179
+ * Replacements are applied from end to start to maintain positions
2180
+ * @param source - Original source code
2181
+ * @param replacements - Replacements to apply
2182
+ * @returns Transformed source code
2215
2183
  */
2216
- function normalizeGqlPermission(permission) {
2217
- return permission.map((policy) => normalizeGqlPolicy(policy));
2218
- }
2219
- function normalizeGqlPolicy(policy) {
2220
- return {
2221
- conditions: policy.conditions ? normalizeConditions(policy.conditions) : [],
2222
- actions: policy.actions === "all" ? ["all"] : policy.actions,
2223
- permit: policy.permit ? "allow" : "deny",
2224
- description: policy.description
2225
- };
2184
+ function applyReplacements(source, replacements) {
2185
+ const sorted = [...replacements].sort((a, b) => b.start - a.start);
2186
+ let result = source;
2187
+ for (const r of sorted) result = result.slice(0, r.start) + r.text + result.slice(r.end);
2188
+ return result;
2226
2189
  }
2227
2190
  /**
2228
- * Parse raw permissions into normalized permissions.
2229
- * This is the main entry point for permission parsing in the parser layer.
2230
- * @param rawPermissions - Raw permissions definition
2231
- * @returns Normalized permissions
2191
+ * Find the end of a statement including any trailing newline
2192
+ * @param source - Source code
2193
+ * @param position - Start position of the statement
2194
+ * @returns Index of the end of the statement including trailing newline
2232
2195
  */
2233
- function parsePermissions(rawPermissions) {
2234
- return {
2235
- ...rawPermissions.record && { record: normalizePermission(rawPermissions.record) },
2236
- ...rawPermissions.gql && { gql: normalizeGqlPermission(rawPermissions.gql) }
2237
- };
2196
+ function findStatementEnd(source, position) {
2197
+ let i = position;
2198
+ while (i < source.length && (source[i] === ";" || source[i] === " " || source[i] === " ")) i++;
2199
+ if (i < source.length && source[i] === "\n") i++;
2200
+ return i;
2238
2201
  }
2239
2202
  /**
2240
- * Normalize a single action permission into the standard format.
2241
- * @param permission - Raw permission definition
2242
- * @returns Normalized action permission
2203
+ * Resolve a relative path from a base directory
2204
+ * Simple implementation that handles ./ and ../ prefixes
2205
+ * @param baseDir - Base directory
2206
+ * @param relativePath - Relative path to resolve
2207
+ * @returns Resolved absolute path
2243
2208
  */
2244
- function normalizeActionPermission(permission) {
2245
- if (isObjectFormat(permission)) {
2246
- const conditions = permission.conditions;
2247
- return {
2248
- conditions: normalizeConditions(isSingleArrayConditionFormat(conditions) ? [conditions] : conditions),
2249
- permit: permission.permit ? "allow" : "deny",
2250
- description: permission.description
2251
- };
2252
- }
2253
- if (!Array.isArray(permission)) throw new Error("Invalid permission format");
2254
- if (isSingleArrayConditionFormat(permission)) {
2255
- const [op1, operator, op2, permit] = [...permission, true];
2256
- return {
2257
- conditions: normalizeConditions([[
2258
- op1,
2259
- operator,
2260
- op2
2261
- ]]),
2262
- permit: permit ? "allow" : "deny"
2263
- };
2264
- }
2265
- const conditions = [];
2266
- const conditionArray = permission;
2267
- let conditionArrayPermit = true;
2268
- for (const item of conditionArray) {
2269
- if (typeof item === "boolean") {
2270
- conditionArrayPermit = item;
2271
- continue;
2272
- }
2273
- conditions.push(item);
2274
- }
2275
- return {
2276
- conditions: normalizeConditions(conditions),
2277
- permit: conditionArrayPermit ? "allow" : "deny"
2278
- };
2209
+ function resolvePath(baseDir, relativePath) {
2210
+ const parts = relativePath.replace(/\\/g, "/").split("/");
2211
+ const baseParts = baseDir.replace(/\\/g, "/").split("/");
2212
+ for (const part of parts) if (part === ".") {} else if (part === "..") baseParts.pop();
2213
+ else baseParts.push(part);
2214
+ return baseParts.join("/");
2279
2215
  }
2280
2216
 
2281
2217
  //#endregion
2282
- //#region src/parser/service/tailordb/relation.ts
2283
- const relationTypes = {
2284
- "1-1": "1-1",
2285
- oneToOne: "1-1",
2286
- "n-1": "n-1",
2287
- manyToOne: "n-1",
2288
- "N-1": "n-1",
2289
- keyOnly: "keyOnly"
2290
- };
2291
- const relationTypesKeys = Object.keys(relationTypes);
2292
- function fieldRef(context) {
2293
- return `Field "${context.fieldName}" on type "${context.typeName}"`;
2294
- }
2218
+ //#region src/cli/services/workflow/sdk-binding-collector.ts
2295
2219
  /**
2296
- * Validate relation configuration.
2297
- * @param rawRelation - Raw relation configuration from TailorDB type definition
2298
- * @param context - Context information for the relation (type name, field name, all type names)
2220
+ * Collect all import bindings for a specific function from the Tailor SDK package
2221
+ * Returns a Set of local names that refer to the function
2222
+ * @param program - Parsed TypeScript program
2223
+ * @param functionName - Function name to collect bindings for
2224
+ * @returns Set of local names bound to the SDK function
2299
2225
  */
2300
- function validateRelationConfig(rawRelation, context) {
2301
- if (!rawRelation.type) throw new Error(`${fieldRef(context)} has a relation but is missing the required 'type' property. Valid values: ${relationTypesKeys.join(", ")}.`);
2302
- if (!(rawRelation.type in relationTypes)) throw new Error(`${fieldRef(context)} has invalid relation type '${rawRelation.type}'. Valid values: ${relationTypesKeys.join(", ")}.`);
2303
- if (rawRelation.toward.type !== "self" && !context.allTypeNames.has(rawRelation.toward.type)) throw new Error(`${fieldRef(context)} references unknown type "${rawRelation.toward.type}".`);
2226
+ function collectSdkBindings(program, functionName) {
2227
+ const bindings = /* @__PURE__ */ new Set();
2228
+ function walk(node) {
2229
+ if (!node || typeof node !== "object") return;
2230
+ const nodeType = node.type;
2231
+ if (nodeType === "ImportDeclaration") {
2232
+ const importDecl = node;
2233
+ const source = importDecl.source?.value;
2234
+ if (typeof source === "string" && isTailorSdkSource(source)) {
2235
+ for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportSpecifier") {
2236
+ const importSpec = specifier;
2237
+ const imported = importSpec.imported.type === "Identifier" ? importSpec.imported.name : importSpec.imported.value;
2238
+ if (imported === functionName) bindings.add(importSpec.local?.name || imported);
2239
+ } else if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
2240
+ const spec = specifier;
2241
+ bindings.add(`__namespace__:${spec.local?.name}`);
2242
+ }
2243
+ }
2244
+ }
2245
+ if (nodeType === "VariableDeclaration") {
2246
+ const varDecl = node;
2247
+ for (const decl of varDecl.declarations || []) {
2248
+ const source = getImportSource(unwrapAwait(decl.init));
2249
+ if (source && isTailorSdkSource(source)) {
2250
+ const id = decl.id;
2251
+ if (id?.type === "Identifier") bindings.add(`__namespace__:${id.name}`);
2252
+ else if (id?.type === "ObjectPattern") {
2253
+ const objPattern = id;
2254
+ for (const prop of objPattern.properties || []) if (prop.type === "Property") {
2255
+ const bindingProp = prop;
2256
+ const keyName = bindingProp.key.type === "Identifier" ? bindingProp.key.name : bindingProp.key.value;
2257
+ if (keyName === functionName) {
2258
+ const localName = bindingProp.value.type === "Identifier" ? bindingProp.value.name : keyName;
2259
+ bindings.add(localName ?? "");
2260
+ }
2261
+ }
2262
+ }
2263
+ }
2264
+ }
2265
+ }
2266
+ for (const key of Object.keys(node)) {
2267
+ const child = node[key];
2268
+ if (Array.isArray(child)) child.forEach((c) => walk(c));
2269
+ else if (child && typeof child === "object") walk(child);
2270
+ }
2271
+ }
2272
+ walk(program);
2273
+ return bindings;
2304
2274
  }
2305
2275
  /**
2306
- * Process raw relation config and compute derived metadata values.
2307
- * @param rawRelation - Raw relation configuration
2308
- * @param context - Context information for the relation
2309
- * @param isArrayField - Whether the target field is an array field
2310
- * @returns Computed relation metadata to apply to field config
2276
+ * Check if a CallExpression is a call to a specific SDK function
2277
+ * @param node - AST node to inspect
2278
+ * @param bindings - Collected SDK bindings
2279
+ * @param functionName - SDK function name
2280
+ * @returns True if node is a call to the SDK function
2311
2281
  */
2312
- function processRelationMetadata(rawRelation, context, isArrayField = false) {
2313
- const isUnique = relationTypes[rawRelation.type] === "1-1";
2314
- const key = rawRelation.toward.key ?? "id";
2315
- const targetTypeName = rawRelation.toward.type === "self" ? context.typeName : rawRelation.toward.type;
2316
- const shouldSetIndex = !isArrayField;
2317
- const shouldSetUnique = !isArrayField && isUnique;
2318
- return {
2319
- index: shouldSetIndex,
2320
- foreignKey: true,
2321
- relationType: rawRelation.type,
2322
- unique: shouldSetUnique,
2323
- foreignKeyType: targetTypeName,
2324
- foreignKeyField: key
2325
- };
2282
+ function isSdkFunctionCall(node, bindings, functionName) {
2283
+ if (node.type !== "CallExpression") return false;
2284
+ const callee = node.callee;
2285
+ if (callee.type === "Identifier") {
2286
+ const identifier = callee;
2287
+ return bindings.has(identifier.name);
2288
+ }
2289
+ if (callee.type === "MemberExpression") {
2290
+ const memberExpr = callee;
2291
+ if (!memberExpr.computed) {
2292
+ const object = memberExpr.object;
2293
+ const property = memberExpr.property;
2294
+ if (object.type === "Identifier" && bindings.has(`__namespace__:${object.name}`) && property.name === functionName) return true;
2295
+ }
2296
+ }
2297
+ return false;
2326
2298
  }
2299
+
2300
+ //#endregion
2301
+ //#region src/cli/services/workflow/job-detector.ts
2327
2302
  /**
2328
- * Build relation info for creating forward/backward relationships.
2329
- * Returns undefined for keyOnly relations.
2330
- * @param rawRelation - Raw relation configuration
2331
- * @param context - Context information for the relation
2332
- * @returns Relation information or undefined for keyOnly relations
2303
+ * Find all workflow jobs by detecting createWorkflowJob calls from `@tailor-platform/sdk`
2304
+ * @param program - Parsed TypeScript program
2305
+ * @param _sourceText - Source code text (currently unused)
2306
+ * @returns Detected job locations
2333
2307
  */
2334
- function buildRelationInfo(rawRelation, context) {
2335
- if (rawRelation.type === "keyOnly") return;
2336
- const isUnique = relationTypes[rawRelation.type] === "1-1";
2337
- const key = rawRelation.toward.key ?? "id";
2338
- const targetTypeName = rawRelation.toward.type === "self" ? context.typeName : rawRelation.toward.type;
2339
- let forwardName = rawRelation.toward.as;
2340
- if (!forwardName) if (rawRelation.toward.type === "self") forwardName = context.fieldName.replace(/(ID|Id|id)$/u, "");
2341
- else forwardName = inflection.camelize(targetTypeName, true);
2342
- return {
2343
- targetType: targetTypeName,
2344
- forwardName,
2345
- backwardName: rawRelation.backward ?? "",
2346
- key,
2347
- unique: isUnique
2348
- };
2308
+ function findAllJobs(program, _sourceText) {
2309
+ const jobs = [];
2310
+ const bindings = collectSdkBindings(program, "createWorkflowJob");
2311
+ function walk(node, parents = []) {
2312
+ if (!node || typeof node !== "object") return;
2313
+ if (isSdkFunctionCall(node, bindings, "createWorkflowJob")) {
2314
+ const args = node.arguments;
2315
+ if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
2316
+ const configObj = args[0];
2317
+ const nameProp = findProperty(configObj.properties, "name");
2318
+ const bodyProp = findProperty(configObj.properties, "body");
2319
+ if (nameProp && isStringLiteral(nameProp.value) && bodyProp && isFunctionExpression(bodyProp.value)) {
2320
+ let statementRange;
2321
+ let exportName;
2322
+ for (let i = parents.length - 1; i >= 0; i--) {
2323
+ const parent = parents[i];
2324
+ if (parent.type === "VariableDeclarator") {
2325
+ const declarator = parent;
2326
+ if (declarator.id?.type === "Identifier") exportName = declarator.id.name;
2327
+ }
2328
+ if (parent.type === "ExportNamedDeclaration" || parent.type === "VariableDeclaration") statementRange = {
2329
+ start: parent.start,
2330
+ end: parent.end
2331
+ };
2332
+ }
2333
+ jobs.push({
2334
+ name: nameProp.value.value,
2335
+ exportName,
2336
+ nameRange: {
2337
+ start: nameProp.start,
2338
+ end: nameProp.end
2339
+ },
2340
+ bodyValueRange: {
2341
+ start: bodyProp.value.start,
2342
+ end: bodyProp.value.end
2343
+ },
2344
+ statementRange
2345
+ });
2346
+ }
2347
+ }
2348
+ }
2349
+ const newParents = [...parents, node];
2350
+ for (const key of Object.keys(node)) {
2351
+ const child = node[key];
2352
+ if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
2353
+ else if (child && typeof child === "object") walk(child, newParents);
2354
+ }
2355
+ }
2356
+ walk(program);
2357
+ return jobs;
2349
2358
  }
2350
2359
  /**
2351
- * Apply processed relation metadata to field config.
2352
- * @param fieldConfig - Original operator field configuration
2353
- * @param metadata - Processed relation metadata to apply
2354
- * @returns Field config with relation metadata applied
2360
+ * Build a map from export name to job name from detected jobs
2361
+ * @param jobs - Detected job locations
2362
+ * @returns Map from export name to job name
2355
2363
  */
2356
- function applyRelationMetadataToFieldConfig(fieldConfig, metadata) {
2357
- return {
2358
- ...fieldConfig,
2359
- index: metadata.index,
2360
- foreignKey: metadata.foreignKey,
2361
- unique: metadata.unique,
2362
- foreignKeyType: metadata.foreignKeyType,
2363
- foreignKeyField: metadata.foreignKeyField
2364
- };
2364
+ function buildJobNameMap(jobs) {
2365
+ const map = /* @__PURE__ */ new Map();
2366
+ for (const job of jobs) if (job.exportName) map.set(job.exportName, job.name);
2367
+ return map;
2365
2368
  }
2366
-
2367
- //#endregion
2368
- //#region src/parser/service/tailordb/type-parser.ts
2369
2369
  /**
2370
- * Parse multiple TailorDB types, build relationships, and validate uniqueness.
2371
- * This is the main entry point for parsing TailorDB types.
2372
- * @param rawTypes - Raw TailorDB types keyed by name
2373
- * @param namespace - TailorDB namespace name
2374
- * @param typeSourceInfo - Optional type source information
2375
- * @returns Parsed types
2370
+ * Detect all .trigger() calls in the source code
2371
+ * Returns information about each trigger call for transformation
2372
+ * @param program - Parsed TypeScript program
2373
+ * @param sourceText - Source code text
2374
+ * @returns Detected trigger calls
2376
2375
  */
2377
- function parseTypes(rawTypes, namespace, typeSourceInfo) {
2378
- const types = {};
2379
- const allTypeNames = new Set(Object.keys(rawTypes));
2380
- for (const [typeName, type] of Object.entries(rawTypes)) types[typeName] = parseTailorDBType(type, allTypeNames, rawTypes);
2381
- buildBackwardRelationships(types, namespace, typeSourceInfo);
2382
- validatePluralFormUniqueness(types, namespace, typeSourceInfo);
2383
- return types;
2376
+ function detectTriggerCalls(program, sourceText) {
2377
+ const calls = [];
2378
+ function walk(node, parent = null) {
2379
+ if (!node || typeof node !== "object") return;
2380
+ if (node.type === "CallExpression") {
2381
+ const callExpr = node;
2382
+ const callee = callExpr.callee;
2383
+ if (callee.type === "MemberExpression") {
2384
+ const memberExpr = callee;
2385
+ if (!memberExpr.computed && memberExpr.object.type === "Identifier" && memberExpr.property.name === "trigger") {
2386
+ const identifierName = memberExpr.object.name;
2387
+ let argsText = "";
2388
+ if (callExpr.arguments.length > 0) {
2389
+ const firstArg = callExpr.arguments[0];
2390
+ const lastArg = callExpr.arguments[callExpr.arguments.length - 1];
2391
+ if (firstArg && lastArg && "start" in firstArg && "end" in lastArg) argsText = sourceText.slice(firstArg.start, lastArg.end);
2392
+ }
2393
+ const hasAwait = parent?.type === "AwaitExpression";
2394
+ const awaitExpr = hasAwait ? parent : null;
2395
+ const callRange = {
2396
+ start: callExpr.start,
2397
+ end: callExpr.end
2398
+ };
2399
+ const fullRange = awaitExpr ? {
2400
+ start: awaitExpr.start,
2401
+ end: awaitExpr.end
2402
+ } : callRange;
2403
+ calls.push({
2404
+ identifierName,
2405
+ callRange,
2406
+ argsText,
2407
+ hasAwait,
2408
+ fullRange
2409
+ });
2410
+ }
2411
+ }
2412
+ }
2413
+ for (const key of Object.keys(node)) {
2414
+ const child = node[key];
2415
+ if (Array.isArray(child)) child.forEach((c) => walk(c, node));
2416
+ else if (child && typeof child === "object") walk(child, node);
2417
+ }
2418
+ }
2419
+ walk(program);
2420
+ return calls;
2384
2421
  }
2422
+
2423
+ //#endregion
2424
+ //#region src/cli/services/workflow/workflow-detector.ts
2385
2425
  /**
2386
- * Parse a TailorDBTypeSchemaOutput into a TailorDBType.
2387
- * @param type - TailorDB type to parse
2388
- * @param allTypeNames - Set of all TailorDB type names
2389
- * @param rawTypes - All raw TailorDB types keyed by name
2390
- * @returns Parsed TailorDB type
2426
+ * Find all workflows by detecting createWorkflow calls from `@tailor-platform/sdk`
2427
+ * @param program - Parsed TypeScript program
2428
+ * @param _sourceText - Source code text (currently unused)
2429
+ * @returns Detected workflows
2391
2430
  */
2392
- function parseTailorDBType(type, allTypeNames, rawTypes) {
2393
- const metadata = type.metadata;
2394
- const pluralForm = metadata.settings?.pluralForm || inflection.pluralize(type.name);
2395
- const fields = {};
2396
- const forwardRelationships = {};
2397
- for (const [fieldName, fieldDef] of Object.entries(type.fields)) {
2398
- let fieldConfig = parseFieldConfig(fieldDef);
2399
- const rawRelation = fieldConfig.rawRelation;
2400
- const context = {
2401
- typeName: type.name,
2402
- fieldName,
2403
- allTypeNames
2404
- };
2405
- if (rawRelation) {
2406
- validateRelationConfig(rawRelation, context);
2407
- if ([
2408
- "n-1",
2409
- "manyToOne",
2410
- "N-1"
2411
- ].includes(rawRelation.type) && fieldConfig.unique) throw new Error(`Field "${fieldName}" on type "${type.name}": cannot set unique on n-1 (manyToOne) relation. Use 1-1 (oneToOne) relation instead, or remove the unique constraint.`);
2412
- const relationMetadata = processRelationMetadata(rawRelation, context, fieldConfig.array);
2413
- fieldConfig = applyRelationMetadataToFieldConfig(fieldConfig, relationMetadata);
2431
+ function findAllWorkflows(program, _sourceText) {
2432
+ const workflows = [];
2433
+ const bindings = collectSdkBindings(program, "createWorkflow");
2434
+ function walk(node, parents = []) {
2435
+ if (!node || typeof node !== "object") return;
2436
+ if (isSdkFunctionCall(node, bindings, "createWorkflow")) {
2437
+ const args = node.arguments;
2438
+ if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
2439
+ const configObj = args[0];
2440
+ const nameProp = findProperty(configObj.properties, "name");
2441
+ if (nameProp && isStringLiteral(nameProp.value)) {
2442
+ let exportName;
2443
+ let isDefaultExport = false;
2444
+ for (let i = parents.length - 1; i >= 0; i--) {
2445
+ const parent = parents[i];
2446
+ if (parent.type === "VariableDeclarator") {
2447
+ const declarator = parent;
2448
+ if (declarator.id?.type === "Identifier") {
2449
+ exportName = declarator.id.name;
2450
+ break;
2451
+ }
2452
+ }
2453
+ if (parent.type === "ExportDefaultDeclaration") isDefaultExport = true;
2454
+ }
2455
+ workflows.push({
2456
+ name: nameProp.value.value,
2457
+ exportName,
2458
+ isDefaultExport
2459
+ });
2460
+ }
2461
+ }
2414
2462
  }
2415
- if (fieldConfig.array && fieldConfig.index) throw new Error(`Field "${fieldName}" on type "${type.name}": index cannot be set on array fields`);
2416
- if (fieldConfig.array && fieldConfig.unique) throw new Error(`Field "${fieldName}" on type "${type.name}": unique cannot be set on array fields`);
2417
- const parsedField = {
2418
- name: fieldName,
2419
- config: fieldConfig
2420
- };
2421
- const relationInfo = rawRelation ? buildRelationInfo(rawRelation, context) : void 0;
2422
- if (relationInfo) {
2423
- parsedField.relation = { ...relationInfo };
2424
- const targetType = rawTypes[relationInfo.targetType];
2425
- forwardRelationships[relationInfo.forwardName] = {
2426
- name: relationInfo.forwardName,
2427
- targetType: relationInfo.targetType,
2428
- targetField: fieldName,
2429
- sourceField: relationInfo.key,
2430
- isArray: false,
2431
- description: targetType?.metadata?.description || ""
2432
- };
2463
+ const newParents = [...parents, node];
2464
+ for (const key of Object.keys(node)) {
2465
+ const child = node[key];
2466
+ if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
2467
+ else if (child && typeof child === "object") walk(child, newParents);
2433
2468
  }
2434
- fields[fieldName] = parsedField;
2435
2469
  }
2436
- return {
2437
- name: type.name,
2438
- pluralForm,
2439
- description: metadata.description,
2440
- fields,
2441
- forwardRelationships,
2442
- backwardRelationships: {},
2443
- settings: metadata.settings || {},
2444
- permissions: parsePermissions(metadata.permissions || {}),
2445
- indexes: metadata.indexes,
2446
- files: metadata.files
2447
- };
2470
+ walk(program);
2471
+ return workflows;
2448
2472
  }
2449
2473
  /**
2450
- * Build backward relationships between parsed types.
2451
- * Also validates that backward relation names are unique within each type.
2452
- * @param types - Parsed types
2453
- * @param namespace - TailorDB namespace name
2454
- * @param typeSourceInfo - Optional type source information
2474
+ * Build a map from export name to workflow name from detected workflows
2475
+ * @param workflows - Detected workflows
2476
+ * @returns Map from export name to workflow name
2455
2477
  */
2456
- function buildBackwardRelationships(types, namespace, typeSourceInfo) {
2457
- const backwardNameSources = {};
2458
- for (const typeName of Object.keys(types)) backwardNameSources[typeName] = {};
2459
- for (const [typeName, type] of Object.entries(types)) for (const [otherTypeName, otherType] of Object.entries(types)) for (const [fieldName, field] of Object.entries(otherType.fields)) if (field.relation && field.relation.targetType === typeName) {
2460
- let backwardName = field.relation.backwardName;
2461
- if (!backwardName) {
2462
- const lowerName = inflection.camelize(otherTypeName, true);
2463
- backwardName = field.relation.unique ? inflection.singularize(lowerName) : inflection.pluralize(lowerName);
2464
- }
2465
- if (!backwardNameSources[typeName][backwardName]) backwardNameSources[typeName][backwardName] = [];
2466
- backwardNameSources[typeName][backwardName].push({
2467
- sourceType: otherTypeName,
2468
- fieldName
2469
- });
2470
- type.backwardRelationships[backwardName] = {
2471
- name: backwardName,
2472
- targetType: otherTypeName,
2473
- targetField: fieldName,
2474
- sourceField: field.relation.key,
2475
- isArray: !field.relation.unique,
2476
- description: otherType.description || ""
2477
- };
2478
- }
2479
- const errors = [];
2480
- for (const [targetTypeName, backwardNames] of Object.entries(backwardNameSources)) {
2481
- const targetType = types[targetTypeName];
2482
- const targetTypeSourceInfo = typeSourceInfo?.[targetTypeName];
2483
- const targetLocation = targetTypeSourceInfo ? isPluginGeneratedType(targetTypeSourceInfo) ? ` (plugin: ${targetTypeSourceInfo.pluginId})` : ` (${targetTypeSourceInfo.filePath})` : "";
2484
- for (const [backwardName, sources] of Object.entries(backwardNames)) {
2485
- if (sources.length > 1) {
2486
- const sourceList = sources.map((s) => {
2487
- const sourceInfo = typeSourceInfo?.[s.sourceType];
2488
- const location = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
2489
- return `${s.sourceType}.${s.fieldName}${location}`;
2490
- }).join(", ");
2491
- errors.push(`Backward relation name "${backwardName}" on type "${targetTypeName}" is duplicated from: ${sourceList}. Use the "backward" option in .relation() to specify unique names.`);
2492
- }
2493
- if (backwardName in targetType.fields) {
2494
- const source = sources[0];
2495
- const sourceInfo = typeSourceInfo?.[source.sourceType];
2496
- const sourceLocation = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
2497
- errors.push(`Backward relation name "${backwardName}" from ${source.sourceType}.${source.fieldName}${sourceLocation} conflicts with existing field "${backwardName}" on type "${targetTypeName}"${targetLocation}. Use the "backward" option in .relation() to specify a different name.`);
2498
- }
2499
- if (targetType.files && backwardName in targetType.files) {
2500
- const source = sources[0];
2501
- const sourceInfo = typeSourceInfo?.[source.sourceType];
2502
- const sourceLocation = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
2503
- errors.push(`Backward relation name "${backwardName}" from ${source.sourceType}.${source.fieldName}${sourceLocation} conflicts with files field "${backwardName}" on type "${targetTypeName}"${targetLocation}. Use the "backward" option in .relation() to specify a different name.`);
2478
+ function buildWorkflowNameMap(workflows) {
2479
+ const map = /* @__PURE__ */ new Map();
2480
+ for (const workflow of workflows) if (workflow.exportName) map.set(workflow.exportName, workflow.name);
2481
+ return map;
2482
+ }
2483
+ /**
2484
+ * Detect default imports in a source file and return a map from local name to import source
2485
+ * @param program - Parsed TypeScript program
2486
+ * @returns Map from local name to import source
2487
+ */
2488
+ function detectDefaultImports(program) {
2489
+ const imports = /* @__PURE__ */ new Map();
2490
+ function walk(node) {
2491
+ if (!node || typeof node !== "object") return;
2492
+ if (node.type === "ImportDeclaration") {
2493
+ const importDecl = node;
2494
+ const source = importDecl.source?.value;
2495
+ if (typeof source === "string") {
2496
+ for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportDefaultSpecifier") {
2497
+ const spec = specifier;
2498
+ if (spec.local?.name) imports.set(spec.local.name, source);
2499
+ }
2504
2500
  }
2505
2501
  }
2502
+ for (const key of Object.keys(node)) {
2503
+ const child = node[key];
2504
+ if (Array.isArray(child)) child.forEach((c) => walk(c));
2505
+ else if (child && typeof child === "object") walk(child);
2506
+ }
2506
2507
  }
2507
- if (errors.length > 0) throw new Error(`Backward relation name conflicts detected in TailorDB service "${namespace}".\n${errors.map((e) => ` - ${e}`).join("\n")}`);
2508
+ walk(program);
2509
+ return imports;
2508
2510
  }
2511
+
2512
+ //#endregion
2513
+ //#region src/cli/services/workflow/trigger-transformer.ts
2509
2514
  /**
2510
- * Validate GraphQL query field name uniqueness.
2511
- * Checks for:
2512
- * 1. Each type's singular query name != plural query name
2513
- * 2. No duplicate query names across all types
2514
- * @param types - Parsed types
2515
- * @param namespace - TailorDB namespace name
2516
- * @param typeSourceInfo - Optional type source information
2515
+ * Extract authInvoker info from a config object expression
2516
+ * Returns the authInvoker value text and whether it's a shorthand property
2517
+ * @param configArg - Config argument node
2518
+ * @param sourceText - Source code text
2519
+ * @returns Extracted authInvoker info, if any
2517
2520
  */
2518
- function validatePluralFormUniqueness(types, namespace, typeSourceInfo) {
2519
- const errors = [];
2520
- for (const [, parsedType] of Object.entries(types)) {
2521
- const singularQuery = inflection.camelize(parsedType.name, true);
2522
- if (singularQuery === inflection.camelize(parsedType.pluralForm, true)) {
2523
- const sourceInfo = typeSourceInfo?.[parsedType.name];
2524
- const location = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
2525
- errors.push(`Type "${parsedType.name}"${location} has identical singular and plural query names "${singularQuery}". Use db.type(["${parsedType.name}", "UniquePluralForm"], {...}) to set a unique pluralForm.`);
2521
+ function extractAuthInvokerInfo(configArg, sourceText) {
2522
+ if (!configArg || typeof configArg !== "object") return void 0;
2523
+ if (configArg.type !== "ObjectExpression") return void 0;
2524
+ const objExpr = configArg;
2525
+ for (const prop of objExpr.properties) {
2526
+ if (prop.type !== "Property") continue;
2527
+ const objProp = prop;
2528
+ if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === "authInvoker") {
2529
+ if (objProp.shorthand) return {
2530
+ isShorthand: true,
2531
+ valueText: "authInvoker"
2532
+ };
2533
+ return {
2534
+ isShorthand: false,
2535
+ valueText: sourceText.slice(objProp.value.start, objProp.value.end)
2536
+ };
2526
2537
  }
2527
2538
  }
2528
- const queryNameToSource = {};
2529
- for (const parsedType of Object.values(types)) {
2530
- const singularQuery = inflection.camelize(parsedType.name, true);
2531
- const pluralQuery = inflection.camelize(parsedType.pluralForm, true);
2532
- if (!queryNameToSource[singularQuery]) queryNameToSource[singularQuery] = [];
2533
- queryNameToSource[singularQuery].push({
2534
- typeName: parsedType.name,
2535
- kind: "singular"
2536
- });
2537
- if (singularQuery !== pluralQuery) {
2538
- if (!queryNameToSource[pluralQuery]) queryNameToSource[pluralQuery] = [];
2539
- queryNameToSource[pluralQuery].push({
2540
- typeName: parsedType.name,
2541
- kind: "plural"
2542
- });
2539
+ }
2540
+ /**
2541
+ * Detect .trigger() calls for known workflows and jobs
2542
+ * Only detects calls where the identifier is in workflowNames or jobNames
2543
+ * @param program - The parsed AST program
2544
+ * @param sourceText - The source code text
2545
+ * @param workflowNames - Set of known workflow identifier names
2546
+ * @param jobNames - Set of known job identifier names
2547
+ * @returns Detected trigger call metadata
2548
+ */
2549
+ function detectExtendedTriggerCalls(program, sourceText, workflowNames, jobNames) {
2550
+ const calls = [];
2551
+ function walk(node, parent = null) {
2552
+ if (!node || typeof node !== "object") return;
2553
+ if (node.type === "CallExpression") {
2554
+ const callExpr = node;
2555
+ const callee = callExpr.callee;
2556
+ if (callee.type === "MemberExpression") {
2557
+ const memberExpr = callee;
2558
+ if (!memberExpr.computed && memberExpr.object.type === "Identifier" && memberExpr.property.name === "trigger") {
2559
+ const identifierName = memberExpr.object.name;
2560
+ const isWorkflow = workflowNames.has(identifierName);
2561
+ const isJob = jobNames.has(identifierName);
2562
+ if (!isWorkflow && !isJob) return;
2563
+ const argCount = callExpr.arguments.length;
2564
+ let argsText = "";
2565
+ if (argCount > 0) {
2566
+ const firstArg = callExpr.arguments[0];
2567
+ if (firstArg && "start" in firstArg && "end" in firstArg) argsText = sourceText.slice(firstArg.start, firstArg.end);
2568
+ }
2569
+ const hasAwait = parent?.type === "AwaitExpression";
2570
+ const awaitExpr = hasAwait ? parent : null;
2571
+ if (isWorkflow && argCount >= 2) {
2572
+ const secondArg = callExpr.arguments[1];
2573
+ const authInvoker = extractAuthInvokerInfo(secondArg, sourceText);
2574
+ if (authInvoker) calls.push({
2575
+ kind: "workflow",
2576
+ identifierName,
2577
+ callRange: {
2578
+ start: callExpr.start,
2579
+ end: callExpr.end
2580
+ },
2581
+ argsText,
2582
+ authInvoker,
2583
+ hasAwait: false
2584
+ });
2585
+ } else if (isJob) calls.push({
2586
+ kind: "job",
2587
+ identifierName,
2588
+ callRange: {
2589
+ start: callExpr.start,
2590
+ end: callExpr.end
2591
+ },
2592
+ argsText,
2593
+ hasAwait,
2594
+ fullRange: awaitExpr ? {
2595
+ start: awaitExpr.start,
2596
+ end: awaitExpr.end
2597
+ } : void 0
2598
+ });
2599
+ }
2600
+ }
2601
+ }
2602
+ for (const key of Object.keys(node)) {
2603
+ const child = node[key];
2604
+ if (Array.isArray(child)) child.forEach((c) => walk(c, node));
2605
+ else if (child && typeof child === "object") walk(child, node);
2543
2606
  }
2544
2607
  }
2545
- const duplicates = Object.entries(queryNameToSource).filter(([, sources]) => sources.length > 1);
2546
- for (const [queryName, sources] of duplicates) {
2547
- const sourceList = sources.map((s) => {
2548
- const sourceInfo = typeSourceInfo?.[s.typeName];
2549
- const location = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
2550
- return `"${s.typeName}"${location} (${s.kind})`;
2551
- }).join(", ");
2552
- errors.push(`GraphQL query field "${queryName}" conflicts between: ${sourceList}`);
2608
+ walk(program);
2609
+ return calls;
2610
+ }
2611
+ /**
2612
+ * Transform trigger calls for resolver/executor/workflow functions
2613
+ * Handles both job.trigger() and workflow.trigger() calls
2614
+ * @param source - The source code to transform
2615
+ * @param workflowNameMap - Map from variable name to workflow name
2616
+ * @param jobNameMap - Map from variable name to job name
2617
+ * @param workflowFileMap - Map from file path (without extension) to workflow name for default exports
2618
+ * @param currentFilePath - Path of the current file being transformed (for resolving relative imports)
2619
+ * @returns Transformed source code with trigger calls rewritten
2620
+ */
2621
+ function transformFunctionTriggers(source, workflowNameMap, jobNameMap, workflowFileMap, currentFilePath) {
2622
+ const { program } = parseSync("input.ts", source);
2623
+ const localWorkflowNameMap = new Map(workflowNameMap);
2624
+ if (workflowFileMap && currentFilePath) {
2625
+ const defaultImports = detectDefaultImports(program);
2626
+ const currentDir = currentFilePath.replace(/[/\\][^/\\]+$/, "");
2627
+ for (const [localName, importSource] of defaultImports) {
2628
+ if (!importSource.startsWith(".")) continue;
2629
+ const resolvedPath = resolvePath(currentDir, importSource);
2630
+ const workflowName = workflowFileMap.get(resolvedPath);
2631
+ if (workflowName) localWorkflowNameMap.set(localName, workflowName);
2632
+ }
2553
2633
  }
2554
- if (errors.length > 0) throw new Error(`GraphQL field name conflicts detected in TailorDB service "${namespace}".\n${errors.map((e) => ` - ${e}`).join("\n")}`);
2634
+ const triggerCalls = detectExtendedTriggerCalls(program, source, new Set(localWorkflowNameMap.keys()), new Set(jobNameMap.keys()));
2635
+ const replacements = [];
2636
+ for (const call of triggerCalls) if (call.kind === "workflow" && call.authInvoker) {
2637
+ const workflowName = localWorkflowNameMap.get(call.identifierName);
2638
+ if (workflowName) {
2639
+ const authInvokerExpr = call.authInvoker.isShorthand ? "authInvoker" : call.authInvoker.valueText;
2640
+ const transformedCall = `tailor.workflow.triggerWorkflow("${workflowName}", ${call.argsText || "undefined"}, { authInvoker: ${authInvokerExpr} })`;
2641
+ replacements.push({
2642
+ start: call.callRange.start,
2643
+ end: call.callRange.end,
2644
+ text: transformedCall
2645
+ });
2646
+ }
2647
+ } else if (call.kind === "job") {
2648
+ const jobName = jobNameMap.get(call.identifierName);
2649
+ if (jobName) {
2650
+ const transformedCall = `tailor.workflow.triggerJobFunction("${jobName}", ${call.argsText || "undefined"})`;
2651
+ const range = call.hasAwait && call.fullRange ? call.fullRange : call.callRange;
2652
+ replacements.push({
2653
+ start: range.start,
2654
+ end: range.end,
2655
+ text: transformedCall
2656
+ });
2657
+ }
2658
+ }
2659
+ return applyReplacements(source, replacements);
2555
2660
  }
2556
2661
 
2557
2662
  //#endregion
2558
- //#region src/parser/service/common.ts
2559
- const functionSchema = z.custom((val) => typeof val === "function");
2560
-
2561
- //#endregion
2562
- //#region src/parser/service/tailordb/schema.ts
2663
+ //#region src/cli/shared/trigger-context.ts
2563
2664
  /**
2564
- * Normalize GqlOperationsConfig (alias or object) to GqlOperations object.
2565
- * "query" alias expands to read-only mode: { create: false, update: false, delete: false, read: true }
2566
- * @param config - The config to normalize
2567
- * @returns The normalized GqlOperations object
2665
+ * Normalize a file path by removing extension and resolving to absolute path
2666
+ * @param filePath - File path to normalize
2667
+ * @returns Normalized absolute path without extension
2568
2668
  */
2569
- function normalizeGqlOperations(config) {
2570
- if (config === "query") return {
2571
- create: false,
2572
- update: false,
2573
- delete: false,
2574
- read: true
2669
+ function normalizeFilePath(filePath) {
2670
+ const absolutePath = path.resolve(filePath);
2671
+ const ext = path.extname(absolutePath);
2672
+ return absolutePath.slice(0, -ext.length);
2673
+ }
2674
+ /**
2675
+ * Build trigger context from workflow configuration
2676
+ * Scans workflow files to collect workflow and job mappings
2677
+ * @param workflowConfig - Workflow file loading configuration
2678
+ * @returns Trigger context built from workflow sources
2679
+ */
2680
+ async function buildTriggerContext(workflowConfig) {
2681
+ const workflowNameMap = /* @__PURE__ */ new Map();
2682
+ const jobNameMap = /* @__PURE__ */ new Map();
2683
+ const workflowFileMap = /* @__PURE__ */ new Map();
2684
+ if (!workflowConfig) return {
2685
+ workflowNameMap,
2686
+ jobNameMap,
2687
+ workflowFileMap
2575
2688
  };
2576
- return config;
2689
+ const workflowFiles = loadFilesWithIgnores(workflowConfig);
2690
+ for (const file of workflowFiles) try {
2691
+ const source = await fs$1.promises.readFile(file, "utf-8");
2692
+ const { program } = parseSync("input.ts", source);
2693
+ const workflows = findAllWorkflows(program, source);
2694
+ const workflowMap = buildWorkflowNameMap(workflows);
2695
+ for (const [exportName, workflowName] of workflowMap) workflowNameMap.set(exportName, workflowName);
2696
+ for (const workflow of workflows) if (workflow.isDefaultExport) {
2697
+ const normalizedPath = normalizeFilePath(file);
2698
+ workflowFileMap.set(normalizedPath, workflow.name);
2699
+ }
2700
+ const jobMap = buildJobNameMap(findAllJobs(program, source));
2701
+ for (const [exportName, jobName] of jobMap) jobNameMap.set(exportName, jobName);
2702
+ } catch (error) {
2703
+ const errorMessage = error instanceof Error ? error.message : String(error);
2704
+ logger.warn(`Failed to process workflow file ${file}: ${errorMessage}`, { mode: "stream" });
2705
+ continue;
2706
+ }
2707
+ return {
2708
+ workflowNameMap,
2709
+ jobNameMap,
2710
+ workflowFileMap
2711
+ };
2712
+ }
2713
+ function sortedMapToJson(m) {
2714
+ return JSON.stringify([...m.entries()].sort(([a], [b]) => a.localeCompare(b)));
2577
2715
  }
2578
2716
  /**
2579
- * Zod schema for GqlOperations configuration with normalization transform.
2580
- * Accepts "query" alias or detailed object, normalizes to GqlOperations object.
2717
+ * Serialize trigger context to a deterministic string for cache hashing.
2718
+ * Returns an empty string if no context is provided.
2719
+ * @param ctx - Trigger context to serialize
2720
+ * @returns Deterministic string representation
2581
2721
  */
2582
- const GqlOperationsSchema = z.union([z.literal("query"), z.object({
2583
- create: z.boolean().optional().describe("Enable create mutation (default: true)"),
2584
- update: z.boolean().optional().describe("Enable update mutation (default: true)"),
2585
- delete: z.boolean().optional().describe("Enable delete mutation (default: true)"),
2586
- read: z.boolean().optional().describe("Enable read queries - get, list, aggregation (default: true)")
2587
- })]).describe("Configuration for GraphQL operations on a TailorDB type.\nAll operations are enabled by default (undefined or true = enabled, false = disabled).").transform((val) => normalizeGqlOperations(val));
2588
- const TailorFieldTypeSchema$1 = z.enum([
2589
- "uuid",
2590
- "string",
2591
- "boolean",
2592
- "integer",
2593
- "float",
2594
- "decimal",
2595
- "enum",
2596
- "date",
2597
- "datetime",
2598
- "time",
2599
- "nested"
2600
- ]);
2601
- const AllowedValueSchema$1 = z.object({
2602
- value: z.string(),
2603
- description: z.string().optional()
2604
- });
2605
- const DBFieldMetadataSchema = z.object({
2606
- required: z.boolean().optional().describe("Whether the field is required"),
2607
- array: z.boolean().optional().describe("Whether the field is an array"),
2608
- description: z.string().optional().describe("Field description"),
2609
- typeName: z.string().optional().describe("Type name for nested or enum fields"),
2610
- allowedValues: z.array(AllowedValueSchema$1).optional().describe("Allowed values for enum fields"),
2611
- index: z.boolean().optional().describe("Whether the field is indexed for faster queries"),
2612
- unique: z.boolean().optional().describe("Whether the field value must be unique"),
2613
- vector: z.boolean().optional().describe("Whether the field is a vector field for similarity search"),
2614
- foreignKey: z.boolean().optional().describe("Whether the field is a foreign key"),
2615
- foreignKeyType: z.string().optional().describe("Target type name for foreign key relations"),
2616
- foreignKeyField: z.string().optional().describe("Target field name for foreign key relations"),
2617
- hooks: z.object({
2618
- create: functionSchema.optional().describe("Hook function called on record creation"),
2619
- update: functionSchema.optional().describe("Hook function called on record update")
2620
- }).optional().describe("Lifecycle hooks for the field"),
2621
- validate: z.array(z.union([functionSchema, z.tuple([functionSchema, z.string()])])).optional().describe("Validation functions for the field"),
2622
- serial: z.object({
2623
- start: z.number().describe("Starting value for the serial sequence"),
2624
- maxValue: z.number().optional().describe("Maximum value for the serial sequence"),
2625
- format: z.string().optional().describe("Format string for serial value (string type only)")
2626
- }).optional().describe("Serial (auto-increment) configuration"),
2627
- scale: z.number().int().min(0).max(12).optional().describe("Decimal scale (number of digits after decimal point, 0-12)")
2628
- });
2629
- const RelationTypeSchema = z.enum(relationTypesKeys);
2630
- const RawRelationConfigSchema = z.object({
2631
- type: RelationTypeSchema.describe("Relation cardinality type"),
2632
- toward: z.object({
2633
- type: z.string().describe("Target type name, or 'self' for self-relations"),
2634
- as: z.string().optional().describe("Custom forward relation name"),
2635
- key: z.string().optional().describe("Target field to join on (default: 'id')")
2636
- }),
2637
- backward: z.string().optional().describe("Backward relation name on the target type")
2638
- });
2639
- const TailorDBFieldSchema = z.lazy(() => z.object({
2640
- type: TailorFieldTypeSchema$1,
2641
- fields: z.record(z.string(), TailorDBFieldSchema).optional(),
2642
- metadata: DBFieldMetadataSchema,
2643
- rawRelation: RawRelationConfigSchema.optional()
2644
- }));
2645
- /**
2646
- * Schema for TailorDB type settings.
2647
- * Normalizes gqlOperations from alias ("query") to object format.
2648
- */
2649
- const TailorDBTypeSettingsSchema = z.object({
2650
- pluralForm: z.string().optional().describe("Custom plural form of the type name for GraphQL"),
2651
- aggregation: z.boolean().optional().describe("Enable aggregation queries for this type"),
2652
- bulkUpsert: z.boolean().optional().describe("Enable bulk upsert mutation for this type"),
2653
- gqlOperations: GqlOperationsSchema.optional().describe("Configure GraphQL operations for this type. Use \"query\" for read-only mode, or an object for granular control."),
2654
- publishEvents: z.boolean().optional().describe("Enable publishing events for this type.\nWhen enabled, record creation/update/deletion events are published.\nIf not specified, this is automatically set to true when an executor uses this type\nwith recordCreated/recordUpdated/recordDeleted triggers. If explicitly set to false\nwhile an executor uses this type, an error will be thrown during apply.")
2655
- });
2656
- const GQL_PERMISSION_INVALID_OPERAND_MESSAGE = "operand is not supported in gqlPermission. Use permission() for record-level conditions.";
2657
- const GqlPermissionOperandSchema = z.union([
2658
- z.object({ user: z.string() }).strict(),
2659
- z.string(),
2660
- z.boolean(),
2661
- z.array(z.string()),
2662
- z.array(z.boolean())
2663
- ], { error: (issue) => {
2664
- if (typeof issue.input === "object" && issue.input !== null) {
2665
- const keys = Object.keys(issue.input);
2666
- if (keys.length === 1) return `"${keys[0]}" ${GQL_PERMISSION_INVALID_OPERAND_MESSAGE}`;
2667
- return "Operand object must have exactly 1 key";
2668
- }
2669
- return "Invalid operand in gqlPermission";
2670
- } });
2671
- const RecordPermissionOperandSchema = z.union([
2672
- GqlPermissionOperandSchema,
2673
- z.object({ record: z.string() }),
2674
- z.object({ oldRecord: z.string() }),
2675
- z.object({ newRecord: z.string() })
2676
- ]);
2677
- const PermissionOperatorSchema = z.enum([
2678
- "=",
2679
- "!=",
2680
- "in",
2681
- "not in",
2682
- "hasAny",
2683
- "not hasAny"
2684
- ]);
2685
- const RecordPermissionConditionSchema = z.tuple([
2686
- RecordPermissionOperandSchema,
2687
- PermissionOperatorSchema,
2688
- RecordPermissionOperandSchema
2689
- ]).readonly();
2690
- const GqlPermissionConditionSchema = z.tuple([
2691
- GqlPermissionOperandSchema,
2692
- PermissionOperatorSchema,
2693
- GqlPermissionOperandSchema
2694
- ]).readonly();
2695
- const ActionPermissionSchema = z.union([
2696
- z.object({
2697
- conditions: z.union([RecordPermissionConditionSchema, z.array(RecordPermissionConditionSchema).readonly()]),
2698
- description: z.string().optional(),
2699
- permit: z.boolean().optional()
2700
- }),
2701
- z.tuple([
2702
- RecordPermissionOperandSchema,
2703
- PermissionOperatorSchema,
2704
- RecordPermissionOperandSchema
2705
- ]).readonly(),
2706
- z.tuple([
2707
- RecordPermissionOperandSchema,
2708
- PermissionOperatorSchema,
2709
- RecordPermissionOperandSchema,
2710
- z.boolean()
2711
- ]).readonly(),
2712
- z.array(z.union([RecordPermissionConditionSchema, z.boolean()])).refine((arr) => {
2713
- const boolIndex = arr.findIndex((item) => typeof item === "boolean");
2714
- return boolIndex === -1 || boolIndex === arr.length - 1;
2715
- }, { message: "Boolean permit flag must only appear at the end" }).readonly()
2716
- ]);
2717
- const GqlPermissionActionSchema = z.enum([
2718
- "read",
2719
- "create",
2720
- "update",
2721
- "delete",
2722
- "aggregate",
2723
- "bulkUpsert"
2724
- ]);
2725
- const GqlPermissionPolicySchema = z.object({
2726
- conditions: z.array(GqlPermissionConditionSchema).readonly(),
2727
- actions: z.union([z.literal("all"), z.array(GqlPermissionActionSchema).readonly()]),
2728
- permit: z.boolean().optional(),
2729
- description: z.string().optional()
2730
- });
2731
- const RawPermissionsSchema = z.object({
2732
- record: z.object({
2733
- create: z.array(ActionPermissionSchema).readonly(),
2734
- read: z.array(ActionPermissionSchema).readonly(),
2735
- update: z.array(ActionPermissionSchema).readonly(),
2736
- delete: z.array(ActionPermissionSchema).readonly()
2737
- }).optional(),
2738
- gql: z.array(GqlPermissionPolicySchema).readonly().optional()
2739
- });
2740
- const TailorDBTypeSchema = z.object({
2741
- name: z.string(),
2742
- fields: z.record(z.string(), TailorDBFieldSchema),
2743
- metadata: z.object({
2744
- name: z.string(),
2745
- description: z.string().optional(),
2746
- settings: TailorDBTypeSettingsSchema.optional(),
2747
- permissions: RawPermissionsSchema,
2748
- files: z.record(z.string(), z.string()),
2749
- indexes: z.record(z.string(), z.object({
2750
- fields: z.array(z.string()),
2751
- unique: z.boolean().optional()
2752
- })).optional()
2753
- })
2754
- });
2755
- const TailorDBMigrationConfigSchema = z.object({
2756
- directory: z.string().describe("Directory containing migration files"),
2757
- machineUser: z.string().optional().describe("Machine user name for migration execution")
2758
- });
2722
+ function serializeTriggerContext(ctx) {
2723
+ if (!ctx) return "";
2724
+ return sortedMapToJson(ctx.workflowNameMap) + sortedMapToJson(ctx.jobNameMap) + sortedMapToJson(ctx.workflowFileMap);
2725
+ }
2759
2726
  /**
2760
- * Schema for TailorDB service configuration.
2761
- * Normalizes gqlOperations from alias ("query") to object format.
2727
+ * Create a rolldown plugin for transforming trigger calls
2728
+ * Returns undefined if no trigger context is provided
2729
+ * @param triggerContext - Trigger context to use for transformations
2730
+ * @returns Rolldown plugin or undefined when no context
2762
2731
  */
2763
- const TailorDBServiceConfigSchema = z.object({
2764
- files: z.array(z.string()).describe("Glob patterns for TailorDB type definition files"),
2765
- ignores: z.array(z.string()).optional().describe("Glob patterns to exclude from type discovery"),
2766
- erdSite: z.string().optional().describe("URL for the ERD (Entity Relationship Diagram) site"),
2767
- migration: TailorDBMigrationConfigSchema.optional().describe("Migration configuration"),
2768
- gqlOperations: GqlOperationsSchema.optional().describe("Default GraphQL operations for all types in this service")
2769
- });
2732
+ function createTriggerTransformPlugin(triggerContext) {
2733
+ if (!triggerContext) return;
2734
+ return {
2735
+ name: "trigger-transform",
2736
+ transform: {
2737
+ filter: { id: { include: [/\.ts$/, /\.js$/] } },
2738
+ handler(code, id) {
2739
+ if (!code.includes(".trigger(")) return null;
2740
+ return { code: transformFunctionTriggers(code, triggerContext.workflowNameMap, triggerContext.jobNameMap, triggerContext.workflowFileMap, id) };
2741
+ }
2742
+ }
2743
+ };
2744
+ }
2770
2745
 
2771
2746
  //#endregion
2772
- //#region src/cli/services/tailordb/es-builtins.ts
2773
- const globalsMap = globals.default ?? globals;
2747
+ //#region src/cli/services/auth/bundler.ts
2774
2748
  /**
2775
- * Runtime globals available in the PF execution environment.
2776
- * Identifiers in this set are excluded from free variable detection
2777
- * since they are always available in the runtime environment.
2749
+ * Bundle a single auth hook handler into dist/auth-hooks/.
2778
2750
  *
2779
- * Combines globals.builtin (ECMAScript language builtins) and
2780
- * globals['shared-node-browser'] (shared runtime globals like
2781
- * console, fetch, setTimeout, etc.) from the `globals` npm package.
2751
+ * Follows the same pattern as the executor bundler:
2752
+ * 1. Generate an entry file that re-exports the handler as `main`
2753
+ * 2. Bundle with rolldown + tree-shaking
2754
+ * @param options - Bundle options
2782
2755
  */
2783
- const ES_BUILTINS = new Set([...Object.keys(globalsMap.builtin ?? {}), ...Object.keys(globalsMap["shared-node-browser"] ?? {})]);
2756
+ async function bundleAuthHooks(options) {
2757
+ const { configPath, authName, handlerAccessPath, triggerContext, cache, inlineSourcemap } = options;
2758
+ logger.newline();
2759
+ logger.log(`Bundling auth hook for ${styles.info(`"${authName}"`)}`);
2760
+ const outputDir = path.resolve(getDistDir(), "auth-hooks");
2761
+ fs$1.mkdirSync(outputDir, { recursive: true });
2762
+ await removeStaleEntryFiles(outputDir);
2763
+ let tsconfig;
2764
+ try {
2765
+ tsconfig = await resolveTSConfig();
2766
+ } catch {
2767
+ tsconfig = void 0;
2768
+ }
2769
+ const functionName = `auth-hook--${authName}--before-login`;
2770
+ const outputPath = path.join(outputDir, `${functionName}.js`);
2771
+ const absoluteConfigPath = path.resolve(configPath);
2772
+ await withCache({
2773
+ cache,
2774
+ kind: "auth-hook",
2775
+ name: functionName,
2776
+ sourceFile: absoluteConfigPath,
2777
+ outputPath,
2778
+ contextHash: computeBundlerContextHash({
2779
+ sourceFile: absoluteConfigPath,
2780
+ serializedTriggerContext: serializeTriggerContext(triggerContext),
2781
+ tsconfig,
2782
+ inlineSourcemap
2783
+ }),
2784
+ async build(cachePlugins) {
2785
+ const entryPath = path.join(outputDir, `${functionName}.entry.js`);
2786
+ const entryContent = ml`
2787
+ import _config from "${absoluteConfigPath}";
2788
+ const __auth_hook_function = _config.${handlerAccessPath};
2789
+ export { __auth_hook_function as main };
2790
+ `;
2791
+ fs$1.writeFileSync(entryPath, entryContent);
2792
+ const triggerPlugin = createTriggerTransformPlugin(triggerContext);
2793
+ const plugins = triggerPlugin ? [triggerPlugin] : [];
2794
+ plugins.push(...cachePlugins);
2795
+ await rolldown.build(rolldown.defineConfig({
2796
+ input: entryPath,
2797
+ output: {
2798
+ file: outputPath,
2799
+ format: "esm",
2800
+ sourcemap: inlineSourcemap ? "inline" : true,
2801
+ minify: inlineSourcemap ? { mangle: { keepNames: true } } : true,
2802
+ codeSplitting: false
2803
+ },
2804
+ tsconfig,
2805
+ plugins,
2806
+ treeshake: {
2807
+ moduleSideEffects: false,
2808
+ annotations: true,
2809
+ unknownGlobalSideEffects: false
2810
+ },
2811
+ logLevel: "silent"
2812
+ }));
2813
+ }
2814
+ });
2815
+ logger.log(`${styles.success("Bundled")} auth hook for ${styles.info(`"${authName}"`)}`);
2816
+ }
2784
2817
 
2785
2818
  //#endregion
2786
- //#region src/cli/services/tailordb/hooks-validate-bundler.ts
2819
+ //#region src/parser/service/tailordb/hooks-validate-precompiled-expr.ts
2820
+ const PRECOMPILED_EXPR_KEY = "__precompiledScriptExpr";
2787
2821
  /**
2788
- * Recursively extract binding names from a destructuring pattern node.
2789
- * @param pattern - The binding pattern AST node.
2790
- * @param bindings - Set to collect binding names into.
2822
+ * Attach a precompiled script expression to a function object.
2823
+ * @param fn - Function metadata object.
2824
+ * @param expr - Precompiled script expression.
2791
2825
  */
2792
- function collectBindingsFromPattern(pattern, bindings) {
2793
- switch (pattern.type) {
2794
- case "Identifier":
2795
- bindings.add(pattern.name);
2796
- break;
2797
- case "ObjectPattern":
2798
- for (const prop of pattern.properties) if (prop.type === "RestElement") collectBindingsFromPattern(prop.argument, bindings);
2799
- else collectBindingsFromPattern(prop.value, bindings);
2800
- break;
2801
- case "ArrayPattern":
2802
- for (const elem of pattern.elements) if (elem) if (elem.type === "RestElement") collectBindingsFromPattern(elem.argument, bindings);
2803
- else collectBindingsFromPattern(elem, bindings);
2804
- break;
2805
- case "AssignmentPattern":
2806
- collectBindingsFromPattern(pattern.left, bindings);
2807
- break;
2808
- }
2809
- }
2810
- /** Fields that contain TypeScript type annotations (not runtime references). */
2811
- const TS_TYPE_FIELDS = new Set([
2812
- "typeAnnotation",
2813
- "typeParameters",
2814
- "returnType",
2815
- "superTypeArguments",
2816
- "typeArguments"
2817
- ]);
2818
- function isBindingPattern(param) {
2819
- return param.type !== "TSParameterProperty";
2820
- }
2821
- function toScriptFunction(value) {
2822
- if (typeof value !== "function") return void 0;
2823
- return value;
2824
- }
2825
- function collectScriptTargets(type) {
2826
- const targets = [];
2827
- const collectFieldTargets = (field) => {
2828
- const metadata = field.metadata;
2829
- const createHook = toScriptFunction(metadata.hooks?.create);
2830
- if (createHook) targets.push({
2831
- fn: createHook,
2832
- kind: "hooks"
2833
- });
2834
- const updateHook = toScriptFunction(metadata.hooks?.update);
2835
- if (updateHook) targets.push({
2836
- fn: updateHook,
2837
- kind: "hooks"
2838
- });
2839
- for (const validateInput of metadata.validate ?? []) if (typeof validateInput === "function") {
2840
- const validateFn = toScriptFunction(validateInput);
2841
- if (validateFn) targets.push({
2842
- fn: validateFn,
2843
- kind: "validate"
2844
- });
2845
- } else {
2846
- const validateFn = toScriptFunction(validateInput[0]);
2847
- if (validateFn) targets.push({
2848
- fn: validateFn,
2849
- kind: "validate"
2850
- });
2851
- }
2852
- if (field.type === "nested" && field.fields) for (const nestedField of Object.values(field.fields)) collectFieldTargets(nestedField);
2853
- };
2854
- for (const field of Object.values(type.fields)) collectFieldTargets(field);
2855
- return targets;
2826
+ function setPrecompiledScriptExpr(fn, expr) {
2827
+ fn[PRECOMPILED_EXPR_KEY] = expr;
2856
2828
  }
2857
2829
  /**
2858
- * Parse a code string with oxc-parser and return identifiers that are referenced
2859
- * but never bound anywhere in the snippet (free variables), excluding ES builtins.
2860
- * @param code - Valid JavaScript code to analyze.
2861
- * @returns Set of undefined variable names.
2830
+ * Read a precompiled script expression from a function object.
2831
+ * @param fn - Function metadata object.
2832
+ * @returns Precompiled script expression if attached.
2862
2833
  */
2863
- function findUndefinedReferences(code) {
2864
- const { program } = parseSync("_.js", code);
2865
- const references = /* @__PURE__ */ new Set();
2866
- const bindings = /* @__PURE__ */ new Set();
2867
- const walk = (node) => {
2868
- if (!node) return;
2869
- switch (node.type) {
2870
- case "VariableDeclarator":
2871
- collectBindingsFromPattern(node.id, bindings);
2872
- walk(node.init);
2873
- return;
2874
- case "FunctionDeclaration":
2875
- case "FunctionExpression":
2876
- if (node.id) bindings.add(node.id.name);
2877
- for (const param of node.params) if (isBindingPattern(param)) {
2878
- collectBindingsFromPattern(param, bindings);
2879
- walk(param);
2880
- }
2881
- walk(node.body);
2882
- return;
2883
- case "ArrowFunctionExpression":
2884
- for (const param of node.params) if (isBindingPattern(param)) {
2885
- collectBindingsFromPattern(param, bindings);
2886
- walk(param);
2887
- }
2888
- walk(node.body);
2889
- return;
2890
- case "ClassDeclaration":
2891
- case "ClassExpression":
2892
- if (node.id) bindings.add(node.id.name);
2893
- walk(node.superClass);
2894
- walk(node.body);
2895
- return;
2896
- case "CatchClause":
2897
- if (node.param) collectBindingsFromPattern(node.param, bindings);
2898
- walk(node.body);
2899
- return;
2900
- case "MemberExpression":
2901
- walk(node.object);
2902
- if (node.computed) walk(node.property);
2903
- return;
2904
- case "Property":
2905
- if (node.computed) walk(node.key);
2906
- walk(node.value);
2907
- return;
2908
- case "LabeledStatement":
2909
- walk(node.body);
2910
- return;
2911
- case "Identifier":
2912
- references.add(node.name);
2913
- return;
2914
- }
2915
- const rec = node;
2916
- for (const [key, value] of Object.entries(rec)) {
2917
- if (key === "type" || TS_TYPE_FIELDS.has(key)) continue;
2918
- if (Array.isArray(value)) for (const item of value) walk(item);
2919
- else if (value && typeof value === "object" && "type" in value) walk(value);
2920
- }
2921
- };
2922
- walk(program);
2923
- const freeVars = /* @__PURE__ */ new Set();
2924
- for (const ref of references) if (!bindings.has(ref) && !ES_BUILTINS.has(ref)) freeVars.add(ref);
2925
- return freeVars;
2834
+ function getPrecompiledScriptExpr(fn) {
2835
+ const value = fn[PRECOMPILED_EXPR_KEY];
2836
+ return typeof value === "string" ? value : void 0;
2926
2837
  }
2838
+
2839
+ //#endregion
2840
+ //#region src/parser/service/tailordb/field.ts
2841
+ const tailorUserMap = `{ id: user.id, type: user.type, workspaceId: user.workspace_id, attributes: user.attribute_map, attributeList: user.attributes }`;
2927
2842
  /**
2928
- * Collect all Identifier names from a TypeScript/JavaScript code string using oxc-parser.
2929
- * @param code - Code string to analyze.
2930
- * @returns Set of identifier names found in the code.
2843
+ * Convert a function to a string representation.
2844
+ * Handles method shorthand syntax (e.g., `create() { ... }`) by converting it to
2845
+ * a function expression (e.g., `function create() { ... }`).
2846
+ * @param fn - Function to stringify
2847
+ * @returns Stringified function source
2931
2848
  */
2932
- function collectIdentifierNames(code) {
2933
- const { program } = parseSync("_.ts", code);
2934
- const names = /* @__PURE__ */ new Set();
2935
- const walk = (node) => {
2936
- if (!node || typeof node !== "object") return;
2937
- const record = node;
2938
- if (record.type === "Identifier" && typeof record.name === "string") names.add(record.name);
2939
- for (const [key, value] of Object.entries(record)) {
2940
- if (key === "property" && record.type === "MemberExpression" && !record.computed) continue;
2941
- if (key === "key" && record.type === "Property" && !record.computed) continue;
2942
- if (TS_TYPE_FIELDS.has(key)) continue;
2943
- if (Array.isArray(value)) for (const item of value) walk(item);
2944
- else if (value && typeof value === "object" && "type" in value) walk(value);
2945
- }
2946
- };
2947
- walk(program);
2948
- return names;
2949
- }
2849
+ const stringifyFunction = (fn) => {
2850
+ const src = fn.toString().trim();
2851
+ if (/^[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/.test(src) && !src.startsWith("function") && !src.startsWith("(") && !src.includes("=>")) return `function ${src}`;
2852
+ return src;
2853
+ };
2950
2854
  /**
2951
- * Collect top-level bindings (imports and declarations) from a TypeScript source file.
2952
- * @param sourceFilePath - Absolute path to the source file.
2953
- * @returns Map of binding name to SourceBinding.
2855
+ * Convert a hook function to a script expression.
2856
+ * @param fn - Hook function
2857
+ * @returns JavaScript expression calling the hook
2954
2858
  */
2955
- function collectSourceBindings(sourceFilePath) {
2956
- const source = readFileSync(sourceFilePath, "utf-8");
2957
- const { program } = parseSync(sourceFilePath, source);
2958
- const bindings = /* @__PURE__ */ new Map();
2959
- for (const stmt of program.body) if (stmt.type === "ImportDeclaration") {
2960
- const importDecl = stmt;
2961
- const text = source.slice(importDecl.start, importDecl.end);
2962
- if (importDecl.specifiers) for (const spec of importDecl.specifiers) bindings.set(spec.local.name, {
2963
- name: spec.local.name,
2964
- sourceText: text,
2965
- kind: "import"
2966
- });
2967
- } else if (stmt.type === "VariableDeclaration") {
2968
- const varDecl = stmt;
2969
- const text = source.slice(varDecl.start, varDecl.end);
2970
- for (const decl of varDecl.declarations) if (decl.id.type === "Identifier") bindings.set(decl.id.name, {
2971
- name: decl.id.name,
2972
- sourceText: text,
2973
- kind: "declaration"
2974
- });
2975
- } else if (stmt.type === "FunctionDeclaration") {
2976
- const funcDecl = stmt;
2977
- if (funcDecl.id) {
2978
- const text = source.slice(funcDecl.start, funcDecl.end);
2979
- bindings.set(funcDecl.id.name, {
2980
- name: funcDecl.id.name,
2981
- sourceText: text,
2982
- kind: "declaration"
2983
- });
2984
- }
2985
- } else if (stmt.type === "ExportNamedDeclaration") {
2986
- const innerDecl = stmt.declaration;
2987
- if (!innerDecl) continue;
2988
- if (innerDecl.type === "VariableDeclaration") {
2989
- const varDecl = innerDecl;
2990
- const text = source.slice(varDecl.start, varDecl.end);
2991
- for (const decl of varDecl.declarations) if (decl.id.type === "Identifier") bindings.set(decl.id.name, {
2992
- name: decl.id.name,
2993
- sourceText: text,
2994
- kind: "declaration"
2995
- });
2996
- } else if (innerDecl.type === "FunctionDeclaration") {
2997
- const funcDecl = innerDecl;
2998
- if (funcDecl.id) {
2999
- const text = source.slice(funcDecl.start, funcDecl.end);
3000
- bindings.set(funcDecl.id.name, {
3001
- name: funcDecl.id.name,
3002
- sourceText: text,
3003
- kind: "declaration"
3004
- });
3005
- }
3006
- }
3007
- }
3008
- return bindings;
3009
- }
2859
+ const convertHookToExpr = (fn) => {
2860
+ const precompiledExpr = getPrecompiledScriptExpr(fn);
2861
+ if (precompiledExpr) return precompiledExpr;
2862
+ return `(${stringifyFunction(fn)})({ value: _value, data: _data, user: ${tailorUserMap} })`;
2863
+ };
3010
2864
  /**
3011
- * Resolve all bindings needed by a function, recursively including
3012
- * dependencies of top-level declarations.
3013
- * @param freeVars - Set of free variable names extracted from the function.
3014
- * @param sourceBindings - Available bindings from the source file.
3015
- * @returns Object with needed import statements and declaration texts.
2865
+ * Parse TailorDBField into OperatorFieldConfig.
2866
+ * This transforms user-defined functions into script expressions.
2867
+ * @param field - TailorDB field definition
2868
+ * @returns Parsed operator field configuration
3016
2869
  */
3017
- function resolveNeededBindings(freeVars, sourceBindings) {
3018
- const neededImports = /* @__PURE__ */ new Set();
3019
- const neededDeclarations = /* @__PURE__ */ new Set();
3020
- const unresolved = [];
3021
- const resolved = /* @__PURE__ */ new Set();
3022
- const resolveVars = (vars) => {
3023
- for (const varName of vars) {
3024
- if (resolved.has(varName)) continue;
3025
- resolved.add(varName);
3026
- const binding = sourceBindings.get(varName);
3027
- if (!binding) {
3028
- unresolved.push(varName);
3029
- continue;
3030
- }
3031
- if (binding.kind === "import") neededImports.add(binding.sourceText);
3032
- else {
3033
- const identifiers = collectIdentifierNames(binding.sourceText);
3034
- const referencedVars = /* @__PURE__ */ new Set();
3035
- for (const id of identifiers) if (id !== varName && sourceBindings.has(id)) referencedVars.add(id);
3036
- resolveVars(referencedVars);
3037
- neededDeclarations.add(binding.sourceText);
3038
- }
3039
- }
3040
- };
3041
- resolveVars(freeVars);
2870
+ function parseFieldConfig(field) {
2871
+ const metadata = field.metadata;
2872
+ const fieldType = field.type;
2873
+ const rawRelation = field.rawRelation;
2874
+ const nestedFields = field.fields;
3042
2875
  return {
3043
- imports: [...neededImports],
3044
- declarations: [...neededDeclarations],
3045
- unresolved
2876
+ type: fieldType,
2877
+ ...metadata,
2878
+ rawRelation,
2879
+ ...fieldType === "nested" && nestedFields && Object.keys(nestedFields).length > 0 ? { fields: Object.entries(nestedFields).reduce((acc, [key, nestedField]) => {
2880
+ acc[key] = parseFieldConfig(nestedField);
2881
+ return acc;
2882
+ }, {}) } : {},
2883
+ validate: metadata.validate?.map((v) => {
2884
+ const { fn, message } = typeof v === "function" ? {
2885
+ fn: v,
2886
+ message: `failed by \`${v.toString().trim()}\``
2887
+ } : {
2888
+ fn: v[0],
2889
+ message: v[1]
2890
+ };
2891
+ return {
2892
+ script: { expr: getPrecompiledScriptExpr(fn) ?? `(${fn.toString().trim()})({ value: _value, data: _data, user: ${tailorUserMap} })` },
2893
+ errorMessage: message
2894
+ };
2895
+ }),
2896
+ hooks: metadata.hooks ? {
2897
+ create: metadata.hooks.create ? { expr: convertHookToExpr(metadata.hooks.create) } : void 0,
2898
+ update: metadata.hooks.update ? { expr: convertHookToExpr(metadata.hooks.update) } : void 0
2899
+ } : void 0,
2900
+ serial: metadata.serial ? {
2901
+ start: metadata.serial.start,
2902
+ maxValue: metadata.serial.maxValue,
2903
+ format: "format" in metadata.serial ? metadata.serial.format : void 0
2904
+ } : void 0
3046
2905
  };
3047
2906
  }
3048
- function buildPrecompiledExpr(bundleCode) {
3049
- return `(() => {
3050
- const module = { exports: {} };
3051
- const exports = module.exports;
3052
- ${bundleCode}\n return module.exports.main({ value: _value, data: _data, user: ${tailorUserMap} });\n})()`;
2907
+
2908
+ //#endregion
2909
+ //#region src/parser/service/tailordb/permission.ts
2910
+ const operatorMap = {
2911
+ "=": "eq",
2912
+ "!=": "ne",
2913
+ in: "in",
2914
+ "not in": "nin",
2915
+ hasAny: "hasAny",
2916
+ "not hasAny": "nhasAny"
2917
+ };
2918
+ function normalizeOperand(operand) {
2919
+ if (typeof operand === "object" && "user" in operand) return { user: operand.user === "id" ? "_id" : operand.user };
2920
+ return operand;
2921
+ }
2922
+ function normalizeConditions(conditions) {
2923
+ return conditions.map((cond) => {
2924
+ const [left, operator, right] = cond;
2925
+ return [
2926
+ normalizeOperand(left),
2927
+ operatorMap[operator],
2928
+ normalizeOperand(right)
2929
+ ];
2930
+ });
2931
+ }
2932
+ function isObjectFormat(p) {
2933
+ return typeof p === "object" && p !== null && "conditions" in p;
2934
+ }
2935
+ function isSingleArrayConditionFormat(cond) {
2936
+ return cond.length >= 2 && typeof cond[1] === "string";
3053
2937
  }
3054
2938
  /**
3055
- * Build entry file content from already-resolved imports and declarations.
3056
- * @param imports - Import statement texts.
3057
- * @param declarations - Declaration statement texts.
3058
- * @param fnSource - The function source code.
3059
- * @param sourceFilePath - Path to the source file for resolving relative imports.
3060
- * @returns Entry file content string.
2939
+ * Normalize record-level permissions into a standard structure.
2940
+ * @param permission - Tailor type permission
2941
+ * @returns Normalized record permissions
3061
2942
  */
3062
- function buildMinimalEntryFromResolved(imports, declarations, fnSource, sourceFilePath) {
3063
- const sourceDir = resolve(sourceFilePath, "..").replace(/\\/g, "/");
3064
- return [
3065
- ...imports.map((imp) => imp.replace(/from\s+["'](\.[^"']+)["']/g, (_match, relPath) => `from "${resolve(sourceDir, relPath).replace(/\\/g, "/")}"`)),
3066
- ...declarations,
3067
- `export function main(input) { return (${fnSource})(input); }`
3068
- ].join("\n");
2943
+ function normalizePermission(permission) {
2944
+ return Object.keys(permission).reduce((acc, action) => {
2945
+ acc[action] = permission[action].map((p) => normalizeActionPermission(p));
2946
+ return acc;
2947
+ }, {});
3069
2948
  }
3070
- async function bundleScriptTarget(args) {
3071
- const { fn, kind, sourceFilePath, sourceBindings, tempDir, targetIndex, tsconfig } = args;
3072
- const fnSource = stringifyFunction(fn);
3073
- const inlineExpr = `(${fnSource})({ value: _value, data: _data, user: ${tailorUserMap} })`;
3074
- const freeVars = findUndefinedReferences(`const __fn = ${fnSource};`);
3075
- if (freeVars.size === 0) return inlineExpr;
3076
- const { imports, declarations, unresolved } = resolveNeededBindings(freeVars, sourceBindings);
3077
- if (unresolved.length > 0) throw new Error(`${kind} in ${sourceFilePath} captures unresolvable variables (${unresolved.join(", ")}). Hooks and validators must not reference variables that cannot be resolved from the source file.
3078
- ${kind}: ${fnSource}`);
3079
- const entryContent = buildMinimalEntryFromResolved(imports, declarations, fnSource, sourceFilePath);
3080
- const entryPath = join(tempDir, `tailordb-script-${targetIndex}.entry.ts`);
3081
- const outputPath = join(tempDir, `tailordb-script-${targetIndex}.bundle.cjs`);
3082
- writeFileSync(entryPath, entryContent);
3083
- await rolldown.build(rolldown.defineConfig({
3084
- input: entryPath,
3085
- output: {
3086
- file: outputPath,
3087
- format: "cjs",
3088
- sourcemap: false,
3089
- minify: true,
3090
- codeSplitting: false
3091
- },
3092
- tsconfig,
3093
- treeshake: {
3094
- moduleSideEffects: false,
3095
- annotations: true,
3096
- unknownGlobalSideEffects: false
3097
- },
3098
- logLevel: "silent"
3099
- }));
3100
- return buildPrecompiledExpr(readFileSync(outputPath, "utf-8"));
2949
+ /**
2950
+ * Normalize GraphQL permissions into a standard structure.
2951
+ * @param permission - Tailor GQL permission
2952
+ * @returns Normalized GQL permissions
2953
+ */
2954
+ function normalizeGqlPermission(permission) {
2955
+ return permission.map((policy) => normalizeGqlPolicy(policy));
2956
+ }
2957
+ function normalizeGqlPolicy(policy) {
2958
+ return {
2959
+ conditions: policy.conditions ? normalizeConditions(policy.conditions) : [],
2960
+ actions: policy.actions === "all" ? ["all"] : policy.actions,
2961
+ permit: policy.permit ? "allow" : "deny",
2962
+ description: policy.description
2963
+ };
3101
2964
  }
3102
2965
  /**
3103
- * Precompile TailorDB hooks/validators into self-contained script expressions using rolldown.
3104
- * Uses oxc-parser AST walking to extract free variables from functions, then builds
3105
- * minimal entry points containing only the needed imports and declarations.
3106
- * @param type - TailorDB type schema output.
3107
- * @param sourceFilePath - Source file where the type is defined.
3108
- * @param tsconfig - Resolved tsconfig path, or undefined if not found.
2966
+ * Parse raw permissions into normalized permissions.
2967
+ * This is the main entry point for permission parsing in the parser layer.
2968
+ * @param rawPermissions - Raw permissions definition
2969
+ * @returns Normalized permissions
3109
2970
  */
3110
- async function precompileTailorDBTypeScripts(type, sourceFilePath, tsconfig) {
3111
- const targets = collectScriptTargets(type);
3112
- if (targets.length === 0) return;
3113
- const sourceBindings = collectSourceBindings(sourceFilePath);
3114
- const tempDir = resolve(getDistDir(), "hooks-validate-scripts", type.name);
3115
- mkdirSync(tempDir, { recursive: true });
3116
- try {
3117
- const results = await Promise.allSettled(targets.map((target, index) => bundleScriptTarget({
3118
- fn: target.fn,
3119
- kind: target.kind,
3120
- sourceFilePath,
3121
- sourceBindings,
3122
- tempDir,
3123
- targetIndex: index,
3124
- tsconfig
3125
- })));
3126
- const firstError = results.find((r) => r.status === "rejected");
3127
- if (firstError && firstError.status === "rejected") throw firstError.reason;
3128
- for (const [index, result] of results.entries()) if (result.status === "fulfilled") setPrecompiledScriptExpr(targets[index].fn, result.value);
3129
- } finally {
3130
- rmSync(tempDir, {
3131
- recursive: true,
3132
- force: true
3133
- });
2971
+ function parsePermissions(rawPermissions) {
2972
+ return {
2973
+ ...rawPermissions.record && { record: normalizePermission(rawPermissions.record) },
2974
+ ...rawPermissions.gql && { gql: normalizeGqlPermission(rawPermissions.gql) }
2975
+ };
2976
+ }
2977
+ /**
2978
+ * Normalize a single action permission into the standard format.
2979
+ * @param permission - Raw permission definition
2980
+ * @returns Normalized action permission
2981
+ */
2982
+ function normalizeActionPermission(permission) {
2983
+ if (isObjectFormat(permission)) {
2984
+ const conditions = permission.conditions;
2985
+ return {
2986
+ conditions: normalizeConditions(isSingleArrayConditionFormat(conditions) ? [conditions] : conditions),
2987
+ permit: permission.permit ? "allow" : "deny",
2988
+ description: permission.description
2989
+ };
2990
+ }
2991
+ if (!Array.isArray(permission)) throw new Error("Invalid permission format");
2992
+ if (isSingleArrayConditionFormat(permission)) {
2993
+ const [op1, operator, op2, permit] = [...permission, true];
2994
+ return {
2995
+ conditions: normalizeConditions([[
2996
+ op1,
2997
+ operator,
2998
+ op2
2999
+ ]]),
3000
+ permit: permit ? "allow" : "deny"
3001
+ };
3002
+ }
3003
+ const conditions = [];
3004
+ const conditionArray = permission;
3005
+ let conditionArrayPermit = true;
3006
+ for (const item of conditionArray) {
3007
+ if (typeof item === "boolean") {
3008
+ conditionArrayPermit = item;
3009
+ continue;
3010
+ }
3011
+ conditions.push(item);
3134
3012
  }
3013
+ return {
3014
+ conditions: normalizeConditions(conditions),
3015
+ permit: conditionArrayPermit ? "allow" : "deny"
3016
+ };
3135
3017
  }
3136
3018
 
3137
3019
  //#endregion
3138
- //#region src/cli/services/tailordb/service.ts
3020
+ //#region src/parser/service/tailordb/relation.ts
3021
+ const relationTypes = {
3022
+ "1-1": "1-1",
3023
+ oneToOne: "1-1",
3024
+ "n-1": "n-1",
3025
+ manyToOne: "n-1",
3026
+ "N-1": "n-1",
3027
+ keyOnly: "keyOnly"
3028
+ };
3029
+ const relationTypesKeys = Object.keys(relationTypes);
3030
+ function fieldRef(context) {
3031
+ return `Field "${context.fieldName}" on type "${context.typeName}"`;
3032
+ }
3139
3033
  /**
3140
- * Creates a new TailorDBService instance.
3141
- * @param params - Parameters for creating the service
3142
- * @returns A new TailorDBService instance
3034
+ * Validate relation configuration.
3035
+ * @param rawRelation - Raw relation configuration from TailorDB type definition
3036
+ * @param context - Context information for the relation (type name, field name, all type names)
3143
3037
  */
3144
- function createTailorDBService(params) {
3145
- const { namespace, config, pluginManager } = params;
3146
- const rawTypes = {};
3147
- let types = {};
3148
- const typeSourceInfo = {};
3149
- const pluginAttachments = /* @__PURE__ */ new Map();
3150
- let loadPromise;
3151
- const doParseTypes = () => {
3152
- const allTypes = {};
3153
- for (const fileTypes of Object.values(rawTypes)) for (const [typeName, type] of Object.entries(fileTypes)) allTypes[typeName] = type;
3154
- types = parseTypes(allTypes, namespace, typeSourceInfo);
3038
+ function validateRelationConfig(rawRelation, context) {
3039
+ if (!rawRelation.type) throw new Error(`${fieldRef(context)} has a relation but is missing the required 'type' property. Valid values: ${relationTypesKeys.join(", ")}.`);
3040
+ if (!(rawRelation.type in relationTypes)) throw new Error(`${fieldRef(context)} has invalid relation type '${rawRelation.type}'. Valid values: ${relationTypesKeys.join(", ")}.`);
3041
+ if (rawRelation.toward.type !== "self" && !context.allTypeNames.has(rawRelation.toward.type)) throw new Error(`${fieldRef(context)} references unknown type "${rawRelation.toward.type}".`);
3042
+ }
3043
+ /**
3044
+ * Process raw relation config and compute derived metadata values.
3045
+ * @param rawRelation - Raw relation configuration
3046
+ * @param context - Context information for the relation
3047
+ * @param isArrayField - Whether the target field is an array field
3048
+ * @returns Computed relation metadata to apply to field config
3049
+ */
3050
+ function processRelationMetadata(rawRelation, context, isArrayField = false) {
3051
+ const isUnique = relationTypes[rawRelation.type] === "1-1";
3052
+ const key = rawRelation.toward.key ?? "id";
3053
+ const targetTypeName = rawRelation.toward.type === "self" ? context.typeName : rawRelation.toward.type;
3054
+ const shouldSetIndex = !isArrayField;
3055
+ const shouldSetUnique = !isArrayField && isUnique;
3056
+ return {
3057
+ index: shouldSetIndex,
3058
+ foreignKey: true,
3059
+ relationType: rawRelation.type,
3060
+ unique: shouldSetUnique,
3061
+ foreignKeyType: targetTypeName,
3062
+ foreignKeyField: key
3155
3063
  };
3156
- /**
3157
- * Process plugins for a type and add generated types to rawTypes
3158
- * @param rawType - The raw TailorDB type being processed
3159
- * @param attachments - Plugin attachments for this type
3160
- * @param sourceFilePath - The file path where the type was loaded from
3161
- */
3162
- const processPluginsForType = async (rawType, attachments, sourceFilePath) => {
3163
- if (!pluginManager) return;
3164
- let currentType = rawType;
3165
- for (const attachment of attachments) {
3166
- const result = await pluginManager.processAttachment({
3167
- type: currentType,
3168
- typeConfig: attachment.config,
3169
- namespace,
3170
- pluginId: attachment.pluginId
3171
- });
3172
- if (!result.success) {
3173
- logger.error(result.error);
3174
- throw new Error(result.error);
3064
+ }
3065
+ /**
3066
+ * Build relation info for creating forward/backward relationships.
3067
+ * Returns undefined for keyOnly relations.
3068
+ * @param rawRelation - Raw relation configuration
3069
+ * @param context - Context information for the relation
3070
+ * @returns Relation information or undefined for keyOnly relations
3071
+ */
3072
+ function buildRelationInfo(rawRelation, context) {
3073
+ if (rawRelation.type === "keyOnly") return;
3074
+ const isUnique = relationTypes[rawRelation.type] === "1-1";
3075
+ const key = rawRelation.toward.key ?? "id";
3076
+ const targetTypeName = rawRelation.toward.type === "self" ? context.typeName : rawRelation.toward.type;
3077
+ let forwardName = rawRelation.toward.as;
3078
+ if (!forwardName) if (rawRelation.toward.type === "self") forwardName = context.fieldName.replace(/(ID|Id|id)$/u, "");
3079
+ else forwardName = inflection.camelize(targetTypeName, true);
3080
+ return {
3081
+ targetType: targetTypeName,
3082
+ forwardName,
3083
+ backwardName: rawRelation.backward ?? "",
3084
+ key,
3085
+ unique: isUnique
3086
+ };
3087
+ }
3088
+ /**
3089
+ * Apply processed relation metadata to field config.
3090
+ * @param fieldConfig - Original operator field configuration
3091
+ * @param metadata - Processed relation metadata to apply
3092
+ * @returns Field config with relation metadata applied
3093
+ */
3094
+ function applyRelationMetadataToFieldConfig(fieldConfig, metadata) {
3095
+ return {
3096
+ ...fieldConfig,
3097
+ index: metadata.index,
3098
+ foreignKey: metadata.foreignKey,
3099
+ unique: metadata.unique,
3100
+ foreignKeyType: metadata.foreignKeyType,
3101
+ foreignKeyField: metadata.foreignKeyField
3102
+ };
3103
+ }
3104
+
3105
+ //#endregion
3106
+ //#region src/parser/service/tailordb/type-parser.ts
3107
+ /**
3108
+ * Parse multiple TailorDB types, build relationships, and validate uniqueness.
3109
+ * This is the main entry point for parsing TailorDB types.
3110
+ * @param rawTypes - Raw TailorDB types keyed by name
3111
+ * @param namespace - TailorDB namespace name
3112
+ * @param typeSourceInfo - Optional type source information
3113
+ * @returns Parsed types
3114
+ */
3115
+ function parseTypes(rawTypes, namespace, typeSourceInfo) {
3116
+ const types = {};
3117
+ const allTypeNames = new Set(Object.keys(rawTypes));
3118
+ for (const [typeName, type] of Object.entries(rawTypes)) types[typeName] = parseTailorDBType(type, allTypeNames, rawTypes);
3119
+ buildBackwardRelationships(types, namespace, typeSourceInfo);
3120
+ validatePluralFormUniqueness(types, namespace, typeSourceInfo);
3121
+ return types;
3122
+ }
3123
+ /**
3124
+ * Parse a TailorDBTypeSchemaOutput into a TailorDBType.
3125
+ * @param type - TailorDB type to parse
3126
+ * @param allTypeNames - Set of all TailorDB type names
3127
+ * @param rawTypes - All raw TailorDB types keyed by name
3128
+ * @returns Parsed TailorDB type
3129
+ */
3130
+ function parseTailorDBType(type, allTypeNames, rawTypes) {
3131
+ const metadata = type.metadata;
3132
+ const pluralForm = metadata.settings?.pluralForm || inflection.pluralize(type.name);
3133
+ const fields = {};
3134
+ const forwardRelationships = {};
3135
+ for (const [fieldName, fieldDef] of Object.entries(type.fields)) {
3136
+ let fieldConfig = parseFieldConfig(fieldDef);
3137
+ const rawRelation = fieldConfig.rawRelation;
3138
+ const context = {
3139
+ typeName: type.name,
3140
+ fieldName,
3141
+ allTypeNames
3142
+ };
3143
+ if (rawRelation) {
3144
+ validateRelationConfig(rawRelation, context);
3145
+ if ([
3146
+ "n-1",
3147
+ "manyToOne",
3148
+ "N-1"
3149
+ ].includes(rawRelation.type) && fieldConfig.unique) throw new Error(`Field "${fieldName}" on type "${type.name}": cannot set unique on n-1 (manyToOne) relation. Use 1-1 (oneToOne) relation instead, or remove the unique constraint.`);
3150
+ const relationMetadata = processRelationMetadata(rawRelation, context, fieldConfig.array);
3151
+ fieldConfig = applyRelationMetadataToFieldConfig(fieldConfig, relationMetadata);
3152
+ }
3153
+ if (fieldConfig.array && fieldConfig.index) throw new Error(`Field "${fieldName}" on type "${type.name}": index cannot be set on array fields`);
3154
+ if (fieldConfig.array && fieldConfig.unique) throw new Error(`Field "${fieldName}" on type "${type.name}": unique cannot be set on array fields`);
3155
+ const parsedField = {
3156
+ name: fieldName,
3157
+ config: fieldConfig
3158
+ };
3159
+ const relationInfo = rawRelation ? buildRelationInfo(rawRelation, context) : void 0;
3160
+ if (relationInfo) {
3161
+ parsedField.relation = { ...relationInfo };
3162
+ const targetType = rawTypes[relationInfo.targetType];
3163
+ forwardRelationships[relationInfo.forwardName] = {
3164
+ name: relationInfo.forwardName,
3165
+ targetType: relationInfo.targetType,
3166
+ targetField: fieldName,
3167
+ sourceField: relationInfo.key,
3168
+ isArray: false,
3169
+ description: targetType?.metadata?.description || ""
3170
+ };
3171
+ }
3172
+ fields[fieldName] = parsedField;
3173
+ }
3174
+ return {
3175
+ name: type.name,
3176
+ pluralForm,
3177
+ description: metadata.description,
3178
+ fields,
3179
+ forwardRelationships,
3180
+ backwardRelationships: {},
3181
+ settings: metadata.settings || {},
3182
+ permissions: parsePermissions(metadata.permissions || {}),
3183
+ indexes: metadata.indexes,
3184
+ files: metadata.files
3185
+ };
3186
+ }
3187
+ /**
3188
+ * Build backward relationships between parsed types.
3189
+ * Also validates that backward relation names are unique within each type.
3190
+ * @param types - Parsed types
3191
+ * @param namespace - TailorDB namespace name
3192
+ * @param typeSourceInfo - Optional type source information
3193
+ */
3194
+ function buildBackwardRelationships(types, namespace, typeSourceInfo) {
3195
+ const backwardNameSources = {};
3196
+ for (const typeName of Object.keys(types)) backwardNameSources[typeName] = {};
3197
+ for (const [typeName, type] of Object.entries(types)) for (const [otherTypeName, otherType] of Object.entries(types)) for (const [fieldName, field] of Object.entries(otherType.fields)) if (field.relation && field.relation.targetType === typeName) {
3198
+ let backwardName = field.relation.backwardName;
3199
+ if (!backwardName) {
3200
+ const lowerName = inflection.camelize(otherTypeName, true);
3201
+ backwardName = field.relation.unique ? inflection.singularize(lowerName) : inflection.pluralize(lowerName);
3202
+ }
3203
+ if (!backwardNameSources[typeName][backwardName]) backwardNameSources[typeName][backwardName] = [];
3204
+ backwardNameSources[typeName][backwardName].push({
3205
+ sourceType: otherTypeName,
3206
+ fieldName
3207
+ });
3208
+ type.backwardRelationships[backwardName] = {
3209
+ name: backwardName,
3210
+ targetType: otherTypeName,
3211
+ targetField: fieldName,
3212
+ sourceField: field.relation.key,
3213
+ isArray: !field.relation.unique,
3214
+ description: otherType.description || ""
3215
+ };
3216
+ }
3217
+ const errors = [];
3218
+ for (const [targetTypeName, backwardNames] of Object.entries(backwardNameSources)) {
3219
+ const targetType = types[targetTypeName];
3220
+ const targetTypeSourceInfo = typeSourceInfo?.[targetTypeName];
3221
+ const targetLocation = targetTypeSourceInfo ? isPluginGeneratedType(targetTypeSourceInfo) ? ` (plugin: ${targetTypeSourceInfo.pluginId})` : ` (${targetTypeSourceInfo.filePath})` : "";
3222
+ for (const [backwardName, sources] of Object.entries(backwardNames)) {
3223
+ if (sources.length > 1) {
3224
+ const sourceList = sources.map((s) => {
3225
+ const sourceInfo = typeSourceInfo?.[s.sourceType];
3226
+ const location = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
3227
+ return `${s.sourceType}.${s.fieldName}${location}`;
3228
+ }).join(", ");
3229
+ errors.push(`Backward relation name "${backwardName}" on type "${targetTypeName}" is duplicated from: ${sourceList}. Use the "backward" option in .relation() to specify unique names.`);
3175
3230
  }
3176
- const output = result.output;
3177
- const extendFields = output.extends?.fields;
3178
- if (extendFields && Object.keys(extendFields).length > 0) {
3179
- const extendedType = pluginManager.extendType({
3180
- originalType: currentType,
3181
- extendFields,
3182
- pluginId: attachment.pluginId
3183
- });
3184
- rawTypes[sourceFilePath][currentType.name] = extendedType;
3185
- currentType = extendedType;
3186
- logger.log(` Extended: ${styles.success(currentType.name)} with ${styles.highlight(Object.keys(extendFields).length.toString())} fields by plugin ${styles.info(attachment.pluginId)}`);
3231
+ if (backwardName in targetType.fields) {
3232
+ const source = sources[0];
3233
+ const sourceInfo = typeSourceInfo?.[source.sourceType];
3234
+ const sourceLocation = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
3235
+ errors.push(`Backward relation name "${backwardName}" from ${source.sourceType}.${source.fieldName}${sourceLocation} conflicts with existing field "${backwardName}" on type "${targetTypeName}"${targetLocation}. Use the "backward" option in .relation() to specify a different name.`);
3187
3236
  }
3188
- const plugin = pluginManager.getPlugin(attachment.pluginId);
3189
- for (const [kind, generatedType] of Object.entries(output.types ?? {})) {
3190
- rawTypes[sourceFilePath][generatedType.name] = generatedType;
3191
- typeSourceInfo[generatedType.name] = {
3192
- exportName: generatedType.name,
3193
- pluginId: attachment.pluginId,
3194
- pluginImportPath: pluginManager.getPluginImportPath(attachment.pluginId) ?? "",
3195
- originalFilePath: sourceFilePath,
3196
- originalExportName: typeSourceInfo[rawType.name]?.exportName || rawType.name,
3197
- generatedTypeKind: kind,
3198
- pluginConfig: plugin?.pluginConfig,
3199
- namespace
3200
- };
3201
- logger.log(` Generated: ${styles.success(generatedType.name)} by plugin ${styles.info(attachment.pluginId)}`);
3237
+ if (targetType.files && backwardName in targetType.files) {
3238
+ const source = sources[0];
3239
+ const sourceInfo = typeSourceInfo?.[source.sourceType];
3240
+ const sourceLocation = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
3241
+ errors.push(`Backward relation name "${backwardName}" from ${source.sourceType}.${source.fieldName}${sourceLocation} conflicts with files field "${backwardName}" on type "${targetTypeName}"${targetLocation}. Use the "backward" option in .relation() to specify a different name.`);
3202
3242
  }
3203
3243
  }
3204
- };
3205
- const loadTypeFile = async (typeFile, tsconfig) => {
3206
- rawTypes[typeFile] = {};
3207
- const loadedTypes = {};
3208
- try {
3209
- const module = await import(pathToFileURL(typeFile).href);
3210
- for (const exportName of Object.keys(module)) {
3211
- const exportedValue = module[exportName];
3212
- const result = TailorDBTypeSchema.safeParse(exportedValue);
3213
- if (!result.success) {
3214
- if (isSdkBranded(exportedValue, "tailordb-type")) throw result.error;
3215
- continue;
3216
- }
3217
- const relativePath = path.relative(process.cwd(), typeFile);
3218
- logger.log(`Type: ${styles.successBright(`"${result.data.name}"`)} loaded from ${styles.path(relativePath)}`);
3219
- await precompileTailorDBTypeScripts(result.data, typeFile, tsconfig);
3220
- rawTypes[typeFile][result.data.name] = result.data;
3221
- loadedTypes[result.data.name] = result.data;
3222
- typeSourceInfo[result.data.name] = {
3223
- filePath: typeFile,
3224
- exportName
3225
- };
3226
- if (exportedValue.plugins && Array.isArray(exportedValue.plugins) && exportedValue.plugins.length > 0) {
3227
- pluginAttachments.set(exportedValue.name, [...exportedValue.plugins]);
3228
- logger.log(` Plugin attachments: ${styles.info(exportedValue.plugins.map((p) => p.pluginId).join(", "))}`);
3229
- await processPluginsForType(exportedValue, exportedValue.plugins, typeFile);
3230
- }
3231
- }
3232
- } catch (error) {
3233
- const relativePath = path.relative(process.cwd(), typeFile);
3234
- logger.error(`Failed to load type from ${styles.bold(relativePath)}`);
3235
- logger.error(String(error));
3236
- throw error;
3244
+ }
3245
+ if (errors.length > 0) throw new Error(`Backward relation name conflicts detected in TailorDB service "${namespace}".\n${errors.map((e) => ` - ${e}`).join("\n")}`);
3246
+ }
3247
+ /**
3248
+ * Validate GraphQL query field name uniqueness.
3249
+ * Checks for:
3250
+ * 1. Each type's singular query name != plural query name
3251
+ * 2. No duplicate query names across all types
3252
+ * @param types - Parsed types
3253
+ * @param namespace - TailorDB namespace name
3254
+ * @param typeSourceInfo - Optional type source information
3255
+ */
3256
+ function validatePluralFormUniqueness(types, namespace, typeSourceInfo) {
3257
+ const errors = [];
3258
+ for (const [, parsedType] of Object.entries(types)) {
3259
+ const singularQuery = inflection.camelize(parsedType.name, true);
3260
+ if (singularQuery === inflection.camelize(parsedType.pluralForm, true)) {
3261
+ const sourceInfo = typeSourceInfo?.[parsedType.name];
3262
+ const location = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
3263
+ errors.push(`Type "${parsedType.name}"${location} has identical singular and plural query names "${singularQuery}". Use db.type(["${parsedType.name}", "UniquePluralForm"], {...}) to set a unique pluralForm.`);
3237
3264
  }
3238
- return loadedTypes;
3239
- };
3240
- return {
3241
- namespace,
3242
- config,
3243
- get types() {
3244
- return types;
3245
- },
3246
- get typeSourceInfo() {
3247
- return typeSourceInfo;
3248
- },
3249
- get pluginAttachments() {
3250
- return pluginAttachments;
3251
- },
3252
- loadTypes: async () => {
3253
- if (!loadPromise) loadPromise = (async () => {
3254
- if (!config.files || config.files.length === 0) return;
3255
- const typeFiles = loadFilesWithIgnores(config);
3256
- let tsconfig;
3257
- try {
3258
- tsconfig = await resolveTSConfig();
3259
- } catch {
3260
- tsconfig = void 0;
3261
- }
3262
- logger.newline();
3263
- logger.log(`Found ${styles.highlight(typeFiles.length.toString())} type files for TailorDB service ${styles.highlight(`"${namespace}"`)}`);
3264
- if (pluginManager) for (const typeFile of typeFiles) await loadTypeFile(typeFile, tsconfig);
3265
- else await Promise.all(typeFiles.map((typeFile) => loadTypeFile(typeFile, tsconfig)));
3266
- doParseTypes();
3267
- return types;
3268
- })();
3269
- return loadPromise;
3270
- },
3271
- processNamespacePlugins: async () => {
3272
- if (!pluginManager) return;
3273
- const results = await pluginManager.processNamespacePlugins(namespace);
3274
- const pluginGeneratedKey = "__plugin_generated__";
3275
- if (!rawTypes[pluginGeneratedKey]) rawTypes[pluginGeneratedKey] = {};
3276
- let hasGeneratedTypes = false;
3277
- for (const { pluginId, config, result } of results) {
3278
- if (!result.success) {
3279
- logger.error(result.error);
3280
- throw new Error(result.error);
3281
- }
3282
- const output = result.output;
3283
- for (const [kind, generatedType] of Object.entries(output.types ?? {})) {
3284
- rawTypes[pluginGeneratedKey][generatedType.name] = generatedType;
3285
- hasGeneratedTypes = true;
3286
- typeSourceInfo[generatedType.name] = {
3287
- exportName: generatedType.name,
3288
- pluginId,
3289
- pluginImportPath: pluginManager.getPluginImportPath(pluginId) ?? "",
3290
- originalFilePath: "",
3291
- originalExportName: "",
3292
- generatedTypeKind: kind,
3293
- pluginConfig: config,
3294
- namespace
3295
- };
3296
- logger.log(` Generated: ${styles.success(generatedType.name)} by namespace plugin ${styles.info(pluginId)}`);
3297
- }
3298
- }
3299
- if (hasGeneratedTypes) doParseTypes();
3265
+ }
3266
+ const queryNameToSource = {};
3267
+ for (const parsedType of Object.values(types)) {
3268
+ const singularQuery = inflection.camelize(parsedType.name, true);
3269
+ const pluralQuery = inflection.camelize(parsedType.pluralForm, true);
3270
+ if (!queryNameToSource[singularQuery]) queryNameToSource[singularQuery] = [];
3271
+ queryNameToSource[singularQuery].push({
3272
+ typeName: parsedType.name,
3273
+ kind: "singular"
3274
+ });
3275
+ if (singularQuery !== pluralQuery) {
3276
+ if (!queryNameToSource[pluralQuery]) queryNameToSource[pluralQuery] = [];
3277
+ queryNameToSource[pluralQuery].push({
3278
+ typeName: parsedType.name,
3279
+ kind: "plural"
3280
+ });
3300
3281
  }
3301
- };
3282
+ }
3283
+ const duplicates = Object.entries(queryNameToSource).filter(([, sources]) => sources.length > 1);
3284
+ for (const [queryName, sources] of duplicates) {
3285
+ const sourceList = sources.map((s) => {
3286
+ const sourceInfo = typeSourceInfo?.[s.typeName];
3287
+ const location = sourceInfo ? isPluginGeneratedType(sourceInfo) ? ` (plugin: ${sourceInfo.pluginId})` : ` (${sourceInfo.filePath})` : "";
3288
+ return `"${s.typeName}"${location} (${s.kind})`;
3289
+ }).join(", ");
3290
+ errors.push(`GraphQL query field "${queryName}" conflicts between: ${sourceList}`);
3291
+ }
3292
+ if (errors.length > 0) throw new Error(`GraphQL field name conflicts detected in TailorDB service "${namespace}".\n${errors.map((e) => ` - ${e}`).join("\n")}`);
3302
3293
  }
3303
3294
 
3304
3295
  //#endregion
3305
- //#region src/parser/service/resolver/schema.ts
3306
- const TailorFieldTypeSchema = z.enum([
3296
+ //#region src/parser/service/common.ts
3297
+ const functionSchema = z.custom((val) => typeof val === "function");
3298
+
3299
+ //#endregion
3300
+ //#region src/parser/service/tailordb/schema.ts
3301
+ /**
3302
+ * Normalize GqlOperationsConfig (alias or object) to GqlOperations object.
3303
+ * "query" alias expands to read-only mode: { create: false, update: false, delete: false, read: true }
3304
+ * @param config - The config to normalize
3305
+ * @returns The normalized GqlOperations object
3306
+ */
3307
+ function normalizeGqlOperations(config) {
3308
+ if (config === "query") return {
3309
+ create: false,
3310
+ update: false,
3311
+ delete: false,
3312
+ read: true
3313
+ };
3314
+ return config;
3315
+ }
3316
+ /**
3317
+ * Zod schema for GqlOperations configuration with normalization transform.
3318
+ * Accepts "query" alias or detailed object, normalizes to GqlOperations object.
3319
+ */
3320
+ const GqlOperationsSchema = z.union([z.literal("query"), z.object({
3321
+ create: z.boolean().optional().describe("Enable create mutation (default: true)"),
3322
+ update: z.boolean().optional().describe("Enable update mutation (default: true)"),
3323
+ delete: z.boolean().optional().describe("Enable delete mutation (default: true)"),
3324
+ read: z.boolean().optional().describe("Enable read queries - get, list, aggregation (default: true)")
3325
+ })]).describe("Configuration for GraphQL operations on a TailorDB type.\nAll operations are enabled by default (undefined or true = enabled, false = disabled).").transform((val) => normalizeGqlOperations(val));
3326
+ const TailorFieldTypeSchema$1 = z.enum([
3307
3327
  "uuid",
3308
3328
  "string",
3309
3329
  "boolean",
@@ -3316,931 +3336,998 @@ const TailorFieldTypeSchema = z.enum([
3316
3336
  "time",
3317
3337
  "nested"
3318
3338
  ]);
3319
- const QueryTypeSchema = z.union([z.literal("query"), z.literal("mutation")]).describe("GraphQL operation type");
3320
- const AllowedValueSchema = z.object({
3321
- value: z.string().describe("The allowed value"),
3322
- description: z.string().optional().describe("Description of the allowed value")
3339
+ const AllowedValueSchema$1 = z.object({
3340
+ value: z.string(),
3341
+ description: z.string().optional()
3323
3342
  });
3324
- const FieldMetadataSchema = z.object({
3343
+ const DBFieldMetadataSchema = z.object({
3325
3344
  required: z.boolean().optional().describe("Whether the field is required"),
3326
3345
  array: z.boolean().optional().describe("Whether the field is an array"),
3327
3346
  description: z.string().optional().describe("Field description"),
3328
- allowedValues: z.array(AllowedValueSchema).optional().describe("Allowed values for enum fields"),
3347
+ typeName: z.string().optional().describe("Type name for nested or enum fields"),
3348
+ allowedValues: z.array(AllowedValueSchema$1).optional().describe("Allowed values for enum fields"),
3349
+ index: z.boolean().optional().describe("Whether the field is indexed for faster queries"),
3350
+ unique: z.boolean().optional().describe("Whether the field value must be unique"),
3351
+ vector: z.boolean().optional().describe("Whether the field is a vector field for similarity search"),
3352
+ foreignKey: z.boolean().optional().describe("Whether the field is a foreign key"),
3353
+ foreignKeyType: z.string().optional().describe("Target type name for foreign key relations"),
3354
+ foreignKeyField: z.string().optional().describe("Target field name for foreign key relations"),
3329
3355
  hooks: z.object({
3330
- create: functionSchema.optional().describe("Hook function called on creation"),
3331
- update: functionSchema.optional().describe("Hook function called on update")
3332
- }).optional().describe("Lifecycle hooks"),
3333
- typeName: z.string().optional().describe("Type name for nested or enum fields")
3334
- });
3335
- const TailorFieldSchema = z.object({
3336
- type: TailorFieldTypeSchema.describe("Field data type"),
3337
- metadata: FieldMetadataSchema.describe("Field metadata configuration"),
3338
- get fields() {
3339
- return z.record(z.string(), TailorFieldSchema);
3340
- }
3341
- });
3342
- const ResolverSchema = z.object({
3343
- operation: QueryTypeSchema.describe("GraphQL operation type (query or mutation)"),
3344
- name: z.string().describe("Resolver name"),
3345
- description: z.string().optional().describe("Resolver description"),
3346
- input: z.record(z.string(), TailorFieldSchema).optional().describe("Input field definitions"),
3347
- body: functionSchema.describe("Resolver implementation function"),
3348
- output: TailorFieldSchema.describe("Output field definition"),
3349
- publishEvents: z.boolean().optional().describe("Enable publishing events from this resolver")
3350
- });
3351
-
3352
- //#endregion
3353
- //#region src/parser/service/auth/schema.ts
3354
- const AuthInvokerSchema = z.object({
3355
- namespace: z.string().describe("Auth namespace"),
3356
- machineUserName: z.string().describe("Machine user name for authentication")
3357
- });
3358
- const secretValueSchema = z.object({
3359
- vaultName: z.string().describe("Vault name containing the secret"),
3360
- secretKey: z.string().describe("Key of the secret in the vault")
3361
- });
3362
- const OIDCSchema = z.object({
3363
- name: z.string().describe("Identity provider name"),
3364
- kind: z.literal("OIDC"),
3365
- clientID: z.string().describe("OAuth2 client ID"),
3366
- clientSecret: secretValueSchema.describe("OAuth2 client secret"),
3367
- providerURL: z.string().describe("OIDC provider URL"),
3368
- issuerURL: z.string().optional().describe("OIDC issuer URL (defaults to providerURL)"),
3369
- usernameClaim: z.string().optional().describe("JWT claim to use as username")
3370
- });
3371
- const SAMLSchema = z.object({
3372
- name: z.string().describe("Identity provider name"),
3373
- kind: z.literal("SAML"),
3374
- enableSignRequest: z.boolean().default(false).describe("Enable signing of SAML requests"),
3375
- metadataURL: z.string().optional().describe("URL to fetch SAML metadata (mutually exclusive with rawMetadata)"),
3376
- rawMetadata: z.string().optional().describe("Raw SAML metadata XML (mutually exclusive with metadataURL)")
3377
- }).refine((value) => {
3378
- return value.metadataURL !== void 0 !== (value.rawMetadata !== void 0);
3379
- }, "Provide either metadataURL or rawMetadata");
3380
- const IDTokenSchema = z.object({
3381
- name: z.string().describe("Identity provider name"),
3382
- kind: z.literal("IDToken"),
3383
- providerURL: z.string().describe("ID token provider URL"),
3384
- issuerURL: z.string().optional().describe("ID token issuer URL"),
3385
- clientID: z.string().describe("Client ID for ID token validation"),
3386
- usernameClaim: z.string().optional().describe("JWT claim to use as username")
3387
- });
3388
- const BuiltinIdPSchema = z.object({
3389
- name: z.string().describe("Identity provider name"),
3390
- kind: z.literal("BuiltInIdP"),
3391
- namespace: z.string().describe("IdP namespace"),
3392
- clientName: z.string().describe("OAuth2 client name in the IdP")
3393
- });
3394
- const IdProviderSchema = z.discriminatedUnion("kind", [
3395
- OIDCSchema,
3396
- SAMLSchema,
3397
- IDTokenSchema,
3398
- BuiltinIdPSchema
3399
- ]);
3400
- const OAuth2ClientGrantTypeSchema = z.union([z.literal("authorization_code"), z.literal("refresh_token")]).describe("OAuth2 grant type");
3401
- const OAuth2ClientSchema = z.object({
3402
- description: z.string().optional().describe("Client description"),
3403
- grantTypes: z.array(OAuth2ClientGrantTypeSchema).default(["authorization_code", "refresh_token"]).describe("Allowed OAuth2 grant types"),
3404
- redirectURIs: z.array(z.union([
3405
- z.templateLiteral(["https://", z.string()]),
3406
- z.templateLiteral(["http://", z.string()]),
3407
- z.templateLiteral([z.string(), ":url"]),
3408
- z.templateLiteral([
3409
- z.string(),
3410
- ":url/",
3411
- z.string()
3412
- ])
3413
- ])).describe("Allowed redirect URIs"),
3414
- clientType: z.union([
3415
- z.literal("confidential"),
3416
- z.literal("public"),
3417
- z.literal("browser")
3418
- ]).optional().describe("OAuth2 client type"),
3419
- accessTokenLifetimeSeconds: z.number().int().min(60, "Minimum access token lifetime is 60 seconds").max(86400, "Maximum access token lifetime is 1 day (86400 seconds)").optional().describe("Access token lifetime in seconds (60-86400)").transform((val) => val ? {
3420
- seconds: BigInt(val),
3421
- nanos: 0
3422
- } : void 0),
3423
- refreshTokenLifetimeSeconds: z.number().int().min(60, "Minimum refresh token lifetime is 60 seconds").max(604800, "Maximum refresh token lifetime is 7 days (604800 seconds)").optional().describe("Refresh token lifetime in seconds (60-604800)").transform((val) => val ? {
3424
- seconds: BigInt(val),
3425
- nanos: 0
3426
- } : void 0),
3427
- requireDpop: z.boolean().optional().describe("Require DPoP (Demonstrating Proof-of-Possession) for token requests")
3428
- }).refine((data) => !(data.clientType === "browser" && data.requireDpop === true), {
3429
- message: "requireDpop cannot be set to true for browser clients as they don't support DPoP",
3430
- path: ["requireDpop"]
3431
- });
3432
- const SCIMAuthorizationSchema = z.object({
3433
- type: z.union([z.literal("oauth2"), z.literal("bearer")]).describe("SCIM authorization type"),
3434
- bearerSecret: secretValueSchema.optional().describe("Bearer token secret (required for bearer type)")
3435
- });
3436
- const SCIMAttributeTypeSchema = z.union([
3437
- z.literal("string"),
3438
- z.literal("number"),
3439
- z.literal("boolean"),
3440
- z.literal("datetime"),
3441
- z.literal("complex")
3442
- ]).describe("SCIM attribute data type");
3443
- const SCIMAttributeSchema = z.object({
3444
- type: SCIMAttributeTypeSchema.describe("Attribute data type"),
3445
- name: z.string().describe("Attribute name"),
3446
- description: z.string().optional().describe("Attribute description"),
3447
- mutability: z.union([
3448
- z.literal("readOnly"),
3449
- z.literal("readWrite"),
3450
- z.literal("writeOnly")
3451
- ]).optional().describe("Attribute mutability"),
3452
- required: z.boolean().optional().describe("Whether the attribute is required"),
3453
- multiValued: z.boolean().optional().describe("Whether the attribute can have multiple values"),
3454
- uniqueness: z.union([
3455
- z.literal("none"),
3456
- z.literal("server"),
3457
- z.literal("global")
3458
- ]).optional().describe("Uniqueness constraint"),
3459
- canonicalValues: z.array(z.string()).nullable().optional().describe("List of canonical values"),
3460
- get subAttributes() {
3461
- return z.array(SCIMAttributeSchema).nullable().optional();
3462
- }
3463
- });
3464
- const SCIMSchemaSchema = z.object({
3465
- name: z.string().describe("SCIM schema name"),
3466
- attributes: z.array(SCIMAttributeSchema).describe("Schema attributes")
3467
- });
3468
- const SCIMAttributeMappingSchema = z.object({
3469
- tailorDBField: z.string().describe("TailorDB field name to map to"),
3470
- scimPath: z.string().describe("SCIM attribute path")
3471
- });
3472
- const SCIMResourceSchema = z.object({
3473
- name: z.string().describe("SCIM resource name"),
3474
- tailorDBNamespace: z.string().describe("TailorDB namespace for the resource"),
3475
- tailorDBType: z.string().describe("TailorDB type name for the resource"),
3476
- coreSchema: SCIMSchemaSchema.describe("Core SCIM schema definition"),
3477
- attributeMapping: z.array(SCIMAttributeMappingSchema).describe("Attribute mapping configuration")
3478
- });
3479
- const SCIMSchema = z.object({
3480
- machineUserName: z.string().describe("Machine user name for SCIM operations"),
3481
- authorization: SCIMAuthorizationSchema.describe("SCIM authorization configuration"),
3482
- resources: z.array(SCIMResourceSchema).describe("SCIM resource definitions")
3483
- });
3484
- const TenantProviderSchema = z.object({
3485
- namespace: z.string().describe("TailorDB namespace for the tenant type"),
3486
- type: z.string().describe("TailorDB type name for tenants"),
3487
- signatureField: z.string().describe("Field used as the tenant signature")
3356
+ create: functionSchema.optional().describe("Hook function called on record creation"),
3357
+ update: functionSchema.optional().describe("Hook function called on record update")
3358
+ }).optional().describe("Lifecycle hooks for the field"),
3359
+ validate: z.array(z.union([functionSchema, z.tuple([functionSchema, z.string()])])).optional().describe("Validation functions for the field"),
3360
+ serial: z.object({
3361
+ start: z.number().describe("Starting value for the serial sequence"),
3362
+ maxValue: z.number().optional().describe("Maximum value for the serial sequence"),
3363
+ format: z.string().optional().describe("Format string for serial value (string type only)")
3364
+ }).optional().describe("Serial (auto-increment) configuration"),
3365
+ scale: z.number().int().min(0).max(12).optional().describe("Decimal scale (number of digits after decimal point, 0-12)")
3488
3366
  });
3489
- const UserProfileSchema = z.object({
3490
- type: z.object({
3491
- name: z.string(),
3492
- fields: z.any(),
3493
- metadata: z.any(),
3494
- hooks: z.any(),
3495
- validate: z.any(),
3496
- features: z.any(),
3497
- indexes: z.any(),
3498
- files: z.any(),
3499
- permission: z.any(),
3500
- gqlPermission: z.any(),
3501
- _output: z.any()
3367
+ const RelationTypeSchema = z.enum(relationTypesKeys);
3368
+ const RawRelationConfigSchema = z.object({
3369
+ type: RelationTypeSchema.describe("Relation cardinality type"),
3370
+ toward: z.object({
3371
+ type: z.string().describe("Target type name, or 'self' for self-relations"),
3372
+ as: z.string().optional().describe("Custom forward relation name"),
3373
+ key: z.string().optional().describe("Target field to join on (default: 'id')")
3502
3374
  }),
3503
- usernameField: z.string(),
3504
- attributes: z.record(z.string(), z.literal(true)).optional(),
3505
- attributeList: z.array(z.string()).optional()
3375
+ backward: z.string().optional().describe("Backward relation name on the target type")
3376
+ });
3377
+ const TailorDBFieldSchema = z.lazy(() => z.object({
3378
+ type: TailorFieldTypeSchema$1,
3379
+ fields: z.record(z.string(), TailorDBFieldSchema).optional(),
3380
+ metadata: DBFieldMetadataSchema,
3381
+ rawRelation: RawRelationConfigSchema.optional()
3382
+ }));
3383
+ /**
3384
+ * Schema for TailorDB type settings.
3385
+ * Normalizes gqlOperations from alias ("query") to object format.
3386
+ */
3387
+ const TailorDBTypeSettingsSchema = z.object({
3388
+ pluralForm: z.string().optional().describe("Custom plural form of the type name for GraphQL"),
3389
+ aggregation: z.boolean().optional().describe("Enable aggregation queries for this type"),
3390
+ bulkUpsert: z.boolean().optional().describe("Enable bulk upsert mutation for this type"),
3391
+ gqlOperations: GqlOperationsSchema.optional().describe("Configure GraphQL operations for this type. Use \"query\" for read-only mode, or an object for granular control."),
3392
+ publishEvents: z.boolean().optional().describe("Enable publishing events for this type.\nWhen enabled, record creation/update/deletion events are published.\nIf not specified, this is automatically set to true when an executor uses this type\nwith recordCreated/recordUpdated/recordDeleted triggers. If explicitly set to false\nwhile an executor uses this type, an error will be thrown during apply.")
3506
3393
  });
3507
- const ValueOperandSchema = z.union([
3394
+ const GQL_PERMISSION_INVALID_OPERAND_MESSAGE = "operand is not supported in gqlPermission. Use permission() for record-level conditions.";
3395
+ const GqlPermissionOperandSchema = z.union([
3396
+ z.object({ user: z.string() }).strict(),
3508
3397
  z.string(),
3509
3398
  z.boolean(),
3510
3399
  z.array(z.string()),
3511
3400
  z.array(z.boolean())
3401
+ ], { error: (issue) => {
3402
+ if (typeof issue.input === "object" && issue.input !== null) {
3403
+ const keys = Object.keys(issue.input);
3404
+ if (keys.length === 1) return `"${keys[0]}" ${GQL_PERMISSION_INVALID_OPERAND_MESSAGE}`;
3405
+ return "Operand object must have exactly 1 key";
3406
+ }
3407
+ return "Invalid operand in gqlPermission";
3408
+ } });
3409
+ const RecordPermissionOperandSchema = z.union([
3410
+ GqlPermissionOperandSchema,
3411
+ z.object({ record: z.string() }),
3412
+ z.object({ oldRecord: z.string() }),
3413
+ z.object({ newRecord: z.string() })
3512
3414
  ]);
3513
- const MachineUserSchema = z.object({
3514
- attributes: z.record(z.string(), ValueOperandSchema).optional(),
3515
- attributeList: z.array(z.uuid()).optional()
3415
+ const PermissionOperatorSchema = z.enum([
3416
+ "=",
3417
+ "!=",
3418
+ "in",
3419
+ "not in",
3420
+ "hasAny",
3421
+ "not hasAny"
3422
+ ]);
3423
+ const RecordPermissionConditionSchema = z.tuple([
3424
+ RecordPermissionOperandSchema,
3425
+ PermissionOperatorSchema,
3426
+ RecordPermissionOperandSchema
3427
+ ]).readonly();
3428
+ const GqlPermissionConditionSchema = z.tuple([
3429
+ GqlPermissionOperandSchema,
3430
+ PermissionOperatorSchema,
3431
+ GqlPermissionOperandSchema
3432
+ ]).readonly();
3433
+ const ActionPermissionSchema = z.union([
3434
+ z.object({
3435
+ conditions: z.union([RecordPermissionConditionSchema, z.array(RecordPermissionConditionSchema).readonly()]),
3436
+ description: z.string().optional(),
3437
+ permit: z.boolean().optional()
3438
+ }),
3439
+ z.tuple([
3440
+ RecordPermissionOperandSchema,
3441
+ PermissionOperatorSchema,
3442
+ RecordPermissionOperandSchema
3443
+ ]).readonly(),
3444
+ z.tuple([
3445
+ RecordPermissionOperandSchema,
3446
+ PermissionOperatorSchema,
3447
+ RecordPermissionOperandSchema,
3448
+ z.boolean()
3449
+ ]).readonly(),
3450
+ z.array(z.union([RecordPermissionConditionSchema, z.boolean()])).refine((arr) => {
3451
+ const boolIndex = arr.findIndex((item) => typeof item === "boolean");
3452
+ return boolIndex === -1 || boolIndex === arr.length - 1;
3453
+ }, { message: "Boolean permit flag must only appear at the end" }).readonly()
3454
+ ]);
3455
+ const GqlPermissionActionSchema = z.enum([
3456
+ "read",
3457
+ "create",
3458
+ "update",
3459
+ "delete",
3460
+ "aggregate",
3461
+ "bulkUpsert"
3462
+ ]);
3463
+ const GqlPermissionPolicySchema = z.object({
3464
+ conditions: z.array(GqlPermissionConditionSchema).readonly(),
3465
+ actions: z.union([z.literal("all"), z.array(GqlPermissionActionSchema).readonly()]),
3466
+ permit: z.boolean().optional(),
3467
+ description: z.string().optional()
3516
3468
  });
3517
- const AuthConfigBaseSchema = z.object({
3518
- name: z.string().describe("Auth service name"),
3519
- machineUsers: z.record(z.string(), MachineUserSchema).optional().describe("Machine user definitions"),
3520
- oauth2Clients: z.record(z.string(), OAuth2ClientSchema).optional().describe("OAuth2 client definitions"),
3521
- idProvider: IdProviderSchema.optional().describe("Identity provider configuration"),
3522
- scim: SCIMSchema.optional().describe("SCIM provisioning configuration"),
3523
- tenantProvider: TenantProviderSchema.optional().describe("Multi-tenant provider configuration"),
3524
- publishSessionEvents: z.boolean().optional().describe("Enable publishing session events")
3469
+ const RawPermissionsSchema = z.object({
3470
+ record: z.object({
3471
+ create: z.array(ActionPermissionSchema).readonly(),
3472
+ read: z.array(ActionPermissionSchema).readonly(),
3473
+ update: z.array(ActionPermissionSchema).readonly(),
3474
+ delete: z.array(ActionPermissionSchema).readonly()
3475
+ }).optional(),
3476
+ gql: z.array(GqlPermissionPolicySchema).readonly().optional()
3477
+ });
3478
+ const TailorDBTypeSchema = z.object({
3479
+ name: z.string(),
3480
+ fields: z.record(z.string(), TailorDBFieldSchema),
3481
+ metadata: z.object({
3482
+ name: z.string(),
3483
+ description: z.string().optional(),
3484
+ settings: TailorDBTypeSettingsSchema.optional(),
3485
+ permissions: RawPermissionsSchema,
3486
+ files: z.record(z.string(), z.string()),
3487
+ indexes: z.record(z.string(), z.object({
3488
+ fields: z.array(z.string()),
3489
+ unique: z.boolean().optional()
3490
+ })).optional()
3491
+ })
3492
+ });
3493
+ const TailorDBMigrationConfigSchema = z.object({
3494
+ directory: z.string().describe("Directory containing migration files"),
3495
+ machineUser: z.string().optional().describe("Machine user name for migration execution")
3525
3496
  });
3526
- const AuthConfigSchema = z.union([AuthConfigBaseSchema.extend({
3527
- userProfile: z.undefined().optional(),
3528
- machineUserAttributes: z.undefined().optional()
3529
- }), z.xor([AuthConfigBaseSchema.extend({
3530
- userProfile: UserProfileSchema,
3531
- machineUserAttributes: z.undefined().optional()
3532
- }), AuthConfigBaseSchema.extend({
3533
- userProfile: z.undefined().optional(),
3534
- machineUserAttributes: z.record(z.string(), TailorFieldSchema)
3535
- })])]).brand("AuthConfig");
3536
-
3537
- //#endregion
3538
- //#region src/cli/services/auth/service.ts
3539
3497
  /**
3540
- * Creates a new AuthService instance.
3541
- * @param config - The auth configuration
3542
- * @param tailorDBServices - The TailorDB services
3543
- * @param externalTailorDBNamespaces - External TailorDB namespaces
3544
- * @returns A new AuthService instance
3498
+ * Schema for TailorDB service configuration.
3499
+ * Normalizes gqlOperations from alias ("query") to object format.
3545
3500
  */
3546
- function createAuthService(config, tailorDBServices, externalTailorDBNamespaces) {
3547
- const parsedConfig = {
3548
- ...config,
3549
- idProvider: IdProviderSchema.optional().parse(config.idProvider)
3550
- };
3551
- let userProfile;
3552
- return {
3553
- config,
3554
- tailorDBServices,
3555
- externalTailorDBNamespaces,
3556
- parsedConfig,
3557
- get userProfile() {
3558
- return userProfile;
3559
- },
3560
- resolveNamespaces: async () => {
3561
- if (!config.userProfile) return;
3562
- if (config.userProfile.namespace) {
3563
- userProfile = {
3564
- ...config.userProfile,
3565
- namespace: config.userProfile.namespace
3566
- };
3567
- return;
3568
- }
3569
- const totalNamespaceCount = tailorDBServices.length + externalTailorDBNamespaces.length;
3570
- let userProfileNamespace;
3571
- if (totalNamespaceCount === 1) userProfileNamespace = tailorDBServices[0]?.namespace ?? externalTailorDBNamespaces[0];
3572
- else {
3573
- await Promise.all(tailorDBServices.map((tailordb) => tailordb.loadTypes()));
3574
- const userProfileTypeName = typeof config.userProfile.type === "object" && "name" in config.userProfile.type ? config.userProfile.type.name : void 0;
3575
- if (userProfileTypeName) for (const service of tailorDBServices) {
3576
- const types = service.types;
3577
- if (Object.prototype.hasOwnProperty.call(types, userProfileTypeName)) {
3578
- userProfileNamespace = service.namespace;
3579
- break;
3580
- }
3581
- }
3582
- if (!userProfileNamespace) throw new Error(`userProfile type "${config.userProfile.type.name}" not found in any TailorDB namespace`);
3583
- }
3584
- userProfile = {
3585
- ...config.userProfile,
3586
- namespace: userProfileNamespace
3587
- };
3588
- }
3589
- };
3590
- }
3501
+ const TailorDBServiceConfigSchema = z.object({
3502
+ files: z.array(z.string()).describe("Glob patterns for TailorDB type definition files"),
3503
+ ignores: z.array(z.string()).optional().describe("Glob patterns to exclude from type discovery"),
3504
+ erdSite: z.string().optional().describe("URL for the ERD (Entity Relationship Diagram) site"),
3505
+ migration: TailorDBMigrationConfigSchema.optional().describe("Migration configuration"),
3506
+ gqlOperations: GqlOperationsSchema.optional().describe("Default GraphQL operations for all types in this service")
3507
+ });
3591
3508
 
3592
3509
  //#endregion
3593
- //#region src/cli/services/stale-cleanup.ts
3510
+ //#region src/cli/services/tailordb/es-builtins.ts
3511
+ const globalsMap = globals.default ?? globals;
3594
3512
  /**
3595
- * Remove stale `.entry.js` files from the output directory.
3513
+ * Runtime globals available in the PF execution environment.
3514
+ * Identifiers in this set are excluded from free variable detection
3515
+ * since they are always available in the runtime environment.
3596
3516
  *
3597
- * Must be called before parallel bundling; concurrent builds
3598
- * sharing the same output directory would otherwise conflict.
3599
- * @param outputDir - Directory to clean
3600
- */
3601
- async function removeStaleEntryFiles(outputDir) {
3602
- const files = await fs.readdir(outputDir);
3603
- await Promise.all(files.filter((file) => file.endsWith(".entry.js")).map((file) => fs.rm(path.join(outputDir, file), { force: true })));
3604
- }
3605
-
3606
- //#endregion
3607
- //#region src/cli/services/workflow/ast-utils.ts
3608
- /**
3609
- * Check if a module source is from the Tailor SDK package (including subpaths)
3610
- * @param source - Module source string
3611
- * @returns True if the source is from the Tailor SDK package
3612
- */
3613
- function isTailorSdkSource(source) {
3614
- return /^@tailor-platform\/sdk(\/|$)/.test(source);
3615
- }
3616
- /**
3617
- * Get the source string from a dynamic import or require call
3618
- * @param node - AST node to inspect
3619
- * @returns Resolved import/require source string or null
3620
- */
3621
- function getImportSource(node) {
3622
- if (!node) return null;
3623
- if (node.type === "ImportExpression") {
3624
- const source = node.source;
3625
- if (source.type === "Literal" && typeof source.value === "string") return source.value;
3626
- }
3627
- if (node.type === "CallExpression") {
3628
- const callExpr = node;
3629
- if (callExpr.callee.type === "Identifier" && callExpr.callee.name === "require") {
3630
- const arg = callExpr.arguments[0];
3631
- if (arg && "type" in arg && arg.type === "Literal" && "value" in arg && typeof arg.value === "string") return arg.value;
3632
- }
3633
- }
3634
- return null;
3635
- }
3636
- /**
3637
- * Unwrap AwaitExpression to get the inner expression
3638
- * @param node - AST expression node
3639
- * @returns Inner expression if node is an AwaitExpression
3640
- */
3641
- function unwrapAwait(node) {
3642
- if (node?.type === "AwaitExpression") return node.argument;
3643
- return node;
3644
- }
3645
- /**
3646
- * Check if a node is a string literal
3647
- * @param node - AST expression node
3648
- * @returns True if node is a string literal
3649
- */
3650
- function isStringLiteral(node) {
3651
- return node?.type === "Literal" && typeof node.value === "string";
3652
- }
3653
- /**
3654
- * Check if a node is a function expression (arrow or regular)
3655
- * @param node - AST expression node
3656
- * @returns True if node is a function expression
3517
+ * Combines globals.builtin (ECMAScript language builtins) and
3518
+ * globals['shared-node-browser'] (shared runtime globals like
3519
+ * console, fetch, setTimeout, etc.) from the `globals` npm package.
3657
3520
  */
3658
- function isFunctionExpression(node) {
3659
- return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
3660
- }
3521
+ const ES_BUILTINS = new Set([...Object.keys(globalsMap.builtin ?? {}), ...Object.keys(globalsMap["shared-node-browser"] ?? {})]);
3522
+
3523
+ //#endregion
3524
+ //#region src/cli/services/tailordb/hooks-validate-bundler.ts
3661
3525
  /**
3662
- * Find a property in an object expression
3663
- * @param properties - Object properties to search
3664
- * @param name - Property name to find
3665
- * @returns Found property info or null
3526
+ * Recursively extract binding names from a destructuring pattern node.
3527
+ * @param pattern - The binding pattern AST node.
3528
+ * @param bindings - Set to collect binding names into.
3666
3529
  */
3667
- function findProperty(properties, name) {
3668
- for (const prop of properties) if (prop.type === "Property") {
3669
- const objProp = prop;
3670
- if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === name) return {
3671
- key: objProp.key,
3672
- value: objProp.value,
3673
- start: objProp.start,
3674
- end: objProp.end
3675
- };
3530
+ function collectBindingsFromPattern(pattern, bindings) {
3531
+ switch (pattern.type) {
3532
+ case "Identifier":
3533
+ bindings.add(pattern.name);
3534
+ break;
3535
+ case "ObjectPattern":
3536
+ for (const prop of pattern.properties) if (prop.type === "RestElement") collectBindingsFromPattern(prop.argument, bindings);
3537
+ else collectBindingsFromPattern(prop.value, bindings);
3538
+ break;
3539
+ case "ArrayPattern":
3540
+ for (const elem of pattern.elements) if (elem) if (elem.type === "RestElement") collectBindingsFromPattern(elem.argument, bindings);
3541
+ else collectBindingsFromPattern(elem, bindings);
3542
+ break;
3543
+ case "AssignmentPattern":
3544
+ collectBindingsFromPattern(pattern.left, bindings);
3545
+ break;
3676
3546
  }
3677
- return null;
3678
3547
  }
3679
- /**
3680
- * Apply string replacements to source code
3681
- * Replacements are applied from end to start to maintain positions
3682
- * @param source - Original source code
3683
- * @param replacements - Replacements to apply
3684
- * @returns Transformed source code
3685
- */
3686
- function applyReplacements(source, replacements) {
3687
- const sorted = [...replacements].sort((a, b) => b.start - a.start);
3688
- let result = source;
3689
- for (const r of sorted) result = result.slice(0, r.start) + r.text + result.slice(r.end);
3690
- return result;
3548
+ /** Fields that contain TypeScript type annotations (not runtime references). */
3549
+ const TS_TYPE_FIELDS = new Set([
3550
+ "typeAnnotation",
3551
+ "typeParameters",
3552
+ "returnType",
3553
+ "superTypeArguments",
3554
+ "typeArguments"
3555
+ ]);
3556
+ function isBindingPattern(param) {
3557
+ return param.type !== "TSParameterProperty";
3691
3558
  }
3692
- /**
3693
- * Find the end of a statement including any trailing newline
3694
- * @param source - Source code
3695
- * @param position - Start position of the statement
3696
- * @returns Index of the end of the statement including trailing newline
3697
- */
3698
- function findStatementEnd(source, position) {
3699
- let i = position;
3700
- while (i < source.length && (source[i] === ";" || source[i] === " " || source[i] === " ")) i++;
3701
- if (i < source.length && source[i] === "\n") i++;
3702
- return i;
3559
+ function toScriptFunction(value) {
3560
+ if (typeof value !== "function") return void 0;
3561
+ return value;
3703
3562
  }
3704
- /**
3705
- * Resolve a relative path from a base directory
3706
- * Simple implementation that handles ./ and ../ prefixes
3707
- * @param baseDir - Base directory
3708
- * @param relativePath - Relative path to resolve
3709
- * @returns Resolved absolute path
3710
- */
3711
- function resolvePath(baseDir, relativePath) {
3712
- const parts = relativePath.replace(/\\/g, "/").split("/");
3713
- const baseParts = baseDir.replace(/\\/g, "/").split("/");
3714
- for (const part of parts) if (part === ".") {} else if (part === "..") baseParts.pop();
3715
- else baseParts.push(part);
3716
- return baseParts.join("/");
3563
+ function collectScriptTargets(type) {
3564
+ const targets = [];
3565
+ const collectFieldTargets = (field) => {
3566
+ const metadata = field.metadata;
3567
+ const createHook = toScriptFunction(metadata.hooks?.create);
3568
+ if (createHook) targets.push({
3569
+ fn: createHook,
3570
+ kind: "hooks"
3571
+ });
3572
+ const updateHook = toScriptFunction(metadata.hooks?.update);
3573
+ if (updateHook) targets.push({
3574
+ fn: updateHook,
3575
+ kind: "hooks"
3576
+ });
3577
+ for (const validateInput of metadata.validate ?? []) if (typeof validateInput === "function") {
3578
+ const validateFn = toScriptFunction(validateInput);
3579
+ if (validateFn) targets.push({
3580
+ fn: validateFn,
3581
+ kind: "validate"
3582
+ });
3583
+ } else {
3584
+ const validateFn = toScriptFunction(validateInput[0]);
3585
+ if (validateFn) targets.push({
3586
+ fn: validateFn,
3587
+ kind: "validate"
3588
+ });
3589
+ }
3590
+ if (field.type === "nested" && field.fields) for (const nestedField of Object.values(field.fields)) collectFieldTargets(nestedField);
3591
+ };
3592
+ for (const field of Object.values(type.fields)) collectFieldTargets(field);
3593
+ return targets;
3717
3594
  }
3718
-
3719
- //#endregion
3720
- //#region src/cli/services/workflow/sdk-binding-collector.ts
3721
3595
  /**
3722
- * Collect all import bindings for a specific function from the Tailor SDK package
3723
- * Returns a Set of local names that refer to the function
3724
- * @param program - Parsed TypeScript program
3725
- * @param functionName - Function name to collect bindings for
3726
- * @returns Set of local names bound to the SDK function
3596
+ * Parse a code string with oxc-parser and return identifiers that are referenced
3597
+ * but never bound anywhere in the snippet (free variables), excluding ES builtins.
3598
+ * @param code - Valid JavaScript code to analyze.
3599
+ * @returns Set of undefined variable names.
3727
3600
  */
3728
- function collectSdkBindings(program, functionName) {
3601
+ function findUndefinedReferences(code) {
3602
+ const { program } = parseSync("_.js", code);
3603
+ const references = /* @__PURE__ */ new Set();
3729
3604
  const bindings = /* @__PURE__ */ new Set();
3730
- function walk(node) {
3731
- if (!node || typeof node !== "object") return;
3732
- const nodeType = node.type;
3733
- if (nodeType === "ImportDeclaration") {
3734
- const importDecl = node;
3735
- const source = importDecl.source?.value;
3736
- if (typeof source === "string" && isTailorSdkSource(source)) {
3737
- for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportSpecifier") {
3738
- const importSpec = specifier;
3739
- const imported = importSpec.imported.type === "Identifier" ? importSpec.imported.name : importSpec.imported.value;
3740
- if (imported === functionName) bindings.add(importSpec.local?.name || imported);
3741
- } else if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
3742
- const spec = specifier;
3743
- bindings.add(`__namespace__:${spec.local?.name}`);
3605
+ const walk = (node) => {
3606
+ if (!node) return;
3607
+ switch (node.type) {
3608
+ case "VariableDeclarator":
3609
+ collectBindingsFromPattern(node.id, bindings);
3610
+ walk(node.init);
3611
+ return;
3612
+ case "FunctionDeclaration":
3613
+ case "FunctionExpression":
3614
+ if (node.id) bindings.add(node.id.name);
3615
+ for (const param of node.params) if (isBindingPattern(param)) {
3616
+ collectBindingsFromPattern(param, bindings);
3617
+ walk(param);
3744
3618
  }
3745
- }
3746
- }
3747
- if (nodeType === "VariableDeclaration") {
3748
- const varDecl = node;
3749
- for (const decl of varDecl.declarations || []) {
3750
- const source = getImportSource(unwrapAwait(decl.init));
3751
- if (source && isTailorSdkSource(source)) {
3752
- const id = decl.id;
3753
- if (id?.type === "Identifier") bindings.add(`__namespace__:${id.name}`);
3754
- else if (id?.type === "ObjectPattern") {
3755
- const objPattern = id;
3756
- for (const prop of objPattern.properties || []) if (prop.type === "Property") {
3757
- const bindingProp = prop;
3758
- const keyName = bindingProp.key.type === "Identifier" ? bindingProp.key.name : bindingProp.key.value;
3759
- if (keyName === functionName) {
3760
- const localName = bindingProp.value.type === "Identifier" ? bindingProp.value.name : keyName;
3761
- bindings.add(localName ?? "");
3762
- }
3763
- }
3764
- }
3619
+ walk(node.body);
3620
+ return;
3621
+ case "ArrowFunctionExpression":
3622
+ for (const param of node.params) if (isBindingPattern(param)) {
3623
+ collectBindingsFromPattern(param, bindings);
3624
+ walk(param);
3765
3625
  }
3766
- }
3626
+ walk(node.body);
3627
+ return;
3628
+ case "ClassDeclaration":
3629
+ case "ClassExpression":
3630
+ if (node.id) bindings.add(node.id.name);
3631
+ walk(node.superClass);
3632
+ walk(node.body);
3633
+ return;
3634
+ case "CatchClause":
3635
+ if (node.param) collectBindingsFromPattern(node.param, bindings);
3636
+ walk(node.body);
3637
+ return;
3638
+ case "MemberExpression":
3639
+ walk(node.object);
3640
+ if (node.computed) walk(node.property);
3641
+ return;
3642
+ case "Property":
3643
+ if (node.computed) walk(node.key);
3644
+ walk(node.value);
3645
+ return;
3646
+ case "LabeledStatement":
3647
+ walk(node.body);
3648
+ return;
3649
+ case "Identifier":
3650
+ references.add(node.name);
3651
+ return;
3767
3652
  }
3768
- for (const key of Object.keys(node)) {
3769
- const child = node[key];
3770
- if (Array.isArray(child)) child.forEach((c) => walk(c));
3771
- else if (child && typeof child === "object") walk(child);
3653
+ const rec = node;
3654
+ for (const [key, value] of Object.entries(rec)) {
3655
+ if (key === "type" || TS_TYPE_FIELDS.has(key)) continue;
3656
+ if (Array.isArray(value)) for (const item of value) walk(item);
3657
+ else if (value && typeof value === "object" && "type" in value) walk(value);
3772
3658
  }
3773
- }
3659
+ };
3774
3660
  walk(program);
3775
- return bindings;
3661
+ const freeVars = /* @__PURE__ */ new Set();
3662
+ for (const ref of references) if (!bindings.has(ref) && !ES_BUILTINS.has(ref)) freeVars.add(ref);
3663
+ return freeVars;
3776
3664
  }
3777
3665
  /**
3778
- * Check if a CallExpression is a call to a specific SDK function
3779
- * @param node - AST node to inspect
3780
- * @param bindings - Collected SDK bindings
3781
- * @param functionName - SDK function name
3782
- * @returns True if node is a call to the SDK function
3666
+ * Collect all Identifier names from a TypeScript/JavaScript code string using oxc-parser.
3667
+ * @param code - Code string to analyze.
3668
+ * @returns Set of identifier names found in the code.
3783
3669
  */
3784
- function isSdkFunctionCall(node, bindings, functionName) {
3785
- if (node.type !== "CallExpression") return false;
3786
- const callee = node.callee;
3787
- if (callee.type === "Identifier") {
3788
- const identifier = callee;
3789
- return bindings.has(identifier.name);
3790
- }
3791
- if (callee.type === "MemberExpression") {
3792
- const memberExpr = callee;
3793
- if (!memberExpr.computed) {
3794
- const object = memberExpr.object;
3795
- const property = memberExpr.property;
3796
- if (object.type === "Identifier" && bindings.has(`__namespace__:${object.name}`) && property.name === functionName) return true;
3670
+ function collectIdentifierNames(code) {
3671
+ const { program } = parseSync("_.ts", code);
3672
+ const names = /* @__PURE__ */ new Set();
3673
+ const walk = (node) => {
3674
+ if (!node || typeof node !== "object") return;
3675
+ const record = node;
3676
+ if (record.type === "Identifier" && typeof record.name === "string") names.add(record.name);
3677
+ for (const [key, value] of Object.entries(record)) {
3678
+ if (key === "property" && record.type === "MemberExpression" && !record.computed) continue;
3679
+ if (key === "key" && record.type === "Property" && !record.computed) continue;
3680
+ if (TS_TYPE_FIELDS.has(key)) continue;
3681
+ if (Array.isArray(value)) for (const item of value) walk(item);
3682
+ else if (value && typeof value === "object" && "type" in value) walk(value);
3797
3683
  }
3798
- }
3799
- return false;
3684
+ };
3685
+ walk(program);
3686
+ return names;
3800
3687
  }
3801
-
3802
- //#endregion
3803
- //#region src/cli/services/workflow/job-detector.ts
3804
3688
  /**
3805
- * Find all workflow jobs by detecting createWorkflowJob calls from `@tailor-platform/sdk`
3806
- * @param program - Parsed TypeScript program
3807
- * @param _sourceText - Source code text (currently unused)
3808
- * @returns Detected job locations
3689
+ * Collect top-level bindings (imports and declarations) from a TypeScript source file.
3690
+ * @param sourceFilePath - Absolute path to the source file.
3691
+ * @returns Map of binding name to SourceBinding.
3809
3692
  */
3810
- function findAllJobs(program, _sourceText) {
3811
- const jobs = [];
3812
- const bindings = collectSdkBindings(program, "createWorkflowJob");
3813
- function walk(node, parents = []) {
3814
- if (!node || typeof node !== "object") return;
3815
- if (isSdkFunctionCall(node, bindings, "createWorkflowJob")) {
3816
- const args = node.arguments;
3817
- if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
3818
- const configObj = args[0];
3819
- const nameProp = findProperty(configObj.properties, "name");
3820
- const bodyProp = findProperty(configObj.properties, "body");
3821
- if (nameProp && isStringLiteral(nameProp.value) && bodyProp && isFunctionExpression(bodyProp.value)) {
3822
- let statementRange;
3823
- let exportName;
3824
- for (let i = parents.length - 1; i >= 0; i--) {
3825
- const parent = parents[i];
3826
- if (parent.type === "VariableDeclarator") {
3827
- const declarator = parent;
3828
- if (declarator.id?.type === "Identifier") exportName = declarator.id.name;
3829
- }
3830
- if (parent.type === "ExportNamedDeclaration" || parent.type === "VariableDeclaration") statementRange = {
3831
- start: parent.start,
3832
- end: parent.end
3833
- };
3834
- }
3835
- jobs.push({
3836
- name: nameProp.value.value,
3837
- exportName,
3838
- nameRange: {
3839
- start: nameProp.start,
3840
- end: nameProp.end
3841
- },
3842
- bodyValueRange: {
3843
- start: bodyProp.value.start,
3844
- end: bodyProp.value.end
3845
- },
3846
- statementRange
3847
- });
3848
- }
3849
- }
3693
+ function collectSourceBindings(sourceFilePath) {
3694
+ const source = readFileSync(sourceFilePath, "utf-8");
3695
+ const { program } = parseSync(sourceFilePath, source);
3696
+ const bindings = /* @__PURE__ */ new Map();
3697
+ for (const stmt of program.body) if (stmt.type === "ImportDeclaration") {
3698
+ const importDecl = stmt;
3699
+ const text = source.slice(importDecl.start, importDecl.end);
3700
+ if (importDecl.specifiers) for (const spec of importDecl.specifiers) bindings.set(spec.local.name, {
3701
+ name: spec.local.name,
3702
+ sourceText: text,
3703
+ kind: "import"
3704
+ });
3705
+ } else if (stmt.type === "VariableDeclaration") {
3706
+ const varDecl = stmt;
3707
+ const text = source.slice(varDecl.start, varDecl.end);
3708
+ for (const decl of varDecl.declarations) if (decl.id.type === "Identifier") bindings.set(decl.id.name, {
3709
+ name: decl.id.name,
3710
+ sourceText: text,
3711
+ kind: "declaration"
3712
+ });
3713
+ } else if (stmt.type === "FunctionDeclaration") {
3714
+ const funcDecl = stmt;
3715
+ if (funcDecl.id) {
3716
+ const text = source.slice(funcDecl.start, funcDecl.end);
3717
+ bindings.set(funcDecl.id.name, {
3718
+ name: funcDecl.id.name,
3719
+ sourceText: text,
3720
+ kind: "declaration"
3721
+ });
3850
3722
  }
3851
- const newParents = [...parents, node];
3852
- for (const key of Object.keys(node)) {
3853
- const child = node[key];
3854
- if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
3855
- else if (child && typeof child === "object") walk(child, newParents);
3723
+ } else if (stmt.type === "ExportNamedDeclaration") {
3724
+ const innerDecl = stmt.declaration;
3725
+ if (!innerDecl) continue;
3726
+ if (innerDecl.type === "VariableDeclaration") {
3727
+ const varDecl = innerDecl;
3728
+ const text = source.slice(varDecl.start, varDecl.end);
3729
+ for (const decl of varDecl.declarations) if (decl.id.type === "Identifier") bindings.set(decl.id.name, {
3730
+ name: decl.id.name,
3731
+ sourceText: text,
3732
+ kind: "declaration"
3733
+ });
3734
+ } else if (innerDecl.type === "FunctionDeclaration") {
3735
+ const funcDecl = innerDecl;
3736
+ if (funcDecl.id) {
3737
+ const text = source.slice(funcDecl.start, funcDecl.end);
3738
+ bindings.set(funcDecl.id.name, {
3739
+ name: funcDecl.id.name,
3740
+ sourceText: text,
3741
+ kind: "declaration"
3742
+ });
3743
+ }
3856
3744
  }
3857
3745
  }
3858
- walk(program);
3859
- return jobs;
3746
+ return bindings;
3860
3747
  }
3861
3748
  /**
3862
- * Build a map from export name to job name from detected jobs
3863
- * @param jobs - Detected job locations
3864
- * @returns Map from export name to job name
3749
+ * Resolve all bindings needed by a function, recursively including
3750
+ * dependencies of top-level declarations.
3751
+ * @param freeVars - Set of free variable names extracted from the function.
3752
+ * @param sourceBindings - Available bindings from the source file.
3753
+ * @returns Object with needed import statements and declaration texts.
3865
3754
  */
3866
- function buildJobNameMap(jobs) {
3867
- const map = /* @__PURE__ */ new Map();
3868
- for (const job of jobs) if (job.exportName) map.set(job.exportName, job.name);
3869
- return map;
3755
+ function resolveNeededBindings(freeVars, sourceBindings) {
3756
+ const neededImports = /* @__PURE__ */ new Set();
3757
+ const neededDeclarations = /* @__PURE__ */ new Set();
3758
+ const unresolved = [];
3759
+ const resolved = /* @__PURE__ */ new Set();
3760
+ const resolveVars = (vars) => {
3761
+ for (const varName of vars) {
3762
+ if (resolved.has(varName)) continue;
3763
+ resolved.add(varName);
3764
+ const binding = sourceBindings.get(varName);
3765
+ if (!binding) {
3766
+ unresolved.push(varName);
3767
+ continue;
3768
+ }
3769
+ if (binding.kind === "import") neededImports.add(binding.sourceText);
3770
+ else {
3771
+ const identifiers = collectIdentifierNames(binding.sourceText);
3772
+ const referencedVars = /* @__PURE__ */ new Set();
3773
+ for (const id of identifiers) if (id !== varName && sourceBindings.has(id)) referencedVars.add(id);
3774
+ resolveVars(referencedVars);
3775
+ neededDeclarations.add(binding.sourceText);
3776
+ }
3777
+ }
3778
+ };
3779
+ resolveVars(freeVars);
3780
+ return {
3781
+ imports: [...neededImports],
3782
+ declarations: [...neededDeclarations],
3783
+ unresolved
3784
+ };
3785
+ }
3786
+ function buildPrecompiledExpr(bundleCode) {
3787
+ return `(() => {
3788
+ const module = { exports: {} };
3789
+ const exports = module.exports;
3790
+ ${bundleCode}\n return module.exports.main({ value: _value, data: _data, user: ${tailorUserMap} });\n})()`;
3870
3791
  }
3871
3792
  /**
3872
- * Detect all .trigger() calls in the source code
3873
- * Returns information about each trigger call for transformation
3874
- * @param program - Parsed TypeScript program
3875
- * @param sourceText - Source code text
3876
- * @returns Detected trigger calls
3793
+ * Build entry file content from already-resolved imports and declarations.
3794
+ * @param imports - Import statement texts.
3795
+ * @param declarations - Declaration statement texts.
3796
+ * @param fnSource - The function source code.
3797
+ * @param sourceFilePath - Path to the source file for resolving relative imports.
3798
+ * @returns Entry file content string.
3877
3799
  */
3878
- function detectTriggerCalls(program, sourceText) {
3879
- const calls = [];
3880
- function walk(node, parent = null) {
3881
- if (!node || typeof node !== "object") return;
3882
- if (node.type === "CallExpression") {
3883
- const callExpr = node;
3884
- const callee = callExpr.callee;
3885
- if (callee.type === "MemberExpression") {
3886
- const memberExpr = callee;
3887
- if (!memberExpr.computed && memberExpr.object.type === "Identifier" && memberExpr.property.name === "trigger") {
3888
- const identifierName = memberExpr.object.name;
3889
- let argsText = "";
3890
- if (callExpr.arguments.length > 0) {
3891
- const firstArg = callExpr.arguments[0];
3892
- const lastArg = callExpr.arguments[callExpr.arguments.length - 1];
3893
- if (firstArg && lastArg && "start" in firstArg && "end" in lastArg) argsText = sourceText.slice(firstArg.start, lastArg.end);
3894
- }
3895
- const hasAwait = parent?.type === "AwaitExpression";
3896
- const awaitExpr = hasAwait ? parent : null;
3897
- const callRange = {
3898
- start: callExpr.start,
3899
- end: callExpr.end
3900
- };
3901
- const fullRange = awaitExpr ? {
3902
- start: awaitExpr.start,
3903
- end: awaitExpr.end
3904
- } : callRange;
3905
- calls.push({
3906
- identifierName,
3907
- callRange,
3908
- argsText,
3909
- hasAwait,
3910
- fullRange
3911
- });
3912
- }
3913
- }
3914
- }
3915
- for (const key of Object.keys(node)) {
3916
- const child = node[key];
3917
- if (Array.isArray(child)) child.forEach((c) => walk(c, node));
3918
- else if (child && typeof child === "object") walk(child, node);
3919
- }
3800
+ function buildMinimalEntryFromResolved(imports, declarations, fnSource, sourceFilePath) {
3801
+ const sourceDir = resolve(sourceFilePath, "..").replace(/\\/g, "/");
3802
+ return [
3803
+ ...imports.map((imp) => imp.replace(/from\s+["'](\.[^"']+)["']/g, (_match, relPath) => `from "${resolve(sourceDir, relPath).replace(/\\/g, "/")}"`)),
3804
+ ...declarations,
3805
+ `export function main(input) { return (${fnSource})(input); }`
3806
+ ].join("\n");
3807
+ }
3808
+ async function bundleScriptTarget(args) {
3809
+ const { fn, kind, sourceFilePath, sourceBindings, tempDir, targetIndex, tsconfig } = args;
3810
+ const fnSource = stringifyFunction(fn);
3811
+ const inlineExpr = `(${fnSource})({ value: _value, data: _data, user: ${tailorUserMap} })`;
3812
+ const freeVars = findUndefinedReferences(`const __fn = ${fnSource};`);
3813
+ if (freeVars.size === 0) return inlineExpr;
3814
+ const { imports, declarations, unresolved } = resolveNeededBindings(freeVars, sourceBindings);
3815
+ if (unresolved.length > 0) throw new Error(`${kind} in ${sourceFilePath} captures unresolvable variables (${unresolved.join(", ")}). Hooks and validators must not reference variables that cannot be resolved from the source file.
3816
+ ${kind}: ${fnSource}`);
3817
+ const entryContent = buildMinimalEntryFromResolved(imports, declarations, fnSource, sourceFilePath);
3818
+ const entryPath = join(tempDir, `tailordb-script-${targetIndex}.entry.ts`);
3819
+ const outputPath = join(tempDir, `tailordb-script-${targetIndex}.bundle.cjs`);
3820
+ writeFileSync(entryPath, entryContent);
3821
+ await rolldown.build(rolldown.defineConfig({
3822
+ input: entryPath,
3823
+ output: {
3824
+ file: outputPath,
3825
+ format: "cjs",
3826
+ sourcemap: false,
3827
+ minify: true,
3828
+ codeSplitting: false
3829
+ },
3830
+ tsconfig,
3831
+ treeshake: {
3832
+ moduleSideEffects: false,
3833
+ annotations: true,
3834
+ unknownGlobalSideEffects: false
3835
+ },
3836
+ logLevel: "silent"
3837
+ }));
3838
+ return buildPrecompiledExpr(readFileSync(outputPath, "utf-8"));
3839
+ }
3840
+ /**
3841
+ * Precompile TailorDB hooks/validators into self-contained script expressions using rolldown.
3842
+ * Uses oxc-parser AST walking to extract free variables from functions, then builds
3843
+ * minimal entry points containing only the needed imports and declarations.
3844
+ * @param type - TailorDB type schema output.
3845
+ * @param sourceFilePath - Source file where the type is defined.
3846
+ * @param tsconfig - Resolved tsconfig path, or undefined if not found.
3847
+ */
3848
+ async function precompileTailorDBTypeScripts(type, sourceFilePath, tsconfig) {
3849
+ const targets = collectScriptTargets(type);
3850
+ if (targets.length === 0) return;
3851
+ const sourceBindings = collectSourceBindings(sourceFilePath);
3852
+ const tempDir = resolve(getDistDir(), "hooks-validate-scripts", type.name);
3853
+ mkdirSync(tempDir, { recursive: true });
3854
+ try {
3855
+ const results = await Promise.allSettled(targets.map((target, index) => bundleScriptTarget({
3856
+ fn: target.fn,
3857
+ kind: target.kind,
3858
+ sourceFilePath,
3859
+ sourceBindings,
3860
+ tempDir,
3861
+ targetIndex: index,
3862
+ tsconfig
3863
+ })));
3864
+ const firstError = results.find((r) => r.status === "rejected");
3865
+ if (firstError && firstError.status === "rejected") throw firstError.reason;
3866
+ for (const [index, result] of results.entries()) if (result.status === "fulfilled") setPrecompiledScriptExpr(targets[index].fn, result.value);
3867
+ } finally {
3868
+ rmSync(tempDir, {
3869
+ recursive: true,
3870
+ force: true
3871
+ });
3920
3872
  }
3921
- walk(program);
3922
- return calls;
3923
3873
  }
3924
3874
 
3925
3875
  //#endregion
3926
- //#region src/cli/services/workflow/workflow-detector.ts
3876
+ //#region src/cli/services/tailordb/service.ts
3927
3877
  /**
3928
- * Find all workflows by detecting createWorkflow calls from `@tailor-platform/sdk`
3929
- * @param program - Parsed TypeScript program
3930
- * @param _sourceText - Source code text (currently unused)
3931
- * @returns Detected workflows
3878
+ * Creates a new TailorDBService instance.
3879
+ * @param params - Parameters for creating the service
3880
+ * @returns A new TailorDBService instance
3932
3881
  */
3933
- function findAllWorkflows(program, _sourceText) {
3934
- const workflows = [];
3935
- const bindings = collectSdkBindings(program, "createWorkflow");
3936
- function walk(node, parents = []) {
3937
- if (!node || typeof node !== "object") return;
3938
- if (isSdkFunctionCall(node, bindings, "createWorkflow")) {
3939
- const args = node.arguments;
3940
- if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
3941
- const configObj = args[0];
3942
- const nameProp = findProperty(configObj.properties, "name");
3943
- if (nameProp && isStringLiteral(nameProp.value)) {
3944
- let exportName;
3945
- let isDefaultExport = false;
3946
- for (let i = parents.length - 1; i >= 0; i--) {
3947
- const parent = parents[i];
3948
- if (parent.type === "VariableDeclarator") {
3949
- const declarator = parent;
3950
- if (declarator.id?.type === "Identifier") {
3951
- exportName = declarator.id.name;
3952
- break;
3953
- }
3954
- }
3955
- if (parent.type === "ExportDefaultDeclaration") isDefaultExport = true;
3956
- }
3957
- workflows.push({
3958
- name: nameProp.value.value,
3959
- exportName,
3960
- isDefaultExport
3961
- });
3962
- }
3882
+ function createTailorDBService(params) {
3883
+ const { namespace, config, pluginManager } = params;
3884
+ const rawTypes = {};
3885
+ let types = {};
3886
+ const typeSourceInfo = {};
3887
+ const pluginAttachments = /* @__PURE__ */ new Map();
3888
+ let loadPromise;
3889
+ const doParseTypes = () => {
3890
+ const allTypes = {};
3891
+ for (const fileTypes of Object.values(rawTypes)) for (const [typeName, type] of Object.entries(fileTypes)) allTypes[typeName] = type;
3892
+ types = parseTypes(allTypes, namespace, typeSourceInfo);
3893
+ };
3894
+ /**
3895
+ * Process plugins for a type and add generated types to rawTypes
3896
+ * @param rawType - The raw TailorDB type being processed
3897
+ * @param attachments - Plugin attachments for this type
3898
+ * @param sourceFilePath - The file path where the type was loaded from
3899
+ */
3900
+ const processPluginsForType = async (rawType, attachments, sourceFilePath) => {
3901
+ if (!pluginManager) return;
3902
+ let currentType = rawType;
3903
+ for (const attachment of attachments) {
3904
+ const result = await pluginManager.processAttachment({
3905
+ type: currentType,
3906
+ typeConfig: attachment.config,
3907
+ namespace,
3908
+ pluginId: attachment.pluginId
3909
+ });
3910
+ if (!result.success) {
3911
+ logger.error(result.error);
3912
+ throw new Error(result.error);
3913
+ }
3914
+ const output = result.output;
3915
+ const extendFields = output.extends?.fields;
3916
+ if (extendFields && Object.keys(extendFields).length > 0) {
3917
+ const extendedType = pluginManager.extendType({
3918
+ originalType: currentType,
3919
+ extendFields,
3920
+ pluginId: attachment.pluginId
3921
+ });
3922
+ rawTypes[sourceFilePath][currentType.name] = extendedType;
3923
+ currentType = extendedType;
3924
+ logger.log(` Extended: ${styles.success(currentType.name)} with ${styles.highlight(Object.keys(extendFields).length.toString())} fields by plugin ${styles.info(attachment.pluginId)}`);
3925
+ }
3926
+ const plugin = pluginManager.getPlugin(attachment.pluginId);
3927
+ for (const [kind, generatedType] of Object.entries(output.types ?? {})) {
3928
+ rawTypes[sourceFilePath][generatedType.name] = generatedType;
3929
+ typeSourceInfo[generatedType.name] = {
3930
+ exportName: generatedType.name,
3931
+ pluginId: attachment.pluginId,
3932
+ pluginImportPath: pluginManager.getPluginImportPath(attachment.pluginId) ?? "",
3933
+ originalFilePath: sourceFilePath,
3934
+ originalExportName: typeSourceInfo[rawType.name]?.exportName || rawType.name,
3935
+ generatedTypeKind: kind,
3936
+ pluginConfig: plugin?.pluginConfig,
3937
+ namespace
3938
+ };
3939
+ logger.log(` Generated: ${styles.success(generatedType.name)} by plugin ${styles.info(attachment.pluginId)}`);
3963
3940
  }
3964
3941
  }
3965
- const newParents = [...parents, node];
3966
- for (const key of Object.keys(node)) {
3967
- const child = node[key];
3968
- if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
3969
- else if (child && typeof child === "object") walk(child, newParents);
3942
+ };
3943
+ const loadTypeFile = async (typeFile, tsconfig) => {
3944
+ rawTypes[typeFile] = {};
3945
+ const loadedTypes = {};
3946
+ try {
3947
+ const module = await import(pathToFileURL(typeFile).href);
3948
+ for (const exportName of Object.keys(module)) {
3949
+ const exportedValue = module[exportName];
3950
+ const result = TailorDBTypeSchema.safeParse(exportedValue);
3951
+ if (!result.success) {
3952
+ if (isSdkBranded(exportedValue, "tailordb-type")) throw result.error;
3953
+ continue;
3954
+ }
3955
+ const relativePath = path.relative(process.cwd(), typeFile);
3956
+ logger.log(`Type: ${styles.successBright(`"${result.data.name}"`)} loaded from ${styles.path(relativePath)}`);
3957
+ await precompileTailorDBTypeScripts(result.data, typeFile, tsconfig);
3958
+ rawTypes[typeFile][result.data.name] = result.data;
3959
+ loadedTypes[result.data.name] = result.data;
3960
+ typeSourceInfo[result.data.name] = {
3961
+ filePath: typeFile,
3962
+ exportName
3963
+ };
3964
+ if (exportedValue.plugins && Array.isArray(exportedValue.plugins) && exportedValue.plugins.length > 0) {
3965
+ pluginAttachments.set(exportedValue.name, [...exportedValue.plugins]);
3966
+ logger.log(` Plugin attachments: ${styles.info(exportedValue.plugins.map((p) => p.pluginId).join(", "))}`);
3967
+ await processPluginsForType(exportedValue, exportedValue.plugins, typeFile);
3968
+ }
3969
+ }
3970
+ } catch (error) {
3971
+ const relativePath = path.relative(process.cwd(), typeFile);
3972
+ logger.error(`Failed to load type from ${styles.bold(relativePath)}`);
3973
+ logger.error(String(error));
3974
+ throw error;
3970
3975
  }
3971
- }
3972
- walk(program);
3973
- return workflows;
3974
- }
3975
- /**
3976
- * Build a map from export name to workflow name from detected workflows
3977
- * @param workflows - Detected workflows
3978
- * @returns Map from export name to workflow name
3979
- */
3980
- function buildWorkflowNameMap(workflows) {
3981
- const map = /* @__PURE__ */ new Map();
3982
- for (const workflow of workflows) if (workflow.exportName) map.set(workflow.exportName, workflow.name);
3983
- return map;
3984
- }
3985
- /**
3986
- * Detect default imports in a source file and return a map from local name to import source
3987
- * @param program - Parsed TypeScript program
3988
- * @returns Map from local name to import source
3989
- */
3990
- function detectDefaultImports(program) {
3991
- const imports = /* @__PURE__ */ new Map();
3992
- function walk(node) {
3993
- if (!node || typeof node !== "object") return;
3994
- if (node.type === "ImportDeclaration") {
3995
- const importDecl = node;
3996
- const source = importDecl.source?.value;
3997
- if (typeof source === "string") {
3998
- for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportDefaultSpecifier") {
3999
- const spec = specifier;
4000
- if (spec.local?.name) imports.set(spec.local.name, source);
3976
+ return loadedTypes;
3977
+ };
3978
+ return {
3979
+ namespace,
3980
+ config,
3981
+ get types() {
3982
+ return types;
3983
+ },
3984
+ get typeSourceInfo() {
3985
+ return typeSourceInfo;
3986
+ },
3987
+ get pluginAttachments() {
3988
+ return pluginAttachments;
3989
+ },
3990
+ loadTypes: async () => {
3991
+ if (!loadPromise) loadPromise = (async () => {
3992
+ if (!config.files || config.files.length === 0) return;
3993
+ const typeFiles = loadFilesWithIgnores(config);
3994
+ let tsconfig;
3995
+ try {
3996
+ tsconfig = await resolveTSConfig();
3997
+ } catch {
3998
+ tsconfig = void 0;
3999
+ }
4000
+ logger.newline();
4001
+ logger.log(`Found ${styles.highlight(typeFiles.length.toString())} type files for TailorDB service ${styles.highlight(`"${namespace}"`)}`);
4002
+ if (pluginManager) for (const typeFile of typeFiles) await loadTypeFile(typeFile, tsconfig);
4003
+ else await Promise.all(typeFiles.map((typeFile) => loadTypeFile(typeFile, tsconfig)));
4004
+ doParseTypes();
4005
+ return types;
4006
+ })();
4007
+ return loadPromise;
4008
+ },
4009
+ processNamespacePlugins: async () => {
4010
+ if (!pluginManager) return;
4011
+ const results = await pluginManager.processNamespacePlugins(namespace);
4012
+ const pluginGeneratedKey = "__plugin_generated__";
4013
+ if (!rawTypes[pluginGeneratedKey]) rawTypes[pluginGeneratedKey] = {};
4014
+ let hasGeneratedTypes = false;
4015
+ for (const { pluginId, config, result } of results) {
4016
+ if (!result.success) {
4017
+ logger.error(result.error);
4018
+ throw new Error(result.error);
4019
+ }
4020
+ const output = result.output;
4021
+ for (const [kind, generatedType] of Object.entries(output.types ?? {})) {
4022
+ rawTypes[pluginGeneratedKey][generatedType.name] = generatedType;
4023
+ hasGeneratedTypes = true;
4024
+ typeSourceInfo[generatedType.name] = {
4025
+ exportName: generatedType.name,
4026
+ pluginId,
4027
+ pluginImportPath: pluginManager.getPluginImportPath(pluginId) ?? "",
4028
+ originalFilePath: "",
4029
+ originalExportName: "",
4030
+ generatedTypeKind: kind,
4031
+ pluginConfig: config,
4032
+ namespace
4033
+ };
4034
+ logger.log(` Generated: ${styles.success(generatedType.name)} by namespace plugin ${styles.info(pluginId)}`);
4001
4035
  }
4002
4036
  }
4037
+ if (hasGeneratedTypes) doParseTypes();
4003
4038
  }
4004
- for (const key of Object.keys(node)) {
4005
- const child = node[key];
4006
- if (Array.isArray(child)) child.forEach((c) => walk(c));
4007
- else if (child && typeof child === "object") walk(child);
4008
- }
4009
- }
4010
- walk(program);
4011
- return imports;
4039
+ };
4012
4040
  }
4013
4041
 
4014
4042
  //#endregion
4015
- //#region src/cli/services/workflow/trigger-transformer.ts
4016
- /**
4017
- * Extract authInvoker info from a config object expression
4018
- * Returns the authInvoker value text and whether it's a shorthand property
4019
- * @param configArg - Config argument node
4020
- * @param sourceText - Source code text
4021
- * @returns Extracted authInvoker info, if any
4022
- */
4023
- function extractAuthInvokerInfo(configArg, sourceText) {
4024
- if (!configArg || typeof configArg !== "object") return void 0;
4025
- if (configArg.type !== "ObjectExpression") return void 0;
4026
- const objExpr = configArg;
4027
- for (const prop of objExpr.properties) {
4028
- if (prop.type !== "Property") continue;
4029
- const objProp = prop;
4030
- if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === "authInvoker") {
4031
- if (objProp.shorthand) return {
4032
- isShorthand: true,
4033
- valueText: "authInvoker"
4034
- };
4035
- return {
4036
- isShorthand: false,
4037
- valueText: sourceText.slice(objProp.value.start, objProp.value.end)
4038
- };
4039
- }
4040
- }
4041
- }
4042
- /**
4043
- * Detect .trigger() calls for known workflows and jobs
4044
- * Only detects calls where the identifier is in workflowNames or jobNames
4045
- * @param program - The parsed AST program
4046
- * @param sourceText - The source code text
4047
- * @param workflowNames - Set of known workflow identifier names
4048
- * @param jobNames - Set of known job identifier names
4049
- * @returns Detected trigger call metadata
4050
- */
4051
- function detectExtendedTriggerCalls(program, sourceText, workflowNames, jobNames) {
4052
- const calls = [];
4053
- function walk(node, parent = null) {
4054
- if (!node || typeof node !== "object") return;
4055
- if (node.type === "CallExpression") {
4056
- const callExpr = node;
4057
- const callee = callExpr.callee;
4058
- if (callee.type === "MemberExpression") {
4059
- const memberExpr = callee;
4060
- if (!memberExpr.computed && memberExpr.object.type === "Identifier" && memberExpr.property.name === "trigger") {
4061
- const identifierName = memberExpr.object.name;
4062
- const isWorkflow = workflowNames.has(identifierName);
4063
- const isJob = jobNames.has(identifierName);
4064
- if (!isWorkflow && !isJob) return;
4065
- const argCount = callExpr.arguments.length;
4066
- let argsText = "";
4067
- if (argCount > 0) {
4068
- const firstArg = callExpr.arguments[0];
4069
- if (firstArg && "start" in firstArg && "end" in firstArg) argsText = sourceText.slice(firstArg.start, firstArg.end);
4070
- }
4071
- const hasAwait = parent?.type === "AwaitExpression";
4072
- const awaitExpr = hasAwait ? parent : null;
4073
- if (isWorkflow && argCount >= 2) {
4074
- const secondArg = callExpr.arguments[1];
4075
- const authInvoker = extractAuthInvokerInfo(secondArg, sourceText);
4076
- if (authInvoker) calls.push({
4077
- kind: "workflow",
4078
- identifierName,
4079
- callRange: {
4080
- start: callExpr.start,
4081
- end: callExpr.end
4082
- },
4083
- argsText,
4084
- authInvoker,
4085
- hasAwait: false
4086
- });
4087
- } else if (isJob) calls.push({
4088
- kind: "job",
4089
- identifierName,
4090
- callRange: {
4091
- start: callExpr.start,
4092
- end: callExpr.end
4093
- },
4094
- argsText,
4095
- hasAwait,
4096
- fullRange: awaitExpr ? {
4097
- start: awaitExpr.start,
4098
- end: awaitExpr.end
4099
- } : void 0
4100
- });
4101
- }
4102
- }
4103
- }
4104
- for (const key of Object.keys(node)) {
4105
- const child = node[key];
4106
- if (Array.isArray(child)) child.forEach((c) => walk(c, node));
4107
- else if (child && typeof child === "object") walk(child, node);
4108
- }
4109
- }
4110
- walk(program);
4111
- return calls;
4112
- }
4113
- /**
4114
- * Transform trigger calls for resolver/executor/workflow functions
4115
- * Handles both job.trigger() and workflow.trigger() calls
4116
- * @param source - The source code to transform
4117
- * @param workflowNameMap - Map from variable name to workflow name
4118
- * @param jobNameMap - Map from variable name to job name
4119
- * @param workflowFileMap - Map from file path (without extension) to workflow name for default exports
4120
- * @param currentFilePath - Path of the current file being transformed (for resolving relative imports)
4121
- * @returns Transformed source code with trigger calls rewritten
4122
- */
4123
- function transformFunctionTriggers(source, workflowNameMap, jobNameMap, workflowFileMap, currentFilePath) {
4124
- const { program } = parseSync("input.ts", source);
4125
- const localWorkflowNameMap = new Map(workflowNameMap);
4126
- if (workflowFileMap && currentFilePath) {
4127
- const defaultImports = detectDefaultImports(program);
4128
- const currentDir = currentFilePath.replace(/[/\\][^/\\]+$/, "");
4129
- for (const [localName, importSource] of defaultImports) {
4130
- if (!importSource.startsWith(".")) continue;
4131
- const resolvedPath = resolvePath(currentDir, importSource);
4132
- const workflowName = workflowFileMap.get(resolvedPath);
4133
- if (workflowName) localWorkflowNameMap.set(localName, workflowName);
4134
- }
4043
+ //#region src/parser/service/resolver/schema.ts
4044
+ const TailorFieldTypeSchema = z.enum([
4045
+ "uuid",
4046
+ "string",
4047
+ "boolean",
4048
+ "integer",
4049
+ "float",
4050
+ "decimal",
4051
+ "enum",
4052
+ "date",
4053
+ "datetime",
4054
+ "time",
4055
+ "nested"
4056
+ ]);
4057
+ const QueryTypeSchema = z.union([z.literal("query"), z.literal("mutation")]).describe("GraphQL operation type");
4058
+ const AllowedValueSchema = z.object({
4059
+ value: z.string().describe("The allowed value"),
4060
+ description: z.string().optional().describe("Description of the allowed value")
4061
+ });
4062
+ const FieldMetadataSchema = z.object({
4063
+ required: z.boolean().optional().describe("Whether the field is required"),
4064
+ array: z.boolean().optional().describe("Whether the field is an array"),
4065
+ description: z.string().optional().describe("Field description"),
4066
+ allowedValues: z.array(AllowedValueSchema).optional().describe("Allowed values for enum fields"),
4067
+ hooks: z.object({
4068
+ create: functionSchema.optional().describe("Hook function called on creation"),
4069
+ update: functionSchema.optional().describe("Hook function called on update")
4070
+ }).optional().describe("Lifecycle hooks"),
4071
+ typeName: z.string().optional().describe("Type name for nested or enum fields")
4072
+ });
4073
+ const TailorFieldSchema = z.object({
4074
+ type: TailorFieldTypeSchema.describe("Field data type"),
4075
+ metadata: FieldMetadataSchema.describe("Field metadata configuration"),
4076
+ get fields() {
4077
+ return z.record(z.string(), TailorFieldSchema);
4135
4078
  }
4136
- const triggerCalls = detectExtendedTriggerCalls(program, source, new Set(localWorkflowNameMap.keys()), new Set(jobNameMap.keys()));
4137
- const replacements = [];
4138
- for (const call of triggerCalls) if (call.kind === "workflow" && call.authInvoker) {
4139
- const workflowName = localWorkflowNameMap.get(call.identifierName);
4140
- if (workflowName) {
4141
- const authInvokerExpr = call.authInvoker.isShorthand ? "authInvoker" : call.authInvoker.valueText;
4142
- const transformedCall = `tailor.workflow.triggerWorkflow("${workflowName}", ${call.argsText || "undefined"}, { authInvoker: ${authInvokerExpr} })`;
4143
- replacements.push({
4144
- start: call.callRange.start,
4145
- end: call.callRange.end,
4146
- text: transformedCall
4147
- });
4148
- }
4149
- } else if (call.kind === "job") {
4150
- const jobName = jobNameMap.get(call.identifierName);
4151
- if (jobName) {
4152
- const transformedCall = `tailor.workflow.triggerJobFunction("${jobName}", ${call.argsText || "undefined"})`;
4153
- const range = call.hasAwait && call.fullRange ? call.fullRange : call.callRange;
4154
- replacements.push({
4155
- start: range.start,
4156
- end: range.end,
4157
- text: transformedCall
4158
- });
4159
- }
4079
+ });
4080
+ const ResolverSchema = z.object({
4081
+ operation: QueryTypeSchema.describe("GraphQL operation type (query or mutation)"),
4082
+ name: z.string().describe("Resolver name"),
4083
+ description: z.string().optional().describe("Resolver description"),
4084
+ input: z.record(z.string(), TailorFieldSchema).optional().describe("Input field definitions"),
4085
+ body: functionSchema.describe("Resolver implementation function"),
4086
+ output: TailorFieldSchema.describe("Output field definition"),
4087
+ publishEvents: z.boolean().optional().describe("Enable publishing events from this resolver")
4088
+ });
4089
+
4090
+ //#endregion
4091
+ //#region src/parser/service/auth/schema.ts
4092
+ const AuthInvokerSchema = z.object({
4093
+ namespace: z.string().describe("Auth namespace"),
4094
+ machineUserName: z.string().describe("Machine user name for authentication")
4095
+ });
4096
+ const secretValueSchema = z.object({
4097
+ vaultName: z.string().describe("Vault name containing the secret"),
4098
+ secretKey: z.string().describe("Key of the secret in the vault")
4099
+ });
4100
+ const OIDCSchema = z.object({
4101
+ name: z.string().describe("Identity provider name"),
4102
+ kind: z.literal("OIDC"),
4103
+ clientID: z.string().describe("OAuth2 client ID"),
4104
+ clientSecret: secretValueSchema.describe("OAuth2 client secret"),
4105
+ providerURL: z.string().describe("OIDC provider URL"),
4106
+ issuerURL: z.string().optional().describe("OIDC issuer URL (defaults to providerURL)"),
4107
+ usernameClaim: z.string().optional().describe("JWT claim to use as username")
4108
+ });
4109
+ const SAMLSchema = z.object({
4110
+ name: z.string().describe("Identity provider name"),
4111
+ kind: z.literal("SAML"),
4112
+ enableSignRequest: z.boolean().default(false).describe("Enable signing of SAML requests"),
4113
+ metadataURL: z.string().optional().describe("URL to fetch SAML metadata (mutually exclusive with rawMetadata)"),
4114
+ rawMetadata: z.string().optional().describe("Raw SAML metadata XML (mutually exclusive with metadataURL)")
4115
+ }).refine((value) => {
4116
+ return value.metadataURL !== void 0 !== (value.rawMetadata !== void 0);
4117
+ }, "Provide either metadataURL or rawMetadata");
4118
+ const IDTokenSchema = z.object({
4119
+ name: z.string().describe("Identity provider name"),
4120
+ kind: z.literal("IDToken"),
4121
+ providerURL: z.string().describe("ID token provider URL"),
4122
+ issuerURL: z.string().optional().describe("ID token issuer URL"),
4123
+ clientID: z.string().describe("Client ID for ID token validation"),
4124
+ usernameClaim: z.string().optional().describe("JWT claim to use as username")
4125
+ });
4126
+ const BuiltinIdPSchema = z.object({
4127
+ name: z.string().describe("Identity provider name"),
4128
+ kind: z.literal("BuiltInIdP"),
4129
+ namespace: z.string().describe("IdP namespace"),
4130
+ clientName: z.string().describe("OAuth2 client name in the IdP")
4131
+ });
4132
+ const IdProviderSchema = z.discriminatedUnion("kind", [
4133
+ OIDCSchema,
4134
+ SAMLSchema,
4135
+ IDTokenSchema,
4136
+ BuiltinIdPSchema
4137
+ ]);
4138
+ const OAuth2ClientGrantTypeSchema = z.union([z.literal("authorization_code"), z.literal("refresh_token")]).describe("OAuth2 grant type");
4139
+ const OAuth2ClientSchema = z.object({
4140
+ description: z.string().optional().describe("Client description"),
4141
+ grantTypes: z.array(OAuth2ClientGrantTypeSchema).default(["authorization_code", "refresh_token"]).describe("Allowed OAuth2 grant types"),
4142
+ redirectURIs: z.array(z.union([
4143
+ z.templateLiteral(["https://", z.string()]),
4144
+ z.templateLiteral(["http://", z.string()]),
4145
+ z.templateLiteral([z.string(), ":url"]),
4146
+ z.templateLiteral([
4147
+ z.string(),
4148
+ ":url/",
4149
+ z.string()
4150
+ ])
4151
+ ])).describe("Allowed redirect URIs"),
4152
+ clientType: z.union([
4153
+ z.literal("confidential"),
4154
+ z.literal("public"),
4155
+ z.literal("browser")
4156
+ ]).optional().describe("OAuth2 client type"),
4157
+ accessTokenLifetimeSeconds: z.number().int().min(60, "Minimum access token lifetime is 60 seconds").max(86400, "Maximum access token lifetime is 1 day (86400 seconds)").optional().describe("Access token lifetime in seconds (60-86400)").transform((val) => val ? {
4158
+ seconds: BigInt(val),
4159
+ nanos: 0
4160
+ } : void 0),
4161
+ refreshTokenLifetimeSeconds: z.number().int().min(60, "Minimum refresh token lifetime is 60 seconds").max(604800, "Maximum refresh token lifetime is 7 days (604800 seconds)").optional().describe("Refresh token lifetime in seconds (60-604800)").transform((val) => val ? {
4162
+ seconds: BigInt(val),
4163
+ nanos: 0
4164
+ } : void 0),
4165
+ requireDpop: z.boolean().optional().describe("Require DPoP (Demonstrating Proof-of-Possession) for token requests")
4166
+ }).refine((data) => !(data.clientType === "browser" && data.requireDpop === true), {
4167
+ message: "requireDpop cannot be set to true for browser clients as they don't support DPoP",
4168
+ path: ["requireDpop"]
4169
+ });
4170
+ const SCIMAuthorizationSchema = z.object({
4171
+ type: z.union([z.literal("oauth2"), z.literal("bearer")]).describe("SCIM authorization type"),
4172
+ bearerSecret: secretValueSchema.optional().describe("Bearer token secret (required for bearer type)")
4173
+ });
4174
+ const SCIMAttributeTypeSchema = z.union([
4175
+ z.literal("string"),
4176
+ z.literal("number"),
4177
+ z.literal("boolean"),
4178
+ z.literal("datetime"),
4179
+ z.literal("complex")
4180
+ ]).describe("SCIM attribute data type");
4181
+ const SCIMAttributeSchema = z.object({
4182
+ type: SCIMAttributeTypeSchema.describe("Attribute data type"),
4183
+ name: z.string().describe("Attribute name"),
4184
+ description: z.string().optional().describe("Attribute description"),
4185
+ mutability: z.union([
4186
+ z.literal("readOnly"),
4187
+ z.literal("readWrite"),
4188
+ z.literal("writeOnly")
4189
+ ]).optional().describe("Attribute mutability"),
4190
+ required: z.boolean().optional().describe("Whether the attribute is required"),
4191
+ multiValued: z.boolean().optional().describe("Whether the attribute can have multiple values"),
4192
+ uniqueness: z.union([
4193
+ z.literal("none"),
4194
+ z.literal("server"),
4195
+ z.literal("global")
4196
+ ]).optional().describe("Uniqueness constraint"),
4197
+ canonicalValues: z.array(z.string()).nullable().optional().describe("List of canonical values"),
4198
+ get subAttributes() {
4199
+ return z.array(SCIMAttributeSchema).nullable().optional();
4160
4200
  }
4161
- return applyReplacements(source, replacements);
4162
- }
4201
+ });
4202
+ const SCIMSchemaSchema = z.object({
4203
+ name: z.string().describe("SCIM schema name"),
4204
+ attributes: z.array(SCIMAttributeSchema).describe("Schema attributes")
4205
+ });
4206
+ const SCIMAttributeMappingSchema = z.object({
4207
+ tailorDBField: z.string().describe("TailorDB field name to map to"),
4208
+ scimPath: z.string().describe("SCIM attribute path")
4209
+ });
4210
+ const SCIMResourceSchema = z.object({
4211
+ name: z.string().describe("SCIM resource name"),
4212
+ tailorDBNamespace: z.string().describe("TailorDB namespace for the resource"),
4213
+ tailorDBType: z.string().describe("TailorDB type name for the resource"),
4214
+ coreSchema: SCIMSchemaSchema.describe("Core SCIM schema definition"),
4215
+ attributeMapping: z.array(SCIMAttributeMappingSchema).describe("Attribute mapping configuration")
4216
+ });
4217
+ const SCIMSchema = z.object({
4218
+ machineUserName: z.string().describe("Machine user name for SCIM operations"),
4219
+ authorization: SCIMAuthorizationSchema.describe("SCIM authorization configuration"),
4220
+ resources: z.array(SCIMResourceSchema).describe("SCIM resource definitions")
4221
+ });
4222
+ const TenantProviderSchema = z.object({
4223
+ namespace: z.string().describe("TailorDB namespace for the tenant type"),
4224
+ type: z.string().describe("TailorDB type name for tenants"),
4225
+ signatureField: z.string().describe("Field used as the tenant signature")
4226
+ });
4227
+ const UserProfileSchema = z.object({
4228
+ type: z.object({
4229
+ name: z.string(),
4230
+ fields: z.any(),
4231
+ metadata: z.any(),
4232
+ hooks: z.any(),
4233
+ validate: z.any(),
4234
+ features: z.any(),
4235
+ indexes: z.any(),
4236
+ files: z.any(),
4237
+ permission: z.any(),
4238
+ gqlPermission: z.any(),
4239
+ _output: z.any()
4240
+ }),
4241
+ usernameField: z.string(),
4242
+ attributes: z.record(z.string(), z.literal(true)).optional(),
4243
+ attributeList: z.array(z.string()).optional()
4244
+ });
4245
+ const ValueOperandSchema = z.union([
4246
+ z.string(),
4247
+ z.boolean(),
4248
+ z.array(z.string()),
4249
+ z.array(z.boolean())
4250
+ ]);
4251
+ const MachineUserSchema = z.object({
4252
+ attributes: z.record(z.string(), ValueOperandSchema).optional(),
4253
+ attributeList: z.array(z.uuid()).optional()
4254
+ });
4255
+ const BeforeLoginHookSchema = z.object({
4256
+ handler: z.function(),
4257
+ invoker: z.string()
4258
+ });
4259
+ const AuthConfigBaseSchema = z.object({
4260
+ name: z.string().describe("Auth service name"),
4261
+ hooks: z.object({ beforeLogin: BeforeLoginHookSchema.optional().describe("Before login auth hook") }).optional().describe("Auth hooks"),
4262
+ machineUsers: z.record(z.string(), MachineUserSchema).optional().describe("Machine user definitions"),
4263
+ oauth2Clients: z.record(z.string(), OAuth2ClientSchema).optional().describe("OAuth2 client definitions"),
4264
+ idProvider: IdProviderSchema.optional().describe("Identity provider configuration"),
4265
+ scim: SCIMSchema.optional().describe("SCIM provisioning configuration"),
4266
+ tenantProvider: TenantProviderSchema.optional().describe("Multi-tenant provider configuration"),
4267
+ publishSessionEvents: z.boolean().optional().describe("Enable publishing session events")
4268
+ });
4269
+ const AuthConfigSchema = z.union([AuthConfigBaseSchema.extend({
4270
+ userProfile: z.undefined().optional(),
4271
+ machineUserAttributes: z.undefined().optional()
4272
+ }), z.xor([AuthConfigBaseSchema.extend({
4273
+ userProfile: UserProfileSchema,
4274
+ machineUserAttributes: z.undefined().optional()
4275
+ }), AuthConfigBaseSchema.extend({
4276
+ userProfile: z.undefined().optional(),
4277
+ machineUserAttributes: z.record(z.string(), TailorFieldSchema)
4278
+ })])]).brand("AuthConfig");
4163
4279
 
4164
4280
  //#endregion
4165
- //#region src/cli/shared/trigger-context.ts
4166
- /**
4167
- * Normalize a file path by removing extension and resolving to absolute path
4168
- * @param filePath - File path to normalize
4169
- * @returns Normalized absolute path without extension
4170
- */
4171
- function normalizeFilePath(filePath) {
4172
- const absolutePath = path.resolve(filePath);
4173
- const ext = path.extname(absolutePath);
4174
- return absolutePath.slice(0, -ext.length);
4175
- }
4281
+ //#region src/cli/services/auth/service.ts
4176
4282
  /**
4177
- * Build trigger context from workflow configuration
4178
- * Scans workflow files to collect workflow and job mappings
4179
- * @param workflowConfig - Workflow file loading configuration
4180
- * @returns Trigger context built from workflow sources
4283
+ * Creates a new AuthService instance.
4284
+ * @param config - The auth configuration
4285
+ * @param tailorDBServices - The TailorDB services
4286
+ * @param externalTailorDBNamespaces - External TailorDB namespaces
4287
+ * @returns A new AuthService instance
4181
4288
  */
4182
- async function buildTriggerContext(workflowConfig) {
4183
- const workflowNameMap = /* @__PURE__ */ new Map();
4184
- const jobNameMap = /* @__PURE__ */ new Map();
4185
- const workflowFileMap = /* @__PURE__ */ new Map();
4186
- if (!workflowConfig) return {
4187
- workflowNameMap,
4188
- jobNameMap,
4189
- workflowFileMap
4190
- };
4191
- const workflowFiles = loadFilesWithIgnores(workflowConfig);
4192
- for (const file of workflowFiles) try {
4193
- const source = await fs$1.promises.readFile(file, "utf-8");
4194
- const { program } = parseSync("input.ts", source);
4195
- const workflows = findAllWorkflows(program, source);
4196
- const workflowMap = buildWorkflowNameMap(workflows);
4197
- for (const [exportName, workflowName] of workflowMap) workflowNameMap.set(exportName, workflowName);
4198
- for (const workflow of workflows) if (workflow.isDefaultExport) {
4199
- const normalizedPath = normalizeFilePath(file);
4200
- workflowFileMap.set(normalizedPath, workflow.name);
4201
- }
4202
- const jobMap = buildJobNameMap(findAllJobs(program, source));
4203
- for (const [exportName, jobName] of jobMap) jobNameMap.set(exportName, jobName);
4204
- } catch (error) {
4205
- const errorMessage = error instanceof Error ? error.message : String(error);
4206
- logger.warn(`Failed to process workflow file ${file}: ${errorMessage}`, { mode: "stream" });
4207
- continue;
4208
- }
4209
- return {
4210
- workflowNameMap,
4211
- jobNameMap,
4212
- workflowFileMap
4289
+ function createAuthService(config, tailorDBServices, externalTailorDBNamespaces) {
4290
+ const parsedConfig = {
4291
+ ...config,
4292
+ idProvider: IdProviderSchema.optional().parse(config.idProvider)
4213
4293
  };
4214
- }
4215
- function sortedMapToJson(m) {
4216
- return JSON.stringify([...m.entries()].sort(([a], [b]) => a.localeCompare(b)));
4217
- }
4218
- /**
4219
- * Serialize trigger context to a deterministic string for cache hashing.
4220
- * Returns an empty string if no context is provided.
4221
- * @param ctx - Trigger context to serialize
4222
- * @returns Deterministic string representation
4223
- */
4224
- function serializeTriggerContext(ctx) {
4225
- if (!ctx) return "";
4226
- return sortedMapToJson(ctx.workflowNameMap) + sortedMapToJson(ctx.jobNameMap) + sortedMapToJson(ctx.workflowFileMap);
4227
- }
4228
- /**
4229
- * Create a rolldown plugin for transforming trigger calls
4230
- * Returns undefined if no trigger context is provided
4231
- * @param triggerContext - Trigger context to use for transformations
4232
- * @returns Rolldown plugin or undefined when no context
4233
- */
4234
- function createTriggerTransformPlugin(triggerContext) {
4235
- if (!triggerContext) return;
4294
+ let userProfile;
4236
4295
  return {
4237
- name: "trigger-transform",
4238
- transform: {
4239
- filter: { id: { include: [/\.ts$/, /\.js$/] } },
4240
- handler(code, id) {
4241
- if (!code.includes(".trigger(")) return null;
4242
- return { code: transformFunctionTriggers(code, triggerContext.workflowNameMap, triggerContext.jobNameMap, triggerContext.workflowFileMap, id) };
4296
+ config,
4297
+ tailorDBServices,
4298
+ externalTailorDBNamespaces,
4299
+ parsedConfig,
4300
+ get userProfile() {
4301
+ return userProfile;
4302
+ },
4303
+ resolveNamespaces: async () => {
4304
+ if (!config.userProfile) return;
4305
+ if (config.userProfile.namespace) {
4306
+ userProfile = {
4307
+ ...config.userProfile,
4308
+ namespace: config.userProfile.namespace
4309
+ };
4310
+ return;
4311
+ }
4312
+ const totalNamespaceCount = tailorDBServices.length + externalTailorDBNamespaces.length;
4313
+ let userProfileNamespace;
4314
+ if (totalNamespaceCount === 1) userProfileNamespace = tailorDBServices[0]?.namespace ?? externalTailorDBNamespaces[0];
4315
+ else {
4316
+ await Promise.all(tailorDBServices.map((tailordb) => tailordb.loadTypes()));
4317
+ const userProfileTypeName = typeof config.userProfile.type === "object" && "name" in config.userProfile.type ? config.userProfile.type.name : void 0;
4318
+ if (userProfileTypeName) for (const service of tailorDBServices) {
4319
+ const types = service.types;
4320
+ if (Object.prototype.hasOwnProperty.call(types, userProfileTypeName)) {
4321
+ userProfileNamespace = service.namespace;
4322
+ break;
4323
+ }
4324
+ }
4325
+ if (!userProfileNamespace) throw new Error(`userProfile type "${config.userProfile.type.name}" not found in any TailorDB namespace`);
4243
4326
  }
4327
+ userProfile = {
4328
+ ...config.userProfile,
4329
+ namespace: userProfileNamespace
4330
+ };
4244
4331
  }
4245
4332
  };
4246
4333
  }
@@ -5699,6 +5786,17 @@ async function loadApplication(params) {
5699
5786
  const mainJobNames = workflowService.workflowSources.map((ws) => ws.workflow.mainJob.name);
5700
5787
  workflowBuildResult = await bundleWorkflowJobs(workflowService.jobs, mainJobNames, config.env ?? {}, triggerContext, bundleCache, inlineSourcemap);
5701
5788
  }
5789
+ if (authResult.authService?.config.hooks?.beforeLogin) {
5790
+ const authName = authResult.authService.config.name;
5791
+ await bundleAuthHooks({
5792
+ configPath: config.path,
5793
+ authName,
5794
+ handlerAccessPath: `auth.hooks.beforeLogin.handler`,
5795
+ triggerContext,
5796
+ cache: bundleCache,
5797
+ inlineSourcemap
5798
+ });
5799
+ }
5702
5800
  for (const pipeline of resolverResult.resolverServices) await pipeline.loadResolvers();
5703
5801
  if (executorService) {
5704
5802
  await executorService.loadExecutors();
@@ -5724,5 +5822,5 @@ async function loadApplication(params) {
5724
5822
  }
5725
5823
 
5726
5824
  //#endregion
5727
- export { AuthSCIMAttribute_Uniqueness as $, userAgent as A, PipelineResolver_OperationType as B, fetchAll as C, initOperatorClient as D, initOAuth2Client as E, TailorDBGQLPermission_Operator as F, ExecutorTargetType as G, FunctionExecution_Status as H, TailorDBGQLPermission_Permit as I, AuthInvokerSchema$1 as J, ExecutorTriggerType as K, TailorDBType_Permission_Operator as L, WorkflowExecution_Status as M, WorkflowJobExecution_Status as N, platformBaseUrl as O, TailorDBGQLPermission_Action as P, AuthSCIMAttribute_Type as Q, TailorDBType_Permission_Permit as R, writePlatformConfig as S, fetchUserInfo as T, FunctionExecution_Type as U, IdPLang as V, ExecutorJobStatus as W, AuthOAuth2Client_GrantType as X, AuthOAuth2Client_ClientType as Y, AuthSCIMAttribute_Mutability as Z, hashFile as _, loadConfig as a, ConditionSchema as at, loadWorkspaceId as b, ExecutorSchema as c, PageDirection as ct, TailorDBTypeSchema as d, CIPromptError as dt, AuthSCIMConfig_AuthorizationType as et, stringifyFunction as f, logger as ft, getDistDir as g, createBundleCache as h, resolveInlineSourcemap as i, GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus as it, WorkspacePlatformUserRole as j, resolveStaticWebsiteUrls as k, OAuth2ClientSchema as l, ApplicationSchemaUpdateAttemptStatus as lt, loadFilesWithIgnores as m, symbols as mt, generatePluginFilesIfNeeded as n, TenantProviderConfig_TenantProviderType as nt, WorkflowJobSchema as o, Condition_Operator as ot, tailorUserMap as p, styles as pt, AuthIDPConfig_AuthType as q, loadApplication as r, UserProfileProviderConfig_UserProfileProviderType as rt, createExecutorService as s, FilterSchema as st, defineApplication as t, PATScope as tt, ResolverSchema as u, Subgraph_ServiceType as ut, fetchLatestToken as v, fetchMachineUserToken as w, readPlatformConfig as x, loadAccessToken as y, TailorDBType_PermitAction as z };
5728
- //# sourceMappingURL=application-91Th6tm6.mjs.map
5825
+ export { AuthSCIMAttribute_Type as $, userAgent as A, PipelineResolver_OperationType as B, fetchAll as C, initOperatorClient as D, initOAuth2Client as E, TailorDBGQLPermission_Operator as F, ExecutorTargetType as G, FunctionExecution_Status as H, TailorDBGQLPermission_Permit as I, AuthIDPConfig_AuthType as J, ExecutorTriggerType as K, TailorDBType_Permission_Operator as L, WorkflowExecution_Status as M, WorkflowJobExecution_Status as N, platformBaseUrl as O, TailorDBGQLPermission_Action as P, AuthSCIMAttribute_Mutability as Q, TailorDBType_Permission_Permit as R, writePlatformConfig as S, fetchUserInfo as T, FunctionExecution_Type as U, IdPLang as V, ExecutorJobStatus as W, AuthOAuth2Client_ClientType as X, AuthInvokerSchema$1 as Y, AuthOAuth2Client_GrantType as Z, hashFile as _, loadConfig as a, GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus as at, loadWorkspaceId as b, ExecutorSchema as c, FilterSchema as ct, TailorDBTypeSchema as d, Subgraph_ServiceType as dt, AuthSCIMAttribute_Uniqueness as et, stringifyFunction as f, CIPromptError as ft, getDistDir as g, createBundleCache as h, symbols as ht, resolveInlineSourcemap as i, UserProfileProviderConfig_UserProfileProviderType as it, WorkspacePlatformUserRole as j, resolveStaticWebsiteUrls as k, OAuth2ClientSchema as l, PageDirection as lt, loadFilesWithIgnores as m, styles as mt, generatePluginFilesIfNeeded as n, PATScope as nt, WorkflowJobSchema as o, ConditionSchema as ot, tailorUserMap as p, logger as pt, AuthHookPoint as q, loadApplication as r, TenantProviderConfig_TenantProviderType as rt, createExecutorService as s, Condition_Operator as st, defineApplication as t, AuthSCIMConfig_AuthorizationType as tt, ResolverSchema as u, ApplicationSchemaUpdateAttemptStatus as ut, fetchLatestToken as v, fetchMachineUserToken as w, readPlatformConfig as x, loadAccessToken as y, TailorDBType_PermitAction as z };
5826
+ //# sourceMappingURL=application-D9xahQRQ.mjs.map