@pipeline-builder/api-core 4.1.13 → 4.1.14

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 (187) hide show
  1. package/README.md +3 -2
  2. package/lib/constants/index.d.ts +0 -1
  3. package/lib/constants/index.js +1 -2
  4. package/lib/errors/app-errors.d.ts +8 -3
  5. package/lib/errors/app-errors.js +10 -5
  6. package/lib/helpers/access-helpers.d.ts +4 -6
  7. package/lib/helpers/access-helpers.js +6 -8
  8. package/lib/helpers/index.d.ts +3 -3
  9. package/lib/helpers/index.js +4 -4
  10. package/lib/helpers/org-hierarchy-http.d.ts +11 -10
  11. package/lib/helpers/org-hierarchy-http.js +24 -35
  12. package/lib/helpers/org-hierarchy.d.ts +37 -3
  13. package/lib/helpers/org-hierarchy.js +45 -4
  14. package/lib/helpers/restore-helpers.d.ts +44 -24
  15. package/lib/helpers/restore-helpers.js +41 -52
  16. package/lib/helpers/sse-helpers.d.ts +29 -7
  17. package/lib/helpers/sse-helpers.js +36 -9
  18. package/lib/index.d.ts +16 -14
  19. package/lib/index.js +17 -15
  20. package/lib/middleware/assurance.d.ts +116 -0
  21. package/lib/middleware/assurance.js +176 -0
  22. package/lib/middleware/auth.d.ts +5 -427
  23. package/lib/middleware/auth.js +36 -789
  24. package/lib/middleware/ecosystem-guard.d.ts +47 -0
  25. package/lib/middleware/ecosystem-guard.js +60 -0
  26. package/lib/middleware/index.d.ts +11 -4
  27. package/lib/middleware/index.js +12 -5
  28. package/lib/middleware/jwt-verify.d.ts +52 -0
  29. package/lib/middleware/jwt-verify.js +105 -0
  30. package/lib/middleware/permission-gates.d.ts +133 -0
  31. package/lib/middleware/permission-gates.js +260 -0
  32. package/lib/middleware/revocation.d.ts +96 -0
  33. package/lib/middleware/revocation.js +162 -0
  34. package/lib/middleware/route-table.d.ts +11 -0
  35. package/lib/middleware/route-table.js +4 -1
  36. package/lib/middleware/service-tokens.d.ts +83 -0
  37. package/lib/middleware/service-tokens.js +158 -0
  38. package/lib/middleware/step-up.d.ts +2 -2
  39. package/lib/middleware/step-up.js +8 -7
  40. package/lib/middleware/system-org.d.ts +20 -0
  41. package/lib/middleware/system-org.js +25 -0
  42. package/lib/openapi/routes/plugin-routes.js +133 -10
  43. package/lib/openapi/schema-registry.js +2 -5
  44. package/lib/routes/index.d.ts +1 -1
  45. package/lib/routes/index.js +2 -2
  46. package/lib/services/api-key-exchange.js +7 -5
  47. package/lib/services/audit-spool.d.ts +34 -10
  48. package/lib/services/audit-spool.js +75 -34
  49. package/lib/services/cache-service.d.ts +7 -0
  50. package/lib/services/cache-service.js +1 -1
  51. package/lib/services/circuit-breaker.d.ts +14 -1
  52. package/lib/services/circuit-breaker.js +36 -10
  53. package/lib/services/compliance-client.d.ts +10 -2
  54. package/lib/services/compliance-client.js +17 -10
  55. package/lib/services/compliance-event-subscriber.js +6 -6
  56. package/lib/services/durable-event-bus.js +8 -11
  57. package/lib/services/ecosystem-notify-client.d.ts +32 -0
  58. package/lib/services/ecosystem-notify-client.js +71 -0
  59. package/lib/services/env-redis.d.ts +4 -1
  60. package/lib/services/env-redis.js +32 -3
  61. package/lib/services/http-client.d.ts +19 -0
  62. package/lib/services/http-client.js +98 -19
  63. package/lib/services/index.d.ts +25 -24
  64. package/lib/services/index.js +25 -22
  65. package/lib/services/jwks-cache.js +5 -4
  66. package/lib/services/leader-lock.d.ts +22 -5
  67. package/lib/services/leader-lock.js +61 -6
  68. package/lib/services/quota.d.ts +9 -4
  69. package/lib/services/quota.js +34 -40
  70. package/lib/services/remote-audit-client.d.ts +28 -32
  71. package/lib/services/remote-audit-client.js +166 -49
  72. package/lib/services/retry-forever.js +5 -11
  73. package/lib/services/retry-strategy.d.ts +1 -1
  74. package/lib/services/retry-strategy.js +5 -4
  75. package/lib/services/scheduler.d.ts +8 -3
  76. package/lib/services/scheduler.js +17 -5
  77. package/lib/services/service-boot.d.ts +14 -13
  78. package/lib/services/service-boot.js +18 -15
  79. package/lib/services/service-keys.d.ts +1 -1
  80. package/lib/services/service-keys.js +12 -18
  81. package/lib/services/sse-ticket-store.d.ts +9 -1
  82. package/lib/services/sse-ticket-store.js +24 -9
  83. package/lib/services/system-notification.d.ts +27 -0
  84. package/lib/services/system-notification.js +50 -0
  85. package/lib/services/token-revocation.d.ts +50 -1
  86. package/lib/services/token-revocation.js +103 -3
  87. package/lib/types/audit-events.d.ts +6 -6
  88. package/lib/types/audit-events.js +1 -1
  89. package/lib/types/common.d.ts +32 -13
  90. package/lib/types/common.js +2 -1
  91. package/lib/types/ecosystem-notifications.d.ts +142 -0
  92. package/lib/types/ecosystem-notifications.js +210 -0
  93. package/lib/types/ecosystem.d.ts +77 -0
  94. package/lib/types/ecosystem.js +119 -0
  95. package/lib/types/error-codes.d.ts +81 -0
  96. package/lib/types/error-codes.js +108 -1
  97. package/lib/types/feature-flags.d.ts +21 -1
  98. package/lib/types/feature-flags.js +36 -2
  99. package/lib/types/index.d.ts +14 -9
  100. package/lib/types/index.js +15 -10
  101. package/lib/types/permissions.d.ts +46 -8
  102. package/lib/types/permissions.js +75 -12
  103. package/lib/types/plugin-catalog.d.ts +35 -0
  104. package/lib/types/plugin-catalog.js +39 -0
  105. package/lib/types/plugin-health.d.ts +102 -0
  106. package/lib/types/plugin-health.js +184 -0
  107. package/lib/types/quota-tiers.d.ts +15 -0
  108. package/lib/types/quota-tiers.js +23 -3
  109. package/lib/types/wire-vocabulary.d.ts +102 -0
  110. package/lib/types/wire-vocabulary.js +94 -0
  111. package/lib/utils/alias-resolver.js +2 -2
  112. package/lib/utils/audit.d.ts +5 -2
  113. package/lib/utils/audit.js +6 -3
  114. package/lib/utils/compliance-attributes.js +3 -4
  115. package/lib/utils/concurrency.d.ts +7 -0
  116. package/lib/utils/concurrency.js +13 -1
  117. package/lib/utils/env.d.ts +3 -4
  118. package/lib/utils/env.js +4 -5
  119. package/lib/utils/identity.d.ts +13 -4
  120. package/lib/utils/identity.js +18 -10
  121. package/lib/utils/index.d.ts +13 -10
  122. package/lib/utils/index.js +13 -10
  123. package/lib/utils/jwk.d.ts +4 -0
  124. package/lib/utils/jwk.js +13 -1
  125. package/lib/utils/logger.d.ts +1 -1
  126. package/lib/utils/logger.js +1 -1
  127. package/lib/utils/object.d.ts +11 -0
  128. package/lib/utils/object.js +24 -1
  129. package/lib/utils/params.d.ts +8 -22
  130. package/lib/utils/params.js +15 -43
  131. package/lib/utils/plugin-compliance.d.ts +98 -0
  132. package/lib/utils/plugin-compliance.js +78 -0
  133. package/lib/utils/proof-of-work.d.ts +69 -0
  134. package/lib/utils/proof-of-work.js +139 -0
  135. package/lib/utils/response.d.ts +16 -6
  136. package/lib/utils/response.js +18 -15
  137. package/lib/utils/retention.d.ts +17 -0
  138. package/lib/utils/retention.js +30 -0
  139. package/lib/utils/secret-encryption.d.ts +7 -7
  140. package/lib/utils/secret-encryption.js +9 -10
  141. package/lib/utils/secret-rotation.js +2 -2
  142. package/lib/utils/sensitive-patterns.js +4 -5
  143. package/lib/utils/service-registry.d.ts +15 -0
  144. package/lib/utils/service-registry.js +24 -0
  145. package/lib/utils/ssrf.d.ts +11 -2
  146. package/lib/utils/ssrf.js +112 -33
  147. package/lib/validation/ai-schemas.js +3 -2
  148. package/lib/validation/common-schemas.d.ts +0 -9
  149. package/lib/validation/common-schemas.js +1 -7
  150. package/lib/validation/dockerfile-static.d.ts +26 -0
  151. package/lib/validation/dockerfile-static.js +210 -0
  152. package/lib/validation/index.d.ts +13 -4
  153. package/lib/validation/index.js +14 -5
  154. package/lib/validation/message-schemas.js +6 -4
  155. package/lib/validation/pipeline-schemas.d.ts +8 -2
  156. package/lib/validation/pipeline-schemas.js +30 -4
  157. package/lib/validation/plugin-base-images.d.ts +20 -0
  158. package/lib/validation/plugin-base-images.js +17 -0
  159. package/lib/validation/plugin-catalog-detect.d.ts +86 -0
  160. package/lib/validation/plugin-catalog-detect.js +237 -0
  161. package/lib/validation/plugin-catalog-metadata.d.ts +141 -0
  162. package/lib/validation/plugin-catalog-metadata.js +162 -0
  163. package/lib/validation/plugin-heuristics.d.ts +41 -0
  164. package/lib/validation/plugin-heuristics.js +211 -0
  165. package/lib/validation/plugin-lint.d.ts +18 -0
  166. package/lib/validation/plugin-lint.js +136 -0
  167. package/lib/validation/plugin-name-confusable.d.ts +15 -0
  168. package/lib/validation/plugin-name-confusable.js +81 -0
  169. package/lib/validation/plugin-schemas.d.ts +40 -26
  170. package/lib/validation/plugin-schemas.js +26 -23
  171. package/lib/validation/plugin-spec-schema.d.ts +112 -0
  172. package/lib/validation/plugin-spec-schema.js +163 -0
  173. package/lib/validation/plugin-template-contract.d.ts +64 -0
  174. package/lib/validation/plugin-template-contract.js +113 -0
  175. package/package.json +69 -4
  176. package/lib/testing/mock-api-core.d.ts +0 -150
  177. package/lib/testing/mock-api-core.js +0 -246
  178. package/lib/testing/mock-drizzle.d.ts +0 -6
  179. package/lib/testing/mock-drizzle.js +0 -57
  180. package/lib/testing/route-coverage.d.ts +0 -64
  181. package/lib/testing/route-coverage.js +0 -183
  182. package/lib/testing/service-tokens.d.ts +0 -66
  183. package/lib/testing/service-tokens.js +0 -137
  184. package/lib/testing/tier-mock.d.ts +0 -44
  185. package/lib/testing/tier-mock.js +0 -65
  186. package/lib/testing/user-tokens.d.ts +0 -75
  187. package/lib/testing/user-tokens.js +0 -115
@@ -0,0 +1,210 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /** The field each preference key is stored under in the user's per-org
4
+ * `notifications.ecosystem` preferences (platform `UserPreferences`). */
5
+ export const ECOSYSTEM_EMAIL_PREFERENCE_FIELDS = {
6
+ 'ecosystem.reviews.email': 'reviewsEmail',
7
+ 'ecosystem.upgrades.email': 'upgradesEmail',
8
+ 'ecosystem.installs.email': 'installsEmail',
9
+ 'ecosystem.moderationDigest.email': 'moderationDigestEmail',
10
+ };
11
+ /** Every stored ecosystem email-preference field. */
12
+ export const ECOSYSTEM_EMAIL_PREFERENCE_FIELD_NAMES = Object.values(ECOSYSTEM_EMAIL_PREFERENCE_FIELDS);
13
+ /** The notification event table, as data. */
14
+ export const ECOSYSTEM_NOTIFICATION_EVENTS = {
15
+ N1: { description: 'Anonymous submission received (magic link)', channels: ['email'], preference: null, allowsAddress: true },
16
+ N2: { description: 'Submission verified, entered the moderation queue', channels: ['in_app', 'email'], preference: 'ecosystem.moderationDigest.email', digest: 'daily' },
17
+ N3: { description: 'Submission failed automated gates', channels: ['email'], preference: null, allowsAddress: true },
18
+ N4: { description: 'Submission approved or rejected', channels: ['email'], preference: null, allowsAddress: true },
19
+ N5: { description: 'Submission claimed by an account', channels: ['in_app', 'email'], preference: null },
20
+ N6: { description: 'Verified-publisher application submitted', channels: ['in_app', 'email'], preference: 'ecosystem.moderationDigest.email', digest: 'daily' },
21
+ N7: { description: 'Verified application approved or rejected', channels: ['in_app', 'email'], preference: null },
22
+ N8: { description: 'Moderation action on a listing (suspend, yank, takedown)', channels: ['in_app', 'email'], preference: null },
23
+ N9: { description: 'Ownership transfer requested', channels: ['in_app', 'email'], preference: null },
24
+ N10: { description: 'Ownership transfer accepted, declined, approved or rejected', channels: ['in_app', 'email'], preference: null },
25
+ N11: { description: 'Install requested (policy requires approval)', channels: ['in_app', 'email'], preference: 'ecosystem.installs.email' },
26
+ N12: { description: 'Install approved or denied', channels: ['in_app', 'email'], preference: 'ecosystem.installs.email' },
27
+ N13: { description: 'New version available within an install\'s policy', channels: ['in_app', 'email'], preference: 'ecosystem.upgrades.email', digest: 'weekly' },
28
+ N14: { description: 'Listing deprecated or unmaintained', channels: ['in_app', 'email'], preference: 'ecosystem.upgrades.email' },
29
+ N15: { description: 'New or edited review on a listing', channels: ['in_app', 'email'], preference: 'ecosystem.reviews.email', digest: 'hourly' },
30
+ N16: { description: 'Publisher replied to your review', channels: ['in_app', 'email'], preference: 'ecosystem.reviews.email' },
31
+ N17: { description: 'Review held (reports, burst, filter)', channels: ['in_app', 'email'], preference: 'ecosystem.moderationDigest.email', digest: 'daily' },
32
+ N18: { description: 'Your review was removed', channels: ['in_app', 'email'], preference: null },
33
+ N19: { description: 'Review flagged as a security issue', channels: ['in_app', 'email'], preference: null },
34
+ N20: { description: 'Advisory draft auto-created (CVE rescan)', channels: ['in_app', 'email'], preference: null },
35
+ N21: { description: 'Advisory published or withdrawn', channels: ['in_app', 'email'], preference: null },
36
+ N22: { description: 'Moderation SLA breach', channels: ['email'], preference: null },
37
+ N23: { description: 'Added to or removed from the Ecosystem Manager role', channels: ['in_app', 'email'], preference: null },
38
+ N24: { description: 'Publish request submitted', channels: ['in_app', 'email'], preference: 'ecosystem.moderationDigest.email', digest: 'daily' },
39
+ N25: { description: 'Publish request approved or rejected', channels: ['in_app', 'email'], preference: null },
40
+ N26: { description: 'Listing or version paused by its publisher', channels: ['in_app'], preference: 'ecosystem.upgrades.email' },
41
+ N27: { description: 'Installed listing auto-updated within its range', channels: ['in_app', 'email'], preference: 'ecosystem.upgrades.email', digest: 'weekly' },
42
+ N28: { description: 'A request needs a second approval', channels: ['in_app', 'email'], preference: null },
43
+ N29: { description: 'Plan change affects publishing', channels: ['in_app', 'email'], preference: null },
44
+ };
45
+ /** Whether `value` is a notification event number. */
46
+ export function isEcosystemNotificationEvent(value) {
47
+ return typeof value === 'string' && Object.prototype.hasOwnProperty.call(ECOSYSTEM_NOTIFICATION_EVENTS, value);
48
+ }
49
+ /** Hard caps, matching the message service's own limits. */
50
+ export const ECOSYSTEM_NOTIFY_SUBJECT_MAX = 500;
51
+ export const ECOSYSTEM_NOTIFY_TEXT_MAX = 10000;
52
+ const MAX_RECIPIENT_RULES = 50;
53
+ const ORG_PERMISSIONS = ['publishers:manage', 'plugin_installs:manage'];
54
+ const MODERATOR_PERMISSIONS = ['plugins:moderate', 'publishers:verify'];
55
+ const EMAIL_SHAPE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
56
+ function nonEmptyString(v, max = 255) {
57
+ return typeof v === 'string' && v.trim().length > 0 && v.length <= max;
58
+ }
59
+ function parseRecipient(raw, spec) {
60
+ if (!raw || typeof raw !== 'object')
61
+ return 'each recipient must be an object';
62
+ const r = raw;
63
+ switch (r.kind) {
64
+ case 'user':
65
+ if (!nonEmptyString(r.userId))
66
+ return 'user recipient needs userId';
67
+ if (r.orgId !== undefined && !nonEmptyString(r.orgId))
68
+ return 'user recipient orgId must be a string';
69
+ return { kind: 'user', userId: r.userId, ...(r.orgId ? { orgId: r.orgId } : {}) };
70
+ case 'org_permission':
71
+ if (!nonEmptyString(r.orgId))
72
+ return 'org_permission recipient needs orgId';
73
+ if (typeof r.permission !== 'string' || !ORG_PERMISSIONS.includes(r.permission))
74
+ return 'org_permission recipient names an unsupported permission';
75
+ return {
76
+ kind: 'org_permission',
77
+ orgId: r.orgId,
78
+ permission: r.permission,
79
+ ...(r.inheritFromRoot === true ? { inheritFromRoot: true } : {}),
80
+ };
81
+ case 'moderators': {
82
+ if (typeof r.permission !== 'string' || !MODERATOR_PERMISSIONS.includes(r.permission))
83
+ return 'moderators recipient names an unsupported permission';
84
+ if (r.excludeMembersOfOrgId !== undefined && !nonEmptyString(r.excludeMembersOfOrgId))
85
+ return 'excludeMembersOfOrgId must be a string';
86
+ const exclude = r.excludeUserIds;
87
+ if (exclude !== undefined && (!Array.isArray(exclude) || !exclude.every((u) => nonEmptyString(u))))
88
+ return 'excludeUserIds must be an array of ids';
89
+ return {
90
+ kind: 'moderators',
91
+ permission: r.permission,
92
+ ...(r.excludeMembersOfOrgId ? { excludeMembersOfOrgId: r.excludeMembersOfOrgId } : {}),
93
+ ...(exclude ? { excludeUserIds: exclude } : {}),
94
+ };
95
+ }
96
+ case 'superadmins':
97
+ return { kind: 'superadmins' };
98
+ case 'address':
99
+ if (!spec.allowsAddress)
100
+ return 'address recipients are only allowed for anonymous-submission notices';
101
+ if (!nonEmptyString(r.email, 320) || !EMAIL_SHAPE.test(r.email))
102
+ return 'address recipient needs a valid email';
103
+ return { kind: 'address', email: r.email.trim().toLowerCase() };
104
+ default:
105
+ return 'unknown recipient kind';
106
+ }
107
+ }
108
+ /**
109
+ * Validate an {@link EcosystemNotifyRequest}. Returns the normalized request,
110
+ * or an error string (the relay's 400). Pure, so both the sender (fail at
111
+ * enqueue, not at 09:00 tomorrow) and the relay use the same rules.
112
+ */
113
+ export function parseEcosystemNotifyRequest(body) {
114
+ if (!body || typeof body !== 'object')
115
+ return 'body must be an object';
116
+ const b = body;
117
+ if (!isEcosystemNotificationEvent(b.event))
118
+ return 'event must be one of N1..N29';
119
+ const spec = ECOSYSTEM_NOTIFICATION_EVENTS[b.event];
120
+ if (!nonEmptyString(b.subject, ECOSYSTEM_NOTIFY_SUBJECT_MAX))
121
+ return `subject is required (max ${ECOSYSTEM_NOTIFY_SUBJECT_MAX})`;
122
+ if (!nonEmptyString(b.text, ECOSYSTEM_NOTIFY_TEXT_MAX))
123
+ return `text is required (max ${ECOSYSTEM_NOTIFY_TEXT_MAX})`;
124
+ if (!Array.isArray(b.recipients) || b.recipients.length === 0)
125
+ return 'recipients must be a non-empty array';
126
+ if (b.recipients.length > MAX_RECIPIENT_RULES)
127
+ return `at most ${MAX_RECIPIENT_RULES} recipient rules`;
128
+ const recipients = [];
129
+ for (const raw of b.recipients) {
130
+ const parsed = parseRecipient(raw, spec);
131
+ if (typeof parsed === 'string')
132
+ return parsed;
133
+ recipients.push(parsed);
134
+ }
135
+ let channels;
136
+ if (b.channels !== undefined) {
137
+ if (!Array.isArray(b.channels) || b.channels.length === 0)
138
+ return 'channels must be a non-empty array';
139
+ const bad = b.channels.filter((c) => !spec.channels.includes(c));
140
+ if (bad.length > 0)
141
+ return `event ${b.event} is not delivered on: ${bad.join(', ')}`;
142
+ channels = [...new Set(b.channels)];
143
+ }
144
+ if (b.mandatory !== undefined && typeof b.mandatory !== 'boolean')
145
+ return 'mandatory must be a boolean';
146
+ return {
147
+ event: b.event,
148
+ recipients,
149
+ subject: b.subject.trim(),
150
+ text: b.text.trim(),
151
+ ...(channels ? { channels } : {}),
152
+ ...(b.mandatory === true ? { mandatory: true } : {}),
153
+ };
154
+ }
155
+ /** The UTC hour digests flush at ("daily digest email (09:00 UTC)"). */
156
+ export const ECOSYSTEM_DIGEST_HOUR_UTC = 9;
157
+ /**
158
+ * The next flush time for a digest cadence, strictly after `now`:
159
+ * `hourly` → the next top of the hour; `daily` → the next 09:00 UTC;
160
+ * `weekly` → the next Monday 09:00 UTC.
161
+ */
162
+ export function nextEcosystemDigestTime(cadence, now = new Date()) {
163
+ const t = new Date(now.getTime());
164
+ if (cadence === 'hourly') {
165
+ t.setUTCMinutes(0, 0, 0);
166
+ t.setUTCHours(t.getUTCHours() + 1);
167
+ return t;
168
+ }
169
+ t.setUTCHours(ECOSYSTEM_DIGEST_HOUR_UTC, 0, 0, 0);
170
+ if (t.getTime() <= now.getTime())
171
+ t.setUTCDate(t.getUTCDate() + 1);
172
+ if (cadence === 'weekly') {
173
+ // getUTCDay: 0 = Sunday … 1 = Monday.
174
+ while (t.getUTCDay() !== 1)
175
+ t.setUTCDate(t.getUTCDate() + 1);
176
+ }
177
+ return t;
178
+ }
179
+ /**
180
+ * N23 — someone was added to or removed from the system org's Ecosystem
181
+ * Manager role. Sent to every superadmin and to the affected user;
182
+ * transactional (no opt-out).
183
+ */
184
+ export function renderEcosystemManagerChange(input) {
185
+ const verb = input.added ? 'added to' : 'removed from';
186
+ const by = input.actor ? ` by ${input.actor}` : '';
187
+ return {
188
+ subject: `${input.user} was ${verb} the Ecosystem Manager role`,
189
+ text: input.added
190
+ ? `${input.user} was ${verb} the Ecosystem Manager role${by}. Ecosystem Managers decide publish requests, `
191
+ + 'moderate submissions and reviews, verify publishers and publish advisories for the whole plugin ecosystem. '
192
+ + 'The role works only from the system organization and requires a two-factor sign-in.'
193
+ : `${input.user} was ${verb} the Ecosystem Manager role${by} and can no longer manage or approve anything in the plugin ecosystem.`,
194
+ };
195
+ }
196
+ /**
197
+ * Coalesce several queued notices into one digest email: a count-bearing
198
+ * subject and one line per item (each item's subject), oldest first.
199
+ */
200
+ export function renderEcosystemDigest(event, items) {
201
+ if (items.length === 1)
202
+ return items[0];
203
+ const spec = ECOSYSTEM_NOTIFICATION_EVENTS[event];
204
+ const cadence = spec.digest === 'hourly' ? 'Hourly' : spec.digest === 'weekly' ? 'Weekly' : 'Daily';
205
+ return {
206
+ subject: `${cadence} digest: ${items.length} × ${spec.description}`.slice(0, ECOSYSTEM_NOTIFY_SUBJECT_MAX),
207
+ text: items.map((i) => `• ${i.subject}`).join('\n').slice(0, ECOSYSTEM_NOTIFY_TEXT_MAX),
208
+ };
209
+ }
210
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNvc3lzdGVtLW5vdGlmaWNhdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMvZWNvc3lzdGVtLW5vdGlmaWNhdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQStCdEM7MEVBQzBFO0FBQzFFLE1BQU0sQ0FBQyxNQUFNLGlDQUFpQyxHQUE4RTtJQUMxSCx5QkFBeUIsRUFBRSxjQUFjO0lBQ3pDLDBCQUEwQixFQUFFLGVBQWU7SUFDM0MsMEJBQTBCLEVBQUUsZUFBZTtJQUMzQyxrQ0FBa0MsRUFBRSx1QkFBdUI7Q0FDNUQsQ0FBQztBQUtGLHFEQUFxRDtBQUNyRCxNQUFNLENBQUMsTUFBTSxzQ0FBc0MsR0FDakQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO0FBdUJuRCw2Q0FBNkM7QUFDN0MsTUFBTSxDQUFDLE1BQU0sNkJBQTZCLEdBQXVFO0lBQy9HLEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSw0Q0FBNEMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUU7SUFDN0gsRUFBRSxFQUFFLEVBQUUsV0FBVyxFQUFFLG1EQUFtRCxFQUFFLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsRUFBRSxVQUFVLEVBQUUsa0NBQWtDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRTtJQUN4SyxFQUFFLEVBQUUsRUFBRSxXQUFXLEVBQUUsbUNBQW1DLEVBQUUsUUFBUSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFO0lBQ3BILEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSxpQ0FBaUMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLGFB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QTRCLENBQUM7UUFDMUcsSUFBSSxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUseUJBQXlCLENBQUM7S0FDeEYsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBUaGUgcGx1Z2luLWVjb3N5c3RlbSBub3RpZmljYXRpb24gY29udHJhY3QgKGRvY3MvcGx1Z2luLXB1Ymxpc2hpbmcubWQpLFxuICogc2hhcmVkIGJ5IHRoZSBzZW5kZXIgKHRoZSBwbHVnaW4gc2VydmljZSdzIGVucXVldWUgQVBJIGFuZCBkaWdlc3RcbiAqIGRpc3BhdGNoZXIpIGFuZCB0aGUgcmVsYXkgKHBsYXRmb3JtIGBQT1NUIC9pbnRlcm5hbC9ub3RpZnktZW1haWxgKS5cbiAqXG4gKiBSZWNpcGllbnRzIHRyYXZlbCBhcyBSVUxFUywgbmV2ZXIgYXMgbGlzdHM6IHBsYXRmb3JtIHJlc29sdmVzIGVhY2hcbiAqIHtAbGluayBFY29zeXN0ZW1SZWNpcGllbnRTcGVjfSBhZ2FpbnN0IGl0cyB1c2VyL1JvbGUgZGlyZWN0b3J5IEFUIFNFTkQgVElNRSxcbiAqIHNvIGEgZGlnZXN0IHRoYXQgZmx1c2hlcyB0b21vcnJvdyByZWFjaGVzIHRvbW9ycm93J3MgbW9kZXJhdG9ycywgdGhlIHBsdWdpblxuICogc2VydmljZSBuZXZlciBoYW5kbGVzIGFuIGVtYWlsIGFkZHJlc3Mgb3IgYSBtZW1iZXJzaGlwIGxpc3QsIGFuZCBhIHB1Ymxpc2hlclxuICogY2FuIG5ldmVyIGxlYXJuIHdobyBpbnN0YWxsZWQgdGhlaXIgcGx1Z2luICh0aGUgcmVsYXkgbWFpbHMgZWFjaCByZWNpcGllbnRcbiAqIGluZGl2aWR1YWxseSDigJQgbm8gc2hhcmVkIFRvOiBsaW5lKS5cbiAqL1xuXG4vKiogQSBub3RpZmljYXRpb24gZXZlbnQgbnVtYmVyLiAqL1xuZXhwb3J0IHR5cGUgRWNvc3lzdGVtTm90aWZpY2F0aW9uRXZlbnRJZCA9XG4gIHwgJ04xJyB8ICdOMicgfCAnTjMnIHwgJ040JyB8ICdONScgfCAnTjYnIHwgJ043JyB8ICdOOCcgfCAnTjknIHwgJ04xMCdcbiAgfCAnTjExJyB8ICdOMTInIHwgJ04xMycgfCAnTjE0JyB8ICdOMTUnIHwgJ04xNicgfCAnTjE3JyB8ICdOMTgnIHwgJ04xOScgfCAnTjIwJ1xuICB8ICdOMjEnIHwgJ04yMicgfCAnTjIzJyB8ICdOMjQnIHwgJ04yNScgfCAnTjI2JyB8ICdOMjcnIHwgJ04yOCcgfCAnTjI5JztcblxuLyoqIEEgZGVsaXZlcnkgY2hhbm5lbC4gSW4tYXBwIGlzIHRoZSBzb3VyY2Ugb2YgdHJ1dGg7IGVtYWlsIGlzIHRoZSBjb3VydGVzeSBjb3B5LiAqL1xuZXhwb3J0IHR5cGUgRWNvc3lzdGVtTm90aWZpY2F0aW9uQ2hhbm5lbCA9ICdpbl9hcHAnIHwgJ2VtYWlsJztcblxuLyoqIEEgcGVyLXVzZXIgRU1BSUwgb3B0LW91dCBrZXkuIEluLWFwcCBpcyBuZXZlciBvcHRpb25hbC4gKi9cbmV4cG9ydCB0eXBlIEVjb3N5c3RlbUVtYWlsUHJlZmVyZW5jZSA9XG4gIHwgJ2Vjb3N5c3RlbS5yZXZpZXdzLmVtYWlsJ1xuICB8ICdlY29zeXN0ZW0udXBncmFkZXMuZW1haWwnXG4gIHwgJ2Vjb3N5c3RlbS5pbnN0YWxscy5lbWFpbCdcbiAgfCAnZWNvc3lzdGVtLm1vZGVyYXRpb25EaWdlc3QuZW1haWwnO1xuXG4vKiogVGhlIGZpZWxkIGVhY2ggcHJlZmVyZW5jZSBrZXkgaXMgc3RvcmVkIHVuZGVyIGluIHRoZSB1c2VyJ3MgcGVyLW9yZ1xuICogIGBub3RpZmljYXRpb25zLmVjb3N5c3RlbWAgcHJlZmVyZW5jZXMgKHBsYXRmb3JtIGBVc2VyUHJlZmVyZW5jZXNgKS4gKi9cbmV4cG9ydCBjb25zdCBFQ09TWVNURU1fRU1BSUxfUFJFRkVSRU5DRV9GSUVMRFM6IFJlYWRvbmx5PFJlY29yZDxFY29zeXN0ZW1FbWFpbFByZWZlcmVuY2UsIEVjb3N5c3RlbUVtYWlsUHJlZmVyZW5jZUZpZWxkPj4gPSB7XG4gICdlY29zeXN0ZW0ucmV2aWV3cy5lbWFpbCc6ICdyZXZpZXdzRW1haWwnLFxuICAnZWNvc3lzdGVtLnVwZ3JhZGVzLmVtYWlsJzogJ3VwZ3JhZGVzRW1haWwnLFxuICAnZWNvc3lzdGVtLmluc3RhbGxzLmVtYWlsJzogJ2luc3RhbGxzRW1haWwnLFxuICAnZWNvc3lzdGVtLm1vZGVyYXRpb25EaWdlc3QuZW1haWwnOiAnbW9kZXJhdGlvbkRpZ2VzdEVtYWlsJyxcbn07XG5cbi8qKiBTdG9yZWQgZmllbGQgbmFtZXMgb2YgdGhlIGVjb3N5c3RlbSBlbWFpbCBwcmVmZXJlbmNlcyAoYWxsIGRlZmF1bHQgYHRydWVgKS4gKi9cbmV4cG9ydCB0eXBlIEVjb3N5c3RlbUVtYWlsUHJlZmVyZW5jZUZpZWxkID0gJ3Jldmlld3NFbWFpbCcgfCAndXBncmFkZXNFbWFpbCcgfCAnaW5zdGFsbHNFbWFpbCcgfCAnbW9kZXJhdGlvbkRpZ2VzdEVtYWlsJztcblxuLyoqIEV2ZXJ5IHN0b3JlZCBlY29zeXN0ZW0gZW1haWwtcHJlZmVyZW5jZSBmaWVsZC4gKi9cbmV4cG9ydCBjb25zdCBFQ09TWVNURU1fRU1BSUxfUFJFRkVSRU5DRV9GSUVMRF9OQU1FUzogcmVhZG9ubHkgRWNvc3lzdGVtRW1haWxQcmVmZXJlbmNlRmllbGRbXSA9XG4gIE9iamVjdC52YWx1ZXMoRUNPU1lTVEVNX0VNQUlMX1BSRUZFUkVOQ0VfRklFTERTKTtcblxuLyoqIEhvdyBvZnRlbiBhIGJhdGNoZWQgZW1haWwgaXMgZmx1c2hlZC4gKi9cbmV4cG9ydCB0eXBlIEVjb3N5c3RlbURpZ2VzdENhZGVuY2UgPSAnaG91cmx5JyB8ICdkYWlseScgfCAnd2Vla2x5JztcblxuLyoqIE9uZSBldmVudCdzIGRlbGl2ZXJ5IHJ1bGVzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBFY29zeXN0ZW1FdmVudFNwZWMge1xuICAvKiogT25lLWxpbmUgZGVzY3JpcHRpb24gKGRvY3MsIGxvZ3MpLiAqL1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAvKiogQ2hhbm5lbHMgdGhlIGV2ZW50IGlzIGRlbGl2ZXJlZCBvbi4gKi9cbiAgY2hhbm5lbHM6IHJlYWRvbmx5IEVjb3N5c3RlbU5vdGlmaWNhdGlvbkNoYW5uZWxbXTtcbiAgLyoqXG4gICAqIEVtYWlsIG9wdC1vdXQga2V5LCBvciBgbnVsbGAgd2hlbiB0aGUgZW1haWwgaXMgVFJBTlNBQ1RJT05BTCAvIHNlY3VyaXR5XG4gICAqIChOMSwgTjPigJNONSwgTjfigJNOMTAsIE4xOOKAk04yMywgTjI1LCBOMjgsIE4yOSBjYW4ndCBiZSB0dXJuZWQgb2ZmKS5cbiAgICovXG4gIHByZWZlcmVuY2U6IEVjb3N5c3RlbUVtYWlsUHJlZmVyZW5jZSB8IG51bGw7XG4gIC8qKiBXaGVuIHRoZSBlbWFpbCBpcyBiYXRjaGVkIHJhdGhlciB0aGFuIGltbWVkaWF0ZSwgaXRzIGNhZGVuY2UuICovXG4gIGRpZ2VzdD86IEVjb3N5c3RlbURpZ2VzdENhZGVuY2U7XG4gIC8qKiBBbGxvd2VkIHRvIGFkZHJlc3MgYSByYXcgZW1haWwgKHRoZSBhbm9ueW1vdXMgU1VCTUlUVEVSKSDigJQgb25seSB0aGVcbiAgICogIHRyYW5zYWN0aW9uYWwgc3VibWlzc2lvbiBub3RpY2VzLiAqL1xuICBhbGxvd3NBZGRyZXNzPzogYm9vbGVhbjtcbn1cblxuLyoqIFRoZSBub3RpZmljYXRpb24gZXZlbnQgdGFibGUsIGFzIGRhdGEuICovXG5leHBvcnQgY29uc3QgRUNPU1lTVEVNX05PVElGSUNBVElPTl9FVkVOVFM6IFJlYWRvbmx5PFJlY29yZDxFY29zeXN0ZW1Ob3RpZmljYXRpb25FdmVudElkLCBFY29zeXN0ZW1FdmVudFNwZWM+PiA9IHtcbiAgTjE6IHsgZGVzY3JpcHRpb246ICdBbm9ueW1vdXMgc3VibWlzc2lvbiByZWNlaXZlZCAobWFnaWMgbGluayknLCBjaGFubmVsczogWydlbWFpbCddLCBwcmVmZXJlbmNlOiBudWxsLCBhbGxvd3NBZGRyZXNzOiB0cnVlIH0sXG4gIE4yOiB7IGRlc2NyaXB0aW9uOiAnU3VibWlzc2lvbiB2ZXJpZmllZCwgZW50ZXJlZCB0aGUgbW9kZXJhdGlvbiBxdWV1ZScsIGNoYW5uZWxzOiBbJ2luX2FwcCcsICdlbWFpbCddLCBwcmVmZXJlbmNlOiAnZWNvc3lzdGVtLm1vZGVyYXRpb25EaWdlc3QuZW1haWwnLCBkaWdlc3Q6ICdkYWlseScgfSxcbiAgTjM6IHsgZGVzY3JpcHRpb246ICdTdWJtaXNzaW9uIGZhaWxlZCBhdXRvbWF0ZWQgZ2F0ZXMnLCBjaGFubmVsczogWydlbWFpbCddLCBwcmVmZXJlbmNlOiBudWxsLCBhbGxvd3NBZGRyZXNzOiB0cnVlIH0sXG4gIE40OiB7IGRlc2NyaXB0aW9uOiAnU3VibWlzc2lvbiBhcHByb3ZlZCBvciByZWplY3RlZCcsIGNoYW5uZWxzOiBbJ2VtYWlsJ10sIHByZWZlcmVuY2U6IG51bGwsIGFsbG93c0FkZHJlc3M6IHRydWUgfSxcbiAgTjU6IHsgZGVzY3JpcHRpb246ICdTdWJtaXNzaW9uIGNsYWltZWQgYnkgYW4gYWNjb3VudCcsIGNoYW5uZWxzOiBbJ2luX2FwcCcsICdlbWFpbCddLCBwcmVmZXJlbmNlOiBudWxsIH0sXG4gIE42OiB7IGRlc2NyaXB0aW9uOiAnVmVyaWZpZWQtcHVibGlzaGVyIGFwcGxpY2F0aW9uIHN1Ym1pdHRlZCcsIGNoYW5uZWxzOiBbJ2luX2FwcCcsICdlbWFpbCddLCBwcmVmZXJlbmNlOiAnZWNvc3lzdGVtLm1vZGVyYXRpb25EaWdlc3QuZW1haWwnLCBkaWdlc3Q6ICdkYWlseScgfSxcbiAgTjc6IHsgZGVzY3JpcHRpb246ICdWZXJpZmllZCBhcHBsaWNhdGlvbiBhcHByb3ZlZCBvciByZWplY3RlZCcsIGNoYW5uZWxzOiBbJ2luX2FwcCcsICdlbWFpbCddLCBwcmVmZXJlbmNlOiBudWxsIH0sXG4gIE44OiB7IGRlc2NyaXB0aW9uOiAnTW9kZXJhdGlvbiBhY3Rpb24gb24gYSBsaXN0aW5nIChzdXNwZW5kLCB5YW5rLCB0YWtlZG93biknLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogbnVsbCB9LFxuICBOOTogeyBkZXNjcmlwdGlvbjogJ093bmVyc2hpcCB0cmFuc2ZlciByZXF1ZXN0ZWQnLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogbnVsbCB9LFxuICBOMTA6IHsgZGVzY3JpcHRpb246ICdPd25lcnNoaXAgdHJhbnNmZXIgYWNjZXB0ZWQsIGRlY2xpbmVkLCBhcHByb3ZlZCBvciByZWplY3RlZCcsIGNoYW5uZWxzOiBbJ2luX2FwcCcsICdlbWFpbCddLCBwcmVmZXJlbmNlOiBudWxsIH0sXG4gIE4xMTogeyBkZXNjcmlwdGlvbjogJ0luc3RhbGwgcmVxdWVzdGVkIChwb2xpY3kgcmVxdWlyZXMgYXBwcm92YWwpJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6ICdlY29zeXN0ZW0uaW5zdGFsbHMuZW1haWwnIH0sXG4gIE4xMjogeyBkZXNjcmlwdGlvbjogJ0luc3RhbGwgYXBwcm92ZWQgb3IgZGVuaWVkJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6ICdlY29zeXN0ZW0uaW5zdGFsbHMuZW1haWwnIH0sXG4gIE4xMzogeyBkZXNjcmlwdGlvbjogJ05ldyB2ZXJzaW9uIGF2YWlsYWJsZSB3aXRoaW4gYW4gaW5zdGFsbFxcJ3MgcG9saWN5JywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6ICdlY29zeXN0ZW0udXBncmFkZXMuZW1haWwnLCBkaWdlc3Q6ICd3ZWVrbHknIH0sXG4gIE4xNDogeyBkZXNjcmlwdGlvbjogJ0xpc3RpbmcgZGVwcmVjYXRlZCBvciB1bm1haW50YWluZWQnLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogJ2Vjb3N5c3RlbS51cGdyYWRlcy5lbWFpbCcgfSxcbiAgTjE1OiB7IGRlc2NyaXB0aW9uOiAnTmV3IG9yIGVkaXRlZCByZXZpZXcgb24gYSBsaXN0aW5nJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6ICdlY29zeXN0ZW0ucmV2aWV3cy5lbWFpbCcsIGRpZ2VzdDogJ2hvdXJseScgfSxcbiAgTjE2OiB7IGRlc2NyaXB0aW9uOiAnUHVibGlzaGVyIHJlcGxpZWQgdG8geW91ciByZXZpZXcnLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogJ2Vjb3N5c3RlbS5yZXZpZXdzLmVtYWlsJyB9LFxuICBOMTc6IHsgZGVzY3JpcHRpb246ICdSZXZpZXcgaGVsZCAocmVwb3J0cywgYnVyc3QsIGZpbHRlciknLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogJ2Vjb3N5c3RlbS5tb2RlcmF0aW9uRGlnZXN0LmVtYWlsJywgZGlnZXN0OiAnZGFpbHknIH0sXG4gIE4xODogeyBkZXNjcmlwdGlvbjogJ1lvdXIgcmV2aWV3IHdhcyByZW1vdmVkJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6IG51bGwgfSxcbiAgTjE5OiB7IGRlc2NyaXB0aW9uOiAnUmV2aWV3IGZsYWdnZWQgYXMgYSBzZWN1cml0eSBpc3N1ZScsIGNoYW5uZWxzOiBbJ2luX2FwcCcsICdlbWFpbCddLCBwcmVmZXJlbmNlOiBudWxsIH0sXG4gIE4yMDogeyBkZXNjcmlwdGlvbjogJ0Fkdmlzb3J5IGRyYWZ0IGF1dG8tY3JlYXRlZCAoQ1ZFIHJlc2NhbiknLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogbnVsbCB9LFxuICBOMjE6IHsgZGVzY3JpcHRpb246ICdBZHZpc29yeSBwdWJsaXNoZWQgb3Igd2l0aGRyYXduJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6IG51bGwgfSxcbiAgTjIyOiB7IGRlc2NyaXB0aW9uOiAnTW9kZXJhdGlvbiBTTEEgYnJlYWNoJywgY2hhbm5lbHM6IFsnZW1haWwnXSwgcHJlZmVyZW5jZTogbnVsbCB9LFxuICBOMjM6IHsgZGVzY3JpcHRpb246ICdBZGRlZCB0byBvciByZW1vdmVkIGZyb20gdGhlIEVjb3N5c3RlbSBNYW5hZ2VyIHJvbGUnLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogbnVsbCB9LFxuICBOMjQ6IHsgZGVzY3JpcHRpb246ICdQdWJsaXNoIHJlcXVlc3Qgc3VibWl0dGVkJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6ICdlY29zeXN0ZW0ubW9kZXJhdGlvbkRpZ2VzdC5lbWFpbCcsIGRpZ2VzdDogJ2RhaWx5JyB9LFxuICBOMjU6IHsgZGVzY3JpcHRpb246ICdQdWJsaXNoIHJlcXVlc3QgYXBwcm92ZWQgb3IgcmVqZWN0ZWQnLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogbnVsbCB9LFxuICBOMjY6IHsgZGVzY3JpcHRpb246ICdMaXN0aW5nIG9yIHZlcnNpb24gcGF1c2VkIGJ5IGl0cyBwdWJsaXNoZXInLCBjaGFubmVsczogWydpbl9hcHAnXSwgcHJlZmVyZW5jZTogJ2Vjb3N5c3RlbS51cGdyYWRlcy5lbWFpbCcgfSxcbiAgTjI3OiB7IGRlc2NyaXB0aW9uOiAnSW5zdGFsbGVkIGxpc3RpbmcgYXV0by11cGRhdGVkIHdpdGhpbiBpdHMgcmFuZ2UnLCBjaGFubmVsczogWydpbl9hcHAnLCAnZW1haWwnXSwgcHJlZmVyZW5jZTogJ2Vjb3N5c3RlbS51cGdyYWRlcy5lbWFpbCcsIGRpZ2VzdDogJ3dlZWtseScgfSxcbiAgTjI4OiB7IGRlc2NyaXB0aW9uOiAnQSByZXF1ZXN0IG5lZWRzIGEgc2Vjb25kIGFwcHJvdmFsJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6IG51bGwgfSxcbiAgTjI5OiB7IGRlc2NyaXB0aW9uOiAnUGxhbiBjaGFuZ2UgYWZmZWN0cyBwdWJsaXNoaW5nJywgY2hhbm5lbHM6IFsnaW5fYXBwJywgJ2VtYWlsJ10sIHByZWZlcmVuY2U6IG51bGwgfSxcbn07XG5cbi8qKiBXaGV0aGVyIGB2YWx1ZWAgaXMgYSBub3RpZmljYXRpb24gZXZlbnQgbnVtYmVyLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRWNvc3lzdGVtTm90aWZpY2F0aW9uRXZlbnQodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBFY29zeXN0ZW1Ob3RpZmljYXRpb25FdmVudElkIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKEVDT1NZU1RFTV9OT1RJRklDQVRJT05fRVZFTlRTLCB2YWx1ZSk7XG59XG5cbi8qKiBPcmctbG9jYWwgcGVybWlzc2lvbnMgYW4ge0BsaW5rIEVjb3N5c3RlbVJlY2lwaWVudFNwZWN9IGBvcmdfcGVybWlzc2lvbmAgcnVsZSBtYXkgbmFtZS4gKi9cbmV4cG9ydCB0eXBlIEVjb3N5c3RlbU9yZ1JlY2lwaWVudFBlcm1pc3Npb24gPSAncHVibGlzaGVyczptYW5hZ2UnIHwgJ3BsdWdpbl9pbnN0YWxsczptYW5hZ2UnO1xuLyoqIFN5c3RlbS1vcmcgcGVybWlzc2lvbnMgYSBgbW9kZXJhdG9yc2AgcnVsZSBtYXkgbmFtZS4gKi9cbmV4cG9ydCB0eXBlIEVjb3N5c3RlbU1vZGVyYXRvclBlcm1pc3Npb24gPSAncGx1Z2luczptb2RlcmF0ZScgfCAncHVibGlzaGVyczp2ZXJpZnknO1xuXG4vKipcbiAqIEEgcmVjaXBpZW50IFJVTEUsIHJlc29sdmVkIGJ5IHBsYXRmb3JtIGF0IHNlbmQgdGltZTpcbiAqXG4gKiAgLSBgdXNlcmAg4oCUIG9uZSB1c2VyIChSZXF1ZXN0ZXIsIFJldmlldyBhdXRob3IsIHRoZSBhZmZlY3RlZCB1c2VyIG9mIE4yMykuXG4gKiAgICBgb3JnSWRgIHBpY2tzIHRoZSBpbmJveDsgZGVmYXVsdHMgdG8gdGhlIHVzZXIncyBsYXN0IGFjdGl2ZSBvcmcuXG4gKiAgLSBgb3JnX3Blcm1pc3Npb25gIOKAlCBhY3RpdmUgbWVtYmVycyBvZiBgb3JnSWRgIGhvbGRpbmcgYHBlcm1pc3Npb25gXG4gKiAgICAoUHVibGlzaGVyIG1hbmFnZXJzID0gYHB1Ymxpc2hlcnM6bWFuYWdlYCwgT3JnIGFwcHJvdmVycyA9XG4gKiAgICBgcGx1Z2luX2luc3RhbGxzOm1hbmFnZWApLiBXaXRoIGBpbmhlcml0RnJvbVJvb3RgLCBhIHRlYW0gd2l0aCBubyBob2xkZXJzXG4gKiAgICBmYWxscyBiYWNrIHRvIGl0cyByb290IG9yZydzIGhvbGRlcnM7IHdpdGggbm9uZSBhbnl3aGVyZSwgdGhlIG9yZydzIG93bmVycy5cbiAqICAtIGBtb2RlcmF0b3JzYCDigJQgdGhlIHN5c3RlbSBvcmcncyBob2xkZXJzIG9mIGBwZXJtaXNzaW9uYCAodGhlIEVjb3N5c3RlbVxuICogICAgTWFuYWdlciByb2xlKSwgbWludXMgYW55b25lIHdpdGggYSBjb25mbGljdCBvZiBpbnRlcmVzdCAobWVtYmVycyBvZlxuICogICAgYGV4Y2x1ZGVNZW1iZXJzT2ZPcmdJZGAsIG9yIHRoZSBsaXN0ZWQgdXNlcnMpOyBzdXBlcmFkbWlucyB3aGVuIGVtcHR5LlxuICogIC0gYHN1cGVyYWRtaW5zYCDigJQgZXZlcnkgcGxhdGZvcm0gc3VwZXJhZG1pbi5cbiAqICAtIGBhZGRyZXNzYCDigJQgYSByYXcgYWRkcmVzczsgb25seSB0aGUgYW5vbnltb3VzIFNVQk1JVFRFUiBub3RpY2VzIChOMSwgTjMsXG4gKiAgICBONCksIHdob3NlIHJlY2lwaWVudCBoYXMgbm8gYWNjb3VudC5cbiAqL1xuZXhwb3J0IHR5cGUgRWNvc3lzdGVtUmVjaXBpZW50U3BlYyA9XG4gIHwgeyBraW5kOiAndXNlcic7IHVzZXJJZDogc3RyaW5nOyBvcmdJZD86IHN0cmluZyB9XG4gIHwgeyBraW5kOiAnb3JnX3Blcm1pc3Npb24nOyBvcmdJZDogc3RyaW5nOyBwZXJtaXNzaW9uOiBFY29zeXN0ZW1PcmdSZWNpcGllbnRQZXJtaXNzaW9uOyBpbmhlcml0RnJvbVJvb3Q/OiBib29sZWFuIH1cbiAgfCB7IGtpbmQ6ICdtb2RlcmF0b3JzJzsgcGVybWlzc2lvbjogRWNvc3lzdGVtTW9kZXJhdG9yUGVybWlzc2lvbjsgZXhjbHVkZU1lbWJlcnNPZk9yZ0lkPzogc3RyaW5nOyBleGNsdWRlVXNlcklkcz86IHN0cmluZ1tdIH1cbiAgfCB7IGtpbmQ6ICdzdXBlcmFkbWlucycgfVxuICB8IHsga2luZDogJ2FkZHJlc3MnOyBlbWFpbDogc3RyaW5nIH07XG5cbi8qKiBUaGUgYm9keSBvZiBhbiBlY29zeXN0ZW0gc2VuZCB0aHJvdWdoIHBsYXRmb3JtJ3Mgbm90aWZ5IHJlbGF5LiAqL1xuZXhwb3J0IGludGVyZmFjZSBFY29zeXN0ZW1Ob3RpZnlSZXF1ZXN0IHtcbiAgZXZlbnQ6IEVjb3N5c3RlbU5vdGlmaWNhdGlvbkV2ZW50SWQ7XG4gIHJlY2lwaWVudHM6IEVjb3N5c3RlbVJlY2lwaWVudFNwZWNbXTtcbiAgc3ViamVjdDogc3RyaW5nO1xuICAvKiogUGxhaW4tdGV4dCBib2R5IChlbWFpbCBib2R5IGFuZCBpbi1hcHAgY29udGVudCkuICovXG4gIHRleHQ6IHN0cmluZztcbiAgLyoqIFN1YnNldCBvZiB0aGUgZXZlbnQncyBjaGFubmVscyB0byBkZWxpdmVyIG9uIChkZWZhdWx0OiBhbGwgb2YgdGhlbSkuIFRoZVxuICAgKiAgZGlnZXN0IGRpc3BhdGNoZXIgc2VuZHMgYFsnZW1haWwnXWAgYmVjYXVzZSBpbi1hcHAgd2VudCBvdXQgYXQgZW5xdWV1ZS4gKi9cbiAgY2hhbm5lbHM/OiBFY29zeXN0ZW1Ob3RpZmljYXRpb25DaGFubmVsW107XG4gIC8qKiBEZWxpdmVyIHRoZSBlbWFpbCBldmVuIHRvIHVzZXJzIHdobyBvcHRlZCBvdXQg4oCUIGZvciBhbiBldmVudCB3aG9zZVxuICAgKiAgbm9ybWFsbHktb3B0aW9uYWwgZW1haWwgaXMgbWFuZGF0b3J5IGluIHRoaXMgaW5zdGFuY2UgKE4yNCB5YW5rLCBhZHZpc29yeVxuICAgKiAgYW5kIHNlY3VyaXR5LWZpeCByZXF1ZXN0cykuICovXG4gIG1hbmRhdG9yeT86IGJvb2xlYW47XG59XG5cbi8qKiBIYXJkIGNhcHMsIG1hdGNoaW5nIHRoZSBtZXNzYWdlIHNlcnZpY2UncyBvd24gbGltaXRzLiAqL1xuZXhwb3J0IGNvbnN0IEVDT1NZU1RFTV9OT1RJRllfU1VCSkVDVF9NQVggPSA1MDA7XG5leHBvcnQgY29uc3QgRUNPU1lTVEVNX05PVElGWV9URVhUX01BWCA9IDEwMDAwO1xuY29uc3QgTUFYX1JFQ0lQSUVOVF9SVUxFUyA9IDUwO1xuXG5jb25zdCBPUkdfUEVSTUlTU0lPTlM6IHJlYWRvbmx5IHN0cmluZ1tdID0gWydwdWJsaXNoZXJzOm1hbmFnZScsICdwbHVnaW5faW5zdGFsbHM6bWFuYWdlJ107XG5jb25zdCBNT0RFUkFUT1JfUEVSTUlTU0lPTlM6IHJlYWRvbmx5IHN0cmluZ1tdID0gWydwbHVnaW5zOm1vZGVyYXRlJywgJ3B1Ymxpc2hlcnM6dmVyaWZ5J107XG5jb25zdCBFTUFJTF9TSEFQRSA9IC9eW15cXHNAXStAW15cXHNAXStcXC5bXlxcc0BdKyQvO1xuXG5mdW5jdGlvbiBub25FbXB0eVN0cmluZyh2OiB1bmtub3duLCBtYXggPSAyNTUpOiB2IGlzIHN0cmluZyB7XG4gIHJldHVybiB0eXBlb2YgdiA9PT0gJ3N0cmluZycgJiYgdi50cmltKCkubGVuZ3RoID4gMCAmJiB2Lmxlbmd0aCA8PSBtYXg7XG59XG5cbmZ1bmN0aW9uIHBhcnNlUmVjaXBpZW50KHJhdzogdW5rbm93biwgc3BlYzogRWNvc3lzdGVtRXZlbnRTcGVjKTogRWNvc3lzdGVtUmVjaXBpZW50U3BlYyB8IHN0cmluZyB7XG4gIGlmICghcmF3IHx8IHR5cGVvZiByYXcgIT09ICdvYmplY3QnKSByZXR1cm4gJ2VhY2ggcmVjaXBpZW50IG11c3QgYmUgYW4gb2JqZWN0JztcbiAgY29uc3QgciA9IHJhdyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgc3dpdGNoIChyLmtpbmQpIHtcbiAgICBjYXNlICd1c2VyJzpcbiAgICAgIGlmICghbm9uRW1wdHlTdHJpbmcoci51c2VySWQpKSByZXR1cm4gJ3VzZXIgcmVjaXBpZW50IG5lZWRzIHVzZXJJZCc7XG4gICAgICBpZiAoci5vcmdJZCAhPT0gdW5kZWZpbmVkICYmICFub25FbXB0eVN0cmluZyhyLm9yZ0lkKSkgcmV0dXJuICd1c2VyIHJlY2lwaWVudCBvcmdJZCBtdXN0IGJlIGEgc3RyaW5nJztcbiAgICAgIHJldHVybiB7IGtpbmQ6ICd1c2VyJywgdXNlcklkOiByLnVzZXJJZCwgLi4uKHIub3JnSWQgPyB7IG9yZ0lkOiByLm9yZ0lkIGFzIHN0cmluZyB9IDoge30pIH07XG4gICAgY2FzZSAnb3JnX3Blcm1pc3Npb24nOlxuICAgICAgaWYgKCFub25FbXB0eVN0cmluZyhyLm9yZ0lkKSkgcmV0dXJuICdvcmdfcGVybWlzc2lvbiByZWNpcGllbnQgbmVlZHMgb3JnSWQnO1xuICAgICAgaWYgKHR5cGVvZiByLnBlcm1pc3Npb24gIT09ICdzdHJpbmcnIHx8ICFPUkdfUEVSTUlTU0lPTlMuaW5jbHVkZXMoci5wZXJtaXNzaW9uKSkgcmV0dXJuICdvcmdfcGVybWlzc2lvbiByZWNpcGllbnQgbmFtZXMgYW4gdW5zdXBwb3J0ZWQgcGVybWlzc2lvbic7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBraW5kOiAnb3JnX3Blcm1pc3Npb24nLFxuICAgICAgICBvcmdJZDogci5vcmdJZCxcbiAgICAgICAgcGVybWlzc2lvbjogci5wZXJtaXNzaW9uIGFzIEVjb3N5c3RlbU9yZ1JlY2lwaWVudFBlcm1pc3Npb24sXG4gICAgICAgIC4uLihyLmluaGVyaXRGcm9tUm9vdCA9PT0gdHJ1ZSA/IHsgaW5oZXJpdEZyb21Sb290OiB0cnVlIH0gOiB7fSksXG4gICAgICB9O1xuICAgIGNhc2UgJ21vZGVyYXRvcnMnOiB7XG4gICAgICBpZiAodHlwZW9mIHIucGVybWlzc2lvbiAhPT0gJ3N0cmluZycgfHwgIU1PREVSQVRPUl9QRVJNSVNTSU9OUy5pbmNsdWRlcyhyLnBlcm1pc3Npb24pKSByZXR1cm4gJ21vZGVyYXRvcnMgcmVjaXBpZW50IG5hbWVzIGFuIHVuc3VwcG9ydGVkIHBlcm1pc3Npb24nO1xuICAgICAgaWYgKHIuZXhjbHVkZU1lbWJlcnNPZk9yZ0lkICE9PSB1bmRlZmluZWQgJiYgIW5vbkVtcHR5U3RyaW5nKHIuZXhjbHVkZU1lbWJlcnNPZk9yZ0lkKSkgcmV0dXJuICdleGNsdWRlTWVtYmVyc09mT3JnSWQgbXVzdCBiZSBhIHN0cmluZyc7XG4gICAgICBjb25zdCBleGNsdWRlID0gci5leGNsdWRlVXNlcklkcztcbiAgICAgIGlmIChleGNsdWRlICE9PSB1bmRlZmluZWQgJiYgKCFBcnJheS5pc0FycmF5KGV4Y2x1ZGUpIHx8ICFleGNsdWRlLmV2ZXJ5KCh1KSA9PiBub25FbXB0eVN0cmluZyh1KSkpKSByZXR1cm4gJ2V4Y2x1ZGVVc2VySWRzIG11c3QgYmUgYW4gYXJyYXkgb2YgaWRzJztcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGtpbmQ6ICdtb2RlcmF0b3JzJyxcbiAgICAgICAgcGVybWlzc2lvbjogci5wZXJtaXNzaW9uIGFzIEVjb3N5c3RlbU1vZGVyYXRvclBlcm1pc3Npb24sXG4gICAgICAgIC4uLihyLmV4Y2x1ZGVNZW1iZXJzT2ZPcmdJZCA/IHsgZXhjbHVkZU1lbWJlcnNPZk9yZ0lkOiByLmV4Y2x1ZGVNZW1iZXJzT2ZPcmdJZCBhcyBzdHJpbmcgfSA6IHt9KSxcbiAgICAgICAgLi4uKGV4Y2x1ZGUgPyB7IGV4Y2x1ZGVVc2VySWRzOiBleGNsdWRlIGFzIHN0cmluZ1tdIH0gOiB7fSksXG4gICAgICB9O1xuICAgIH1cbiAgICBjYXNlICdzdXBlcmFkbWlucyc6XG4gICAgICByZXR1cm4geyBraW5kOiAnc3VwZXJhZG1pbnMnIH07XG4gICAgY2FzZSAnYWRkcmVzcyc6XG4gICAgICBpZiAoIXNwZWMuYWxsb3dzQWRkcmVzcykgcmV0dXJuICdhZGRyZXNzIHJlY2lwaWVudHMgYXJlIG9ubHkgYWxsb3dlZCBmb3IgYW5vbnltb3VzLXN1Ym1pc3Npb24gbm90aWNlcyc7XG4gICAgICBpZiAoIW5vbkVtcHR5U3RyaW5nKHIuZW1haWwsIDMyMCkgfHwgIUVNQUlMX1NIQVBFLnRlc3Qoci5lbWFpbCkpIHJldHVybiAnYWRkcmVzcyByZWNpcGllbnQgbmVlZHMgYSB2YWxpZCBlbWFpbCc7XG4gICAgICByZXR1cm4geyBraW5kOiAnYWRkcmVzcycsIGVtYWlsOiByLmVtYWlsLnRyaW0oKS50b0xvd2VyQ2FzZSgpIH07XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiAndW5rbm93biByZWNpcGllbnQga2luZCc7XG4gIH1cbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBhbiB7QGxpbmsgRWNvc3lzdGVtTm90aWZ5UmVxdWVzdH0uIFJldHVybnMgdGhlIG5vcm1hbGl6ZWQgcmVxdWVzdCxcbiAqIG9yIGFuIGVycm9yIHN0cmluZyAodGhlIHJlbGF5J3MgNDAwKS4gUHVyZSwgc28gYm90aCB0aGUgc2VuZGVyIChmYWlsIGF0XG4gKiBlbnF1ZXVlLCBub3QgYXQgMDk6MDAgdG9tb3Jyb3cpIGFuZCB0aGUgcmVsYXkgdXNlIHRoZSBzYW1lIHJ1bGVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VFY29zeXN0ZW1Ob3RpZnlSZXF1ZXN0KGJvZHk6IHVua25vd24pOiBFY29zeXN0ZW1Ob3RpZnlSZXF1ZXN0IHwgc3RyaW5nIHtcbiAgaWYgKCFib2R5IHx8IHR5cGVvZiBib2R5ICE9PSAnb2JqZWN0JykgcmV0dXJuICdib2R5IG11c3QgYmUgYW4gb2JqZWN0JztcbiAgY29uc3QgYiA9IGJvZHkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGlmICghaXNFY29zeXN0ZW1Ob3RpZmljYXRpb25FdmVudChiLmV2ZW50KSkgcmV0dXJuICdldmVudCBtdXN0IGJlIG9uZSBvZiBOMS4uTjI5JztcbiAgY29uc3Qgc3BlYyA9IEVDT1NZU1RFTV9OT1RJRklDQVRJT05fRVZFTlRTW2IuZXZlbnRdO1xuICBpZiAoIW5vbkVtcHR5U3RyaW5nKGIuc3ViamVjdCwgRUNPU1lTVEVNX05PVElGWV9TVUJKRUNUX01BWCkpIHJldHVybiBgc3ViamVjdCBpcyByZXF1aXJlZCAobWF4ICR7RUNPU1lTVEVNX05PVElGWV9TVUJKRUNUX01BWH0pYDtcbiAgaWYgKCFub25FbXB0eVN0cmluZyhiLnRleHQsIEVDT1NZU1RFTV9OT1RJRllfVEVYVF9NQVgpKSByZXR1cm4gYHRleHQgaXMgcmVxdWlyZWQgKG1heCAke0VDT1NZU1RFTV9OT1RJRllfVEVYVF9NQVh9KWA7XG4gIGlmICghQXJyYXkuaXNBcnJheShiLnJlY2lwaWVudHMpIHx8IGIucmVjaXBpZW50cy5sZW5ndGggPT09IDApIHJldHVybiAncmVjaXBpZW50cyBtdXN0IGJlIGEgbm9uLWVtcHR5IGFycmF5JztcbiAgaWYgKGIucmVjaXBpZW50cy5sZW5ndGggPiBNQVhfUkVDSVBJRU5UX1JVTEVTKSByZXR1cm4gYGF0IG1vc3QgJHtNQVhfUkVDSVBJRU5UX1JVTEVTfSByZWNpcGllbnQgcnVsZXNgO1xuICBjb25zdCByZWNpcGllbnRzOiBFY29zeXN0ZW1SZWNpcGllbnRTcGVjW10gPSBbXTtcbiAgZm9yIChjb25zdCByYXcgb2YgYi5yZWNpcGllbnRzKSB7XG4gICAgY29uc3QgcGFyc2VkID0gcGFyc2VSZWNpcGllbnQocmF3LCBzcGVjKTtcbiAgICBpZiAodHlwZW9mIHBhcnNlZCA9PT0gJ3N0cmluZycpIHJldHVybiBwYXJzZWQ7XG4gICAgcmVjaXBpZW50cy5wdXNoKHBhcnNlZCk7XG4gIH1cbiAgbGV0IGNoYW5uZWxzOiBFY29zeXN0ZW1Ob3RpZmljYXRpb25DaGFubmVsW10gfCB1bmRlZmluZWQ7XG4gIGlmIChiLmNoYW5uZWxzICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoYi5jaGFubmVscykgfHwgYi5jaGFubmVscy5sZW5ndGggPT09IDApIHJldHVybiAnY2hhbm5lbHMgbXVzdCBiZSBhIG5vbi1lbXB0eSBhcnJheSc7XG4gICAgY29uc3QgYmFkID0gYi5jaGFubmVscy5maWx0ZXIoKGMpID0+ICFzcGVjLmNoYW5uZWxzLmluY2x1ZGVzKGMgYXMgRWNvc3lzdGVtTm90aWZpY2F0aW9uQ2hhbm5lbCkpO1xuICAgIGlmIChiYWQubGVuZ3RoID4gMCkgcmV0dXJuIGBldmVudCAke2IuZXZlbnR9IGlzIG5vdCBkZWxpdmVyZWQgb246ICR7YmFkLmpvaW4oJywgJyl9YDtcbiAgICBjaGFubmVscyA9IFsuLi5uZXcgU2V0KGIuY2hhbm5lbHMgYXMgRWNvc3lzdGVtTm90aWZpY2F0aW9uQ2hhbm5lbFtdKV07XG4gIH1cbiAgaWYgKGIubWFuZGF0b3J5ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIGIubWFuZGF0b3J5ICE9PSAnYm9vbGVhbicpIHJldHVybiAnbWFuZGF0b3J5IG11c3QgYmUgYSBib29sZWFuJztcbiAgcmV0dXJuIHtcbiAgICBldmVudDogYi5ldmVudCxcbiAgICByZWNpcGllbnRzLFxuICAgIHN1YmplY3Q6IGIuc3ViamVjdC50cmltKCksXG4gICAgdGV4dDogYi50ZXh0LnRyaW0oKSxcbiAgICAuLi4oY2hhbm5lbHMgPyB7IGNoYW5uZWxzIH0gOiB7fSksXG4gICAgLi4uKGIubWFuZGF0b3J5ID09PSB0cnVlID8geyBtYW5kYXRvcnk6IHRydWUgfSA6IHt9KSxcbiAgfTtcbn1cblxuLyoqIFRoZSBVVEMgaG91ciBkaWdlc3RzIGZsdXNoIGF0IChcImRhaWx5IGRpZ2VzdCBlbWFpbCAoMDk6MDAgVVRDKVwiKS4gKi9cbmV4cG9ydCBjb25zdCBFQ09TWVNURU1fRElHRVNUX0hPVVJfVVRDID0gOTtcblxuLyoqXG4gKiBUaGUgbmV4dCBmbHVzaCB0aW1lIGZvciBhIGRpZ2VzdCBjYWRlbmNlLCBzdHJpY3RseSBhZnRlciBgbm93YDpcbiAqIGBob3VybHlgIOKGkiB0aGUgbmV4dCB0b3Agb2YgdGhlIGhvdXI7IGBkYWlseWAg4oaSIHRoZSBuZXh0IDA5OjAwIFVUQztcbiAqIGB3ZWVrbHlgIOKGkiB0aGUgbmV4dCBNb25kYXkgMDk6MDAgVVRDLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbmV4dEVjb3N5c3RlbURpZ2VzdFRpbWUoY2FkZW5jZTogRWNvc3lzdGVtRGlnZXN0Q2FkZW5jZSwgbm93OiBEYXRlID0gbmV3IERhdGUoKSk6IERhdGUge1xuICBjb25zdCB0ID0gbmV3IERhdGUobm93LmdldFRpbWUoKSk7XG4gIGlmIChjYWRlbmNlID09PSAnaG91cmx5Jykge1xuICAgIHQuc2V0VVRDTWludXRlcygwLCAwLCAwKTtcbiAgICB0LnNldFVUQ0hvdXJzKHQuZ2V0VVRDSG91cnMoKSArIDEpO1xuICAgIHJldHVybiB0O1xuICB9XG4gIHQuc2V0VVRDSG91cnMoRUNPU1lTVEVNX0RJR0VTVF9IT1VSX1VUQywgMCwgMCwgMCk7XG4gIGlmICh0LmdldFRpbWUoKSA8PSBub3cuZ2V0VGltZSgpKSB0LnNldFVUQ0RhdGUodC5nZXRVVENEYXRlKCkgKyAxKTtcbiAgaWYgKGNhZGVuY2UgPT09ICd3ZWVrbHknKSB7XG4gICAgLy8gZ2V0VVRDRGF5OiAwID0gU3VuZGF5IOKApiAxID0gTW9uZGF5LlxuICAgIHdoaWxlICh0LmdldFVUQ0RheSgpICE9PSAxKSB0LnNldFVUQ0RhdGUodC5nZXRVVENEYXRlKCkgKyAxKTtcbiAgfVxuICByZXR1cm4gdDtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUZW1wbGF0ZXNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKiogQSByZW5kZXJlZCBub3RpY2UuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjb3N5c3RlbU5vdGlmaWNhdGlvbkNvbnRlbnQge1xuICBzdWJqZWN0OiBzdHJpbmc7XG4gIHRleHQ6IHN0cmluZztcbn1cblxuLyoqXG4gKiBOMjMg4oCUIHNvbWVvbmUgd2FzIGFkZGVkIHRvIG9yIHJlbW92ZWQgZnJvbSB0aGUgc3lzdGVtIG9yZydzIEVjb3N5c3RlbVxuICogTWFuYWdlciByb2xlLiBTZW50IHRvIGV2ZXJ5IHN1cGVyYWRtaW4gYW5kIHRvIHRoZSBhZmZlY3RlZCB1c2VyO1xuICogdHJhbnNhY3Rpb25hbCAobm8gb3B0LW91dCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZW5kZXJFY29zeXN0ZW1NYW5hZ2VyQ2hhbmdlKGlucHV0OiB7XG4gIC8qKiBUaGUgYWZmZWN0ZWQgdXNlcidzIGRpc3BsYXkgbmFtZSBvciBlbWFpbC4gKi9cbiAgdXNlcjogc3RyaW5nO1xuICBhZGRlZDogYm9vbGVhbjtcbiAgLyoqIFdobyBtYWRlIHRoZSBjaGFuZ2UgKHN1cGVyYWRtaW5zIG9ubHkgY2FuKSwgd2hlbiBrbm93bi4gKi9cbiAgYWN0b3I/OiBzdHJpbmc7XG59KTogRWNvc3lzdGVtTm90aWZpY2F0aW9uQ29udGVudCB7XG4gIGNvbnN0IHZlcmIgPSBpbnB1dC5hZGRlZCA/ICdhZGRlZCB0bycgOiAncmVtb3ZlZCBmcm9tJztcbiAgY29uc3QgYnkgPSBpbnB1dC5hY3RvciA/IGAgYnkgJHtpbnB1dC5hY3Rvcn1gIDogJyc7XG4gIHJldHVybiB7XG4gICAgc3ViamVjdDogYCR7aW5wdXQudXNlcn0gd2FzICR7dmVyYn0gdGhlIEVjb3N5c3RlbSBNYW5hZ2VyIHJvbGVgLFxuICAgIHRleHQ6IGlucHV0LmFkZGVkXG4gICAgICA/IGAke2lucHV0LnVzZXJ9IHdhcyAke3ZlcmJ9IHRoZSBFY29zeXN0ZW0gTWFuYWdlciByb2xlJHtieX0uIEVjb3N5c3RlbSBNYW5hZ2VycyBkZWNpZGUgcHVibGlzaCByZXF1ZXN0cywgYFxuICAgICAgICArICdtb2RlcmF0ZSBzdWJtaXNzaW9ucyBhbmQgcmV2aWV3cywgdmVyaWZ5IHB1Ymxpc2hlcnMgYW5kIHB1Ymxpc2ggYWR2aXNvcmllcyBmb3IgdGhlIHdob2xlIHBsdWdpbiBlY29zeXN0ZW0uICdcbiAgICAgICAgKyAnVGhlIHJvbGUgd29ya3Mgb25seSBmcm9tIHRoZSBzeXN0ZW0gb3JnYW5pemF0aW9uIGFuZCByZXF1aXJlcyBhIHR3by1mYWN0b3Igc2lnbi1pbi4nXG4gICAgICA6IGAke2lucHV0LnVzZXJ9IHdhcyAke3ZlcmJ9IHRoZSBFY29zeXN0ZW0gTWFuYWdlciByb2xlJHtieX0gYW5kIGNhbiBubyBsb25nZXIgbWFuYWdlIG9yIGFwcHJvdmUgYW55dGhpbmcgaW4gdGhlIHBsdWdpbiBlY29zeXN0ZW0uYCxcbiAgfTtcbn1cblxuLyoqXG4gKiBDb2FsZXNjZSBzZXZlcmFsIHF1ZXVlZCBub3RpY2VzIGludG8gb25lIGRpZ2VzdCBlbWFpbDogYSBjb3VudC1iZWFyaW5nXG4gKiBzdWJqZWN0IGFuZCBvbmUgbGluZSBwZXIgaXRlbSAoZWFjaCBpdGVtJ3Mgc3ViamVjdCksIG9sZGVzdCBmaXJzdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlckVjb3N5c3RlbURpZ2VzdChcbiAgZXZlbnQ6IEVjb3N5c3RlbU5vdGlmaWNhdGlvbkV2ZW50SWQsXG4gIGl0ZW1zOiByZWFkb25seSBFY29zeXN0ZW1Ob3RpZmljYXRpb25Db250ZW50W10sXG4pOiBFY29zeXN0ZW1Ob3RpZmljYXRpb25Db250ZW50IHtcbiAgaWYgKGl0ZW1zLmxlbmd0aCA9PT0gMSkgcmV0dXJuIGl0ZW1zWzBdITtcbiAgY29uc3Qgc3BlYyA9IEVDT1NZU1RFTV9OT1RJRklDQVRJT05fRVZFTlRTW2V2ZW50XTtcbiAgY29uc3QgY2FkZW5jZSA9IHNwZWMuZGlnZXN0ID09PSAnaG91cmx5JyA/ICdIb3VybHknIDogc3BlYy5kaWdlc3QgPT09ICd3ZWVrbHknID8gJ1dlZWtseScgOiAnRGFpbHknO1xuICByZXR1cm4ge1xuICAgIHN1YmplY3Q6IGAke2NhZGVuY2V9IGRpZ2VzdDogJHtpdGVtcy5sZW5ndGh9IMOXICR7c3BlYy5kZXNjcmlwdGlvbn1gLnNsaWNlKDAsIEVDT1NZU1RFTV9OT1RJRllfU1VCSkVDVF9NQVgpLFxuICAgIHRleHQ6IGl0ZW1zLm1hcCgoaSkgPT4gYOKAoiAke2kuc3ViamVjdH1gKS5qb2luKCdcXG4nKS5zbGljZSgwLCBFQ09TWVNURU1fTk9USUZZX1RFWFRfTUFYKSxcbiAgfTtcbn1cbiJdfQ==
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The name of the system-org SERVICE ACCOUNT the Official catalog loader
3
+ * (`deploy/bin/load-plugins.sh`, driven by `init-platform.sh`) runs as. Only a
4
+ * request submitted by this identity, from the system org, can ride the
5
+ * bootstrap exception or the Official catalog auto-approval rule —
6
+ * never a person, which keeps "a superadmin uploads and approves alone" closed.
7
+ * Service-account names are unique per org and only system-org admins
8
+ * can create one there.
9
+ */
10
+ export declare const OFFICIAL_CATALOG_LOADER_ACCOUNT = "official-catalog-loader";
11
+ /** The publisher terms version in force when the operator sets none. Bumping it
12
+ * (`PUBLISHER_TERMS_VERSION`) makes every publisher re-accept before its next
13
+ * request; existing listings are unaffected. */
14
+ export declare const DEFAULT_PUBLISHER_TERMS_VERSION = "2026-09-21";
15
+ /** The publisher terms version in force on this instance. */
16
+ export declare function publisherTermsVersion(): string;
17
+ /**
18
+ * A publisher handle: one lowercase registry path component, because it names
19
+ * the `public/<handle>/<name>` repository — letters, digits and single
20
+ * hyphens between them, 2–39 characters.
21
+ */
22
+ export declare const PUBLISHER_HANDLE_PATTERN: RegExp;
23
+ export declare const PUBLISHER_HANDLE_MIN = 2;
24
+ export declare const PUBLISHER_HANDLE_MAX = 39;
25
+ /** Why `handle` isn't a valid publisher handle, or null when it is. */
26
+ export declare function publisherHandleProblem(handle: string): string | null;
27
+ /**
28
+ * Handles no tenant may claim directly, on top of the system org's
29
+ * `ecosystem_reserved_names` table: the platform's own publishers, words that
30
+ * would read as an endorsement, and infrastructure names. A reserved handle can
31
+ * still be requested through a `claim` request, decided by the system org.
32
+ */
33
+ export declare const BUILTIN_RESERVED_HANDLES: readonly string[];
34
+ /**
35
+ * Request kinds a TENANT may submit (`moderation` is system-org-created). An
36
+ * `advisory` request carries a security-advisory DRAFT; only the system org
37
+ * publishes it (approving the request) or withdraws it.
38
+ */
39
+ export declare const TENANT_REQUEST_KINDS: readonly ['new_listing', 'new_version', 'listing_update', 'yank', 'unpause', 'transfer', 'claim', 'profile_change', 'verify', 'advisory'];
40
+ export type TenantRequestKind = (typeof TENANT_REQUEST_KINDS)[number];
41
+ /** Kinds submitted under `plugins:publish` (the rest need `publishers:manage`). */
42
+ export declare const PUBLISH_PERMISSION_REQUEST_KINDS: readonly string[];
43
+ /** Kinds DECIDED with `publishers:verify` (the rest need `plugins:moderate`). */
44
+ export declare const VERIFY_REQUEST_KINDS: readonly string[];
45
+ /** Kinds whose decision requires a step-up (suspend/yank/takedown, and every `publishers:verify` decision). */
46
+ export declare const STEP_UP_REQUEST_KINDS: readonly string[];
47
+ /** Moderation-queue SLA per lane, in hours (2 business days ≈ 48 h; security lane 4 h). */
48
+ export declare const REQUEST_SLA_HOURS: {
49
+ readonly standard: 48;
50
+ readonly security: 4;
51
+ };
52
+ /**
53
+ * `OFFICIAL_AUTO_APPROVAL_ENABLED` (default ON): when off, the seeded
54
+ * Official catalog auto-approval rule never fires and every Official update
55
+ * waits for two-person approval.
56
+ */
57
+ export declare function isOfficialAutoApprovalEnabled(): boolean;
58
+ /**
59
+ * `PLUGIN_PUBLISHING_ENABLED`: whether TENANT orgs may submit publish
60
+ * requests. Defaults on for the hosted instance (billing on) and off for a
61
+ * self-hosted one (billing off). The system org's Official catalog is never
62
+ * affected — it is the instance's own catalog.
63
+ */
64
+ export declare function isPluginPublishingEnabled(): boolean;
65
+ /**
66
+ * `ANONYMOUS_SUBMISSIONS_ENABLED` (default OFF): whether the
67
+ * not-logged-in plugin submission API is served. Even when on, submissions
68
+ * stay unavailable while outbound email is not configured (the magic link is
69
+ * the submitter's only verification) — the plugin service checks that too.
70
+ */
71
+ export declare function isAnonymousSubmissionsEnabled(): boolean;
72
+ /**
73
+ * `PLUGIN_REVIEWS_ENABLED` (default ON): when off, reviews are READ-ONLY —
74
+ * writing, editing, voting, reporting and replying answer
75
+ * `PLUGIN_REVIEWS_DISABLED`; moderation keeps working.
76
+ */
77
+ export declare function isPluginReviewsEnabled(): boolean;
@@ -0,0 +1,119 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Plugin-ecosystem constants shared by the plugin service (publishers, the
5
+ * publish-request queue, auto-approval) and its callers
6
+ * (docs/plugin-publishing.md). Dependency-free so
7
+ * the frontend and the CLI can import it too.
8
+ */
9
+ import { isBillingEnabled } from './quota-tiers.js';
10
+ /**
11
+ * The name of the system-org SERVICE ACCOUNT the Official catalog loader
12
+ * (`deploy/bin/load-plugins.sh`, driven by `init-platform.sh`) runs as. Only a
13
+ * request submitted by this identity, from the system org, can ride the
14
+ * bootstrap exception or the Official catalog auto-approval rule —
15
+ * never a person, which keeps "a superadmin uploads and approves alone" closed.
16
+ * Service-account names are unique per org and only system-org admins
17
+ * can create one there.
18
+ */
19
+ export const OFFICIAL_CATALOG_LOADER_ACCOUNT = 'official-catalog-loader';
20
+ /** The publisher terms version in force when the operator sets none. Bumping it
21
+ * (`PUBLISHER_TERMS_VERSION`) makes every publisher re-accept before its next
22
+ * request; existing listings are unaffected. */
23
+ export const DEFAULT_PUBLISHER_TERMS_VERSION = '2026-09-21';
24
+ /** The publisher terms version in force on this instance. */
25
+ export function publisherTermsVersion() {
26
+ const v = (process.env.PUBLISHER_TERMS_VERSION ?? '').trim();
27
+ return v !== '' ? v.slice(0, 50) : DEFAULT_PUBLISHER_TERMS_VERSION;
28
+ }
29
+ /**
30
+ * A publisher handle: one lowercase registry path component, because it names
31
+ * the `public/<handle>/<name>` repository — letters, digits and single
32
+ * hyphens between them, 2–39 characters.
33
+ */
34
+ export const PUBLISHER_HANDLE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
35
+ export const PUBLISHER_HANDLE_MIN = 2;
36
+ export const PUBLISHER_HANDLE_MAX = 39;
37
+ /** Why `handle` isn't a valid publisher handle, or null when it is. */
38
+ export function publisherHandleProblem(handle) {
39
+ if (handle.length < PUBLISHER_HANDLE_MIN || handle.length > PUBLISHER_HANDLE_MAX) {
40
+ return `must be ${PUBLISHER_HANDLE_MIN}-${PUBLISHER_HANDLE_MAX} characters`;
41
+ }
42
+ if (!PUBLISHER_HANDLE_PATTERN.test(handle)) {
43
+ return 'must be lowercase letters and digits, optionally separated by single hyphens';
44
+ }
45
+ return null;
46
+ }
47
+ /**
48
+ * Handles no tenant may claim directly, on top of the system org's
49
+ * `ecosystem_reserved_names` table: the platform's own publishers, words that
50
+ * would read as an endorsement, and infrastructure names. A reserved handle can
51
+ * still be requested through a `claim` request, decided by the system org.
52
+ */
53
+ export const BUILTIN_RESERVED_HANDLES = [
54
+ 'pipeline-builder', 'community', 'official', 'verified', 'system', 'admin', 'administrator',
55
+ 'root', 'support', 'security', 'staff', 'moderator', 'ecosystem', 'public', 'library',
56
+ 'anonymous', 'unverified', 'platform', 'registry', 'plugins', 'plugin', 'api', 'www',
57
+ // Static segments of the public directory's `/plugins/<publisher>/<name>` URL space.
58
+ 'submit', 'category',
59
+ ];
60
+ /**
61
+ * Request kinds a TENANT may submit (`moderation` is system-org-created). An
62
+ * `advisory` request carries a security-advisory DRAFT; only the system org
63
+ * publishes it (approving the request) or withdraws it.
64
+ */
65
+ export const TENANT_REQUEST_KINDS = [
66
+ 'new_listing', 'new_version', 'listing_update', 'yank', 'unpause',
67
+ 'transfer', 'claim', 'profile_change', 'verify', 'advisory',
68
+ ];
69
+ /** Kinds submitted under `plugins:publish` (the rest need `publishers:manage`). */
70
+ export const PUBLISH_PERMISSION_REQUEST_KINDS = [
71
+ 'new_listing', 'new_version', 'listing_update', 'yank', 'unpause',
72
+ ];
73
+ /** Kinds DECIDED with `publishers:verify` (the rest need `plugins:moderate`). */
74
+ export const VERIFY_REQUEST_KINDS = ['transfer', 'claim', 'profile_change', 'verify'];
75
+ /** Kinds whose decision requires a step-up (suspend/yank/takedown, and every `publishers:verify` decision). */
76
+ export const STEP_UP_REQUEST_KINDS = ['yank', 'transfer', 'claim', 'profile_change', 'verify', 'moderation'];
77
+ /** Moderation-queue SLA per lane, in hours (2 business days ≈ 48 h; security lane 4 h). */
78
+ export const REQUEST_SLA_HOURS = { standard: 48, security: 4 };
79
+ function flag(name, dflt) {
80
+ const raw = (process.env[name] ?? '').trim().toLowerCase();
81
+ if (raw === '')
82
+ return dflt;
83
+ return raw !== 'false' && raw !== '0' && raw !== 'off' && raw !== 'no';
84
+ }
85
+ /**
86
+ * `OFFICIAL_AUTO_APPROVAL_ENABLED` (default ON): when off, the seeded
87
+ * Official catalog auto-approval rule never fires and every Official update
88
+ * waits for two-person approval.
89
+ */
90
+ export function isOfficialAutoApprovalEnabled() {
91
+ return flag('OFFICIAL_AUTO_APPROVAL_ENABLED', true);
92
+ }
93
+ /**
94
+ * `PLUGIN_PUBLISHING_ENABLED`: whether TENANT orgs may submit publish
95
+ * requests. Defaults on for the hosted instance (billing on) and off for a
96
+ * self-hosted one (billing off). The system org's Official catalog is never
97
+ * affected — it is the instance's own catalog.
98
+ */
99
+ export function isPluginPublishingEnabled() {
100
+ return flag('PLUGIN_PUBLISHING_ENABLED', isBillingEnabled());
101
+ }
102
+ /**
103
+ * `ANONYMOUS_SUBMISSIONS_ENABLED` (default OFF): whether the
104
+ * not-logged-in plugin submission API is served. Even when on, submissions
105
+ * stay unavailable while outbound email is not configured (the magic link is
106
+ * the submitter's only verification) — the plugin service checks that too.
107
+ */
108
+ export function isAnonymousSubmissionsEnabled() {
109
+ return flag('ANONYMOUS_SUBMISSIONS_ENABLED', false);
110
+ }
111
+ /**
112
+ * `PLUGIN_REVIEWS_ENABLED` (default ON): when off, reviews are READ-ONLY —
113
+ * writing, editing, voting, reporting and replying answer
114
+ * `PLUGIN_REVIEWS_DISABLED`; moderation keeps working.
115
+ */
116
+ export function isPluginReviewsEnabled() {
117
+ return flag('PLUGIN_REVIEWS_ENABLED', true);
118
+ }
119
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNvc3lzdGVtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3R5cGVzL2Vjb3N5c3RlbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFcEQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBRyx5QkFBeUIsQ0FBQztBQUV6RTs7aURBRWlEO0FBQ2pELE1BQU0sQ0FBQyxNQUFNLCtCQUErQixHQUFHLFlBQVksQ0FBQztBQUU1RCw2REFBNkQ7QUFDN0QsTUFBTSxVQUFVLHFCQUFxQjtJQUNuQyxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDN0QsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsK0JBQStCLENBQUM7QUFDckUsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyw0QkFBNEIsQ0FBQztBQUNyRSxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLENBQUM7QUFDdEMsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsRUFBRSxDQUFDO0FBRXZDLHVFQUF1RTtBQUN2RSxNQUFNLFVBQVUsc0JBQXNCLENBQUMsTUFBYztJQUNuRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsb0JBQW9CLElBQUksTUFBTSxDQUFDLE1BQU0sR0FBRyxvQkFBb0IsRUFBRSxDQUFDO1FBQ2pGLE9BQU8sV0FBVyxvQkFBb0IsSUFBSSxvQkFBb0IsYUFBYSxDQUFDO0lBQzlFLENBQUM7SUFDRCxJQUFJLENBQUMsd0JBQXdCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDM0MsT0FBTyw4RUFBOEUsQ0FBQztJQUN4RixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBc0I7SUFDekQsa0JBQWtCLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxlQUFlO0lBQzNGLE1BQU0sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxTQUFTO0lBQ3JGLFdBQVcsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxLQUFLO0lBQ3BGLHFGQUFxRjtJQUNyRixRQUFRLEVBQUUsVUFBVTtDQUNyQixDQUFDO0FBRUY7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHO0lBQ2xDLGFBQWEsRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxFQUFFLFNBQVM7SUFDakUsVUFBVSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxRQUFRLEVBQUUsVUFBVTtDQUNuRCxDQUFDO0FBR1gsbUZBQW1GO0FBQ25GLE1BQU0sQ0FBQyxNQUFNLGdDQUFnQyxHQUFzQjtJQUNqRSxhQUFhLEVBQUUsYUFBYSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxTQUFTO0NBQ2xFLENBQUM7QUFFRixpRkFBaUY7QUFDakYsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQXNCLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxRQUFRLENBQUMsQ0FBQztBQUV6RywrR0FBK0c7QUFDL0csTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQXNCLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsUUFBUSxFQUFFLFlBQVksQ0FBQyxDQUFDO0FBRWhJLDJGQUEyRjtBQUMzRixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBVyxDQUFDO0FBRXhFLFNBQVMsSUFBSSxDQUFDLElBQVksRUFBRSxJQUFhO0lBQ3ZDLE1BQU0sR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUMzRCxJQUFJLEdBQUcsS0FBSyxFQUFFO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDNUIsT0FBTyxHQUFHLEtBQUssT0FBTyxJQUFJLEdBQUcsS0FBSyxHQUFHLElBQUksR0FBRyxLQUFLLEtBQUssSUFBSSxHQUFHLEtBQUssSUFBSSxDQUFDO0FBQ3pFLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLDZCQUE2QjtJQUMzQyxPQUFPLElBQUksQ0FBQyxnQ0FBZ0MsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUN0RCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUseUJBQXlCO0lBQ3ZDLE9BQU8sSUFBSSxDQUFDLDJCQUEyQixFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztBQUMvRCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsNkJBQTZCO0lBQzNDLE9BQU8sSUFBSSxDQUFDLCtCQUErQixFQUFFLEtBQUssQ0FBQyxDQUFDO0FBQ3RELENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQjtJQUNwQyxPQUFPLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUM5QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogUGx1Z2luLWVjb3N5c3RlbSBjb25zdGFudHMgc2hhcmVkIGJ5IHRoZSBwbHVnaW4gc2VydmljZSAocHVibGlzaGVycywgdGhlXG4gKiBwdWJsaXNoLXJlcXVlc3QgcXVldWUsIGF1dG8tYXBwcm92YWwpIGFuZCBpdHMgY2FsbGVyc1xuICogKGRvY3MvcGx1Z2luLXB1Ymxpc2hpbmcubWQpLiBEZXBlbmRlbmN5LWZyZWUgc29cbiAqIHRoZSBmcm9udGVuZCBhbmQgdGhlIENMSSBjYW4gaW1wb3J0IGl0IHRvby5cbiAqL1xuXG5pbXBvcnQgeyBpc0JpbGxpbmdFbmFibGVkIH0gZnJvbSAnLi9xdW90YS10aWVycy5qcyc7XG5cbi8qKlxuICogVGhlIG5hbWUgb2YgdGhlIHN5c3RlbS1vcmcgU0VSVklDRSBBQ0NPVU5UIHRoZSBPZmZpY2lhbCBjYXRhbG9nIGxvYWRlclxuICogKGBkZXBsb3kvYmluL2xvYWQtcGx1Z2lucy5zaGAsIGRyaXZlbiBieSBgaW5pdC1wbGF0Zm9ybS5zaGApIHJ1bnMgYXMuIE9ubHkgYVxuICogcmVxdWVzdCBzdWJtaXR0ZWQgYnkgdGhpcyBpZGVudGl0eSwgZnJvbSB0aGUgc3lzdGVtIG9yZywgY2FuIHJpZGUgdGhlXG4gKiBib290c3RyYXAgZXhjZXB0aW9uIG9yIHRoZSBPZmZpY2lhbCBjYXRhbG9nIGF1dG8tYXBwcm92YWwgcnVsZSDigJRcbiAqIG5ldmVyIGEgcGVyc29uLCB3aGljaCBrZWVwcyBcImEgc3VwZXJhZG1pbiB1cGxvYWRzIGFuZCBhcHByb3ZlcyBhbG9uZVwiIGNsb3NlZC5cbiAqIFNlcnZpY2UtYWNjb3VudCBuYW1lcyBhcmUgdW5pcXVlIHBlciBvcmcgYW5kIG9ubHkgc3lzdGVtLW9yZyBhZG1pbnNcbiAqIGNhbiBjcmVhdGUgb25lIHRoZXJlLlxuICovXG5leHBvcnQgY29uc3QgT0ZGSUNJQUxfQ0FUQUxPR19MT0FERVJfQUNDT1VOVCA9ICdvZmZpY2lhbC1jYXRhbG9nLWxvYWRlcic7XG5cbi8qKiBUaGUgcHVibGlzaGVyIHRlcm1zIHZlcnNpb24gaW4gZm9yY2Ugd2hlbiB0aGUgb3BlcmF0b3Igc2V0cyBub25lLiBCdW1waW5nIGl0XG4gKiAgKGBQVUJMSVNIRVJfVEVSTVNfVkVSU0lPTmApIG1ha2VzIGV2ZXJ5IHB1Ymxpc2hlciByZS1hY2NlcHQgYmVmb3JlIGl0cyBuZXh0XG4gKiAgcmVxdWVzdDsgZXhpc3RpbmcgbGlzdGluZ3MgYXJlIHVuYWZmZWN0ZWQuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9QVUJMSVNIRVJfVEVSTVNfVkVSU0lPTiA9ICcyMDI2LTA5LTIxJztcblxuLyoqIFRoZSBwdWJsaXNoZXIgdGVybXMgdmVyc2lvbiBpbiBmb3JjZSBvbiB0aGlzIGluc3RhbmNlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHB1Ymxpc2hlclRlcm1zVmVyc2lvbigpOiBzdHJpbmcge1xuICBjb25zdCB2ID0gKHByb2Nlc3MuZW52LlBVQkxJU0hFUl9URVJNU19WRVJTSU9OID8/ICcnKS50cmltKCk7XG4gIHJldHVybiB2ICE9PSAnJyA/IHYuc2xpY2UoMCwgNTApIDogREVGQVVMVF9QVUJMSVNIRVJfVEVSTVNfVkVSU0lPTjtcbn1cblxuLyoqXG4gKiBBIHB1Ymxpc2hlciBoYW5kbGU6IG9uZSBsb3dlcmNhc2UgcmVnaXN0cnkgcGF0aCBjb21wb25lbnQsIGJlY2F1c2UgaXQgbmFtZXNcbiAqIHRoZSBgcHVibGljLzxoYW5kbGU+LzxuYW1lPmAgcmVwb3NpdG9yeSDigJQgbGV0dGVycywgZGlnaXRzIGFuZCBzaW5nbGVcbiAqIGh5cGhlbnMgYmV0d2VlbiB0aGVtLCAy4oCTMzkgY2hhcmFjdGVycy5cbiAqL1xuZXhwb3J0IGNvbnN0IFBVQkxJU0hFUl9IQU5ETEVfUEFUVEVSTiA9IC9eW2EtejAtOV0rKD86LVthLXowLTldKykqJC87XG5leHBvcnQgY29uc3QgUFVCTElTSEVSX0hBTkRMRV9NSU4gPSAyO1xuZXhwb3J0IGNvbnN0IFBVQkxJU0hFUl9IQU5ETEVfTUFYID0gMzk7XG5cbi8qKiBXaHkgYGhhbmRsZWAgaXNuJ3QgYSB2YWxpZCBwdWJsaXNoZXIgaGFuZGxlLCBvciBudWxsIHdoZW4gaXQgaXMuICovXG5leHBvcnQgZnVuY3Rpb24gcHVibGlzaGVySGFuZGxlUHJvYmxlbShoYW5kbGU6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBpZiAoaGFuZGxlLmxlbmd0aCA8IFBVQkxJU0hFUl9IQU5ETEVfTUlOIHx8IGhhbmRsZS5sZW5ndGggPiBQVUJMSVNIRVJfSEFORExFX01BWCkge1xuICAgIHJldHVybiBgbXVzdCBiZSAke1BVQkxJU0hFUl9IQU5ETEVfTUlOfS0ke1BVQkxJU0hFUl9IQU5ETEVfTUFYfSBjaGFyYWN0ZXJzYDtcbiAgfVxuICBpZiAoIVBVQkxJU0hFUl9IQU5ETEVfUEFUVEVSTi50ZXN0KGhhbmRsZSkpIHtcbiAgICByZXR1cm4gJ211c3QgYmUgbG93ZXJjYXNlIGxldHRlcnMgYW5kIGRpZ2l0cywgb3B0aW9uYWxseSBzZXBhcmF0ZWQgYnkgc2luZ2xlIGh5cGhlbnMnO1xuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIEhhbmRsZXMgbm8gdGVuYW50IG1heSBjbGFpbSBkaXJlY3RseSwgb24gdG9wIG9mIHRoZSBzeXN0ZW0gb3JnJ3NcbiAqIGBlY29zeXN0ZW1fcmVzZXJ2ZWRfbmFtZXNgIHRhYmxlOiB0aGUgcGxhdGZvcm0ncyBvd24gcHVibGlzaGVycywgd29yZHMgdGhhdFxuICogd291bGQgcmVhZCBhcyBhbiBlbmRvcnNlbWVudCwgYW5kIGluZnJhc3RydWN0dXJlIG5hbWVzLiBBIHJlc2VydmVkIGhhbmRsZSBjYW5cbiAqIHN0aWxsIGJlIHJlcXVlc3RlZCB0aHJvdWdoIGEgYGNsYWltYCByZXF1ZXN0LCBkZWNpZGVkIGJ5IHRoZSBzeXN0ZW0gb3JnLlxuICovXG5leHBvcnQgY29uc3QgQlVJTFRJTl9SRVNFUlZFRF9IQU5ETEVTOiByZWFkb25seSBzdHJpbmdbXSA9IFtcbiAgJ3BpcGVsaW5lLWJ1aWxkZXInLCAnY29tbXVuaXR5JywgJ29mZmljaWFsJywgJ3ZlcmlmaWVkJywgJ3N5c3RlbScsICdhZG1pbicsICdhZG1pbmlzdHJhdG9yJyxcbiAgJ3Jvb3QnLCAnc3VwcG9ydCcsICdzZWN1cml0eScsICdzdGFmZicsICdtb2RlcmF0b3InLCAnZWNvc3lzdGVtJywgJ3B1YmxpYycsICdsaWJyYXJ5JyxcbiAgJ2Fub255bW91cycsICd1bnZlcmlmaWVkJywgJ3BsYXRmb3JtJywgJ3JlZ2lzdHJ5JywgJ3BsdWdpbnMnLCAncGx1Z2luJywgJ2FwaScsICd3d3cnLFxuICAvLyBTdGF0aWMgc2VnbWVudHMgb2YgdGhlIHB1YmxpYyBkaXJlY3RvcnkncyBgL3BsdWdpbnMvPHB1Ymxpc2hlcj4vPG5hbWU+YCBVUkwgc3BhY2UuXG4gICdzdWJtaXQnLCAnY2F0ZWdvcnknLFxuXTtcblxuLyoqXG4gKiBSZXF1ZXN0IGtpbmRzIGEgVEVOQU5UIG1heSBzdWJtaXQgKGBtb2RlcmF0aW9uYCBpcyBzeXN0ZW0tb3JnLWNyZWF0ZWQpLiBBblxuICogYGFkdmlzb3J5YCByZXF1ZXN0IGNhcnJpZXMgYSBzZWN1cml0eS1hZHZpc29yeSBEUkFGVDsgb25seSB0aGUgc3lzdGVtIG9yZ1xuICogcHVibGlzaGVzIGl0IChhcHByb3ZpbmcgdGhlIHJlcXVlc3QpIG9yIHdpdGhkcmF3cyBpdC5cbiAqL1xuZXhwb3J0IGNvbnN0IFRFTkFOVF9SRVFVRVNUX0tJTkRTID0gW1xuICAnbmV3X2xpc3RpbmcnLCAnbmV3X3ZlcnNpb24nLCAnbGlzdGluZ191cGRhdGUnLCAneWFuaycsICd1bnBhdXNlJyxcbiAgJ3RyYW5zZmVyJywgJ2NsYWltJywgJ3Byb2ZpbGVfY2hhbmdlJywgJ3ZlcmlmeScsICdhZHZpc29yeScsXG5dIGFzIGNvbnN0O1xuZXhwb3J0IHR5cGUgVGVuYW50UmVxdWVzdEtpbmQgPSAodHlwZW9mIFRFTkFOVF9SRVFVRVNUX0tJTkRTKVtudW1iZXJdO1xuXG4vKiogS2luZHMgc3VibWl0dGVkIHVuZGVyIGBwbHVnaW5zOnB1Ymxpc2hgICh0aGUgcmVzdCBuZWVkIGBwdWJsaXNoZXJzOm1hbmFnZWApLiAqL1xuZXhwb3J0IGNvbnN0IFBVQkxJU0hfUEVSTUlTU0lPTl9SRVFVRVNUX0tJTkRTOiByZWFkb25seSBzdHJpbmdbXSA9IFtcbiAgJ25ld19saXN0aW5nJywgJ25ld192ZXJzaW9uJywgJ2xpc3RpbmdfdXBkYXRlJywgJ3lhbmsnLCAndW5wYXVzZScsXG5dO1xuXG4vKiogS2luZHMgREVDSURFRCB3aXRoIGBwdWJsaXNoZXJzOnZlcmlmeWAgKHRoZSByZXN0IG5lZWQgYHBsdWdpbnM6bW9kZXJhdGVgKS4gKi9cbmV4cG9ydCBjb25zdCBWRVJJRllfUkVRVUVTVF9LSU5EUzogcmVhZG9ubHkgc3RyaW5nW10gPSBbJ3RyYW5zZmVyJywgJ2NsYWltJywgJ3Byb2ZpbGVfY2hhbmdlJywgJ3ZlcmlmeSddO1xuXG4vKiogS2luZHMgd2hvc2UgZGVjaXNpb24gcmVxdWlyZXMgYSBzdGVwLXVwIChzdXNwZW5kL3lhbmsvdGFrZWRvd24sIGFuZCBldmVyeSBgcHVibGlzaGVyczp2ZXJpZnlgIGRlY2lzaW9uKS4gKi9cbmV4cG9ydCBjb25zdCBTVEVQX1VQX1JFUVVFU1RfS0lORFM6IHJlYWRvbmx5IHN0cmluZ1tdID0gWyd5YW5rJywgJ3RyYW5zZmVyJywgJ2NsYWltJywgJ3Byb2ZpbGVfY2hhbmdlJywgJ3ZlcmlmeScsICdtb2RlcmF0aW9uJ107XG5cbi8qKiBNb2RlcmF0aW9uLXF1ZXVlIFNMQSBwZXIgbGFuZSwgaW4gaG91cnMgKDIgYnVzaW5lc3MgZGF5cyDiiYggNDggaDsgc2VjdXJpdHkgbGFuZSA0IGgpLiAqL1xuZXhwb3J0IGNvbnN0IFJFUVVFU1RfU0xBX0hPVVJTID0geyBzdGFuZGFyZDogNDgsIHNlY3VyaXR5OiA0IH0gYXMgY29uc3Q7XG5cbmZ1bmN0aW9uIGZsYWcobmFtZTogc3RyaW5nLCBkZmx0OiBib29sZWFuKTogYm9vbGVhbiB7XG4gIGNvbnN0IHJhdyA9IChwcm9jZXNzLmVudltuYW1lXSA/PyAnJykudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gIGlmIChyYXcgPT09ICcnKSByZXR1cm4gZGZsdDtcbiAgcmV0dXJuIHJhdyAhPT0gJ2ZhbHNlJyAmJiByYXcgIT09ICcwJyAmJiByYXcgIT09ICdvZmYnICYmIHJhdyAhPT0gJ25vJztcbn1cblxuLyoqXG4gKiBgT0ZGSUNJQUxfQVVUT19BUFBST1ZBTF9FTkFCTEVEYCAoZGVmYXVsdCBPTik6IHdoZW4gb2ZmLCB0aGUgc2VlZGVkXG4gKiBPZmZpY2lhbCBjYXRhbG9nIGF1dG8tYXBwcm92YWwgcnVsZSBuZXZlciBmaXJlcyBhbmQgZXZlcnkgT2ZmaWNpYWwgdXBkYXRlXG4gKiB3YWl0cyBmb3IgdHdvLXBlcnNvbiBhcHByb3ZhbC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzT2ZmaWNpYWxBdXRvQXBwcm92YWxFbmFibGVkKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gZmxhZygnT0ZGSUNJQUxfQVVUT19BUFBST1ZBTF9FTkFCTEVEJywgdHJ1ZSk7XG59XG5cbi8qKlxuICogYFBMVUdJTl9QVUJMSVNISU5HX0VOQUJMRURgOiB3aGV0aGVyIFRFTkFOVCBvcmdzIG1heSBzdWJtaXQgcHVibGlzaFxuICogcmVxdWVzdHMuIERlZmF1bHRzIG9uIGZvciB0aGUgaG9zdGVkIGluc3RhbmNlIChiaWxsaW5nIG9uKSBhbmQgb2ZmIGZvciBhXG4gKiBzZWxmLWhvc3RlZCBvbmUgKGJpbGxpbmcgb2ZmKS4gVGhlIHN5c3RlbSBvcmcncyBPZmZpY2lhbCBjYXRhbG9nIGlzIG5ldmVyXG4gKiBhZmZlY3RlZCDigJQgaXQgaXMgdGhlIGluc3RhbmNlJ3Mgb3duIGNhdGFsb2cuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1BsdWdpblB1Ymxpc2hpbmdFbmFibGVkKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gZmxhZygnUExVR0lOX1BVQkxJU0hJTkdfRU5BQkxFRCcsIGlzQmlsbGluZ0VuYWJsZWQoKSk7XG59XG5cbi8qKlxuICogYEFOT05ZTU9VU19TVUJNSVNTSU9OU19FTkFCTEVEYCAoZGVmYXVsdCBPRkYpOiB3aGV0aGVyIHRoZVxuICogbm90LWxvZ2dlZC1pbiBwbHVnaW4gc3VibWlzc2lvbiBBUEkgaXMgc2VydmVkLiBFdmVuIHdoZW4gb24sIHN1Ym1pc3Npb25zXG4gKiBzdGF5IHVuYXZhaWxhYmxlIHdoaWxlIG91dGJvdW5kIGVtYWlsIGlzIG5vdCBjb25maWd1cmVkICh0aGUgbWFnaWMgbGluayBpc1xuICogdGhlIHN1Ym1pdHRlcidzIG9ubHkgdmVyaWZpY2F0aW9uKSDigJQgdGhlIHBsdWdpbiBzZXJ2aWNlIGNoZWNrcyB0aGF0IHRvby5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQW5vbnltb3VzU3VibWlzc2lvbnNFbmFibGVkKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gZmxhZygnQU5PTllNT1VTX1NVQk1JU1NJT05TX0VOQUJMRUQnLCBmYWxzZSk7XG59XG5cbi8qKlxuICogYFBMVUdJTl9SRVZJRVdTX0VOQUJMRURgIChkZWZhdWx0IE9OKTogd2hlbiBvZmYsIHJldmlld3MgYXJlIFJFQUQtT05MWSDigJRcbiAqIHdyaXRpbmcsIGVkaXRpbmcsIHZvdGluZywgcmVwb3J0aW5nIGFuZCByZXBseWluZyBhbnN3ZXJcbiAqIGBQTFVHSU5fUkVWSUVXU19ESVNBQkxFRGA7IG1vZGVyYXRpb24ga2VlcHMgd29ya2luZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUGx1Z2luUmV2aWV3c0VuYWJsZWQoKTogYm9vbGVhbiB7XG4gIHJldHVybiBmbGFnKCdQTFVHSU5fUkVWSUVXU19FTkFCTEVEJywgdHJ1ZSk7XG59XG4iXX0=
@@ -27,12 +27,46 @@ export declare enum ErrorCode {
27
27
  /** A bootstrap-admin enrolment session (`mfaEnrollmentPending`) reached a
28
28
  * route outside the enrolment / sign-out / setup allowlist. */
29
29
  MFA_ENROLLMENT_REQUIRED = "MFA_ENROLLMENT_REQUIRED",
30
+ /** A read-only impersonation token (`impersonationReadOnly`) attempted a
31
+ * state-changing request (anything but GET/HEAD/OPTIONS). */
32
+ IMPERSONATION_READ_ONLY = "IMPERSONATION_READ_ONLY",
33
+ /** A plugin-ecosystem governance route (docs/runbooks/ecosystem-moderation.md)
34
+ * was called from an active org other than the system org — a token minted in
35
+ * a tenant org is refused even for the same user. Switch to the system org. */
36
+ SYSTEM_ORG_REQUIRED = "SYSTEM_ORG_REQUIRED",
37
+ /** The publisher hasn't accepted the CURRENT publisher terms version, so it
38
+ * can't submit new requests (existing listings are unaffected). */
39
+ PUBLISHER_TERMS_REQUIRED = "PUBLISHER_TERMS_REQUIRED",
40
+ /** Publishing is done from the ROOT org; a team org can't own a publisher or
41
+ * submit requests. */
42
+ PUBLISHER_ROOT_ORG_REQUIRED = "PUBLISHER_ROOT_ORG_REQUIRED",
43
+ /** The publisher is suspended by the system org. */
44
+ PUBLISHER_SUSPENDED = "PUBLISHER_SUSPENDED",
45
+ /** Tenant publishing is switched off on this instance (`PLUGIN_PUBLISHING_ENABLED`). */
46
+ PLUGIN_PUBLISHING_DISABLED = "PLUGIN_PUBLISHING_DISABLED",
47
+ /** Review writes are switched off on this instance (`PLUGIN_REVIEWS_ENABLED`):
48
+ * reviews stay readable, nothing new is written. */
49
+ PLUGIN_REVIEWS_DISABLED = "PLUGIN_REVIEWS_DISABLED",
50
+ /** A member of the publisher's own organization tried to review (or vote on a
51
+ * review of) one of its listings (self-promotion). */
52
+ REVIEW_SELF_PROMOTION = "REVIEW_SELF_PROMOTION",
53
+ /** Separation of duties: the caller may not decide this request —
54
+ * it came from an org they belong to, they uploaded the version, or they
55
+ * gave the first of two approvals. */
56
+ SEPARATION_OF_DUTIES = "SEPARATION_OF_DUTIES",
30
57
  ORG_MISMATCH = "ORG_MISMATCH",
31
58
  COMPLIANCE_VIOLATION = "COMPLIANCE_VIOLATION",
32
59
  NOT_FOUND = "NOT_FOUND",
33
60
  ORG_NOT_FOUND = "ORG_NOT_FOUND",
61
+ /** The anonymous plugin submission API is off on this instance
62
+ * (`ANONYMOUS_SUBMISSIONS_ENABLED`, or outbound email isn't configured) —
63
+ * answered as a plain 404 (docs/plugin-publishing.md). */
64
+ SUBMISSIONS_DISABLED = "SUBMISSIONS_DISABLED",
34
65
  VALIDATION_ERROR = "VALIDATION_ERROR",
35
66
  MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD",
67
+ /** A proof-of-work answer is missing, malformed, expired, too easy, wrong,
68
+ * or was already used (anonymous submissions). */
69
+ PROOF_OF_WORK_INVALID = "PROOF_OF_WORK_INVALID",
36
70
  TEMPLATE_UNKNOWN_PATH = "TEMPLATE_UNKNOWN_PATH",
37
71
  TEMPLATE_CYCLE = "TEMPLATE_CYCLE",
38
72
  TEMPLATE_PARSE_ERROR = "TEMPLATE_PARSE_ERROR",
@@ -43,6 +77,9 @@ export declare enum ErrorCode {
43
77
  TEMPLATE_VALIDATION_FAILED = "TEMPLATE_VALIDATION_FAILED",
44
78
  QUOTA_EXCEEDED = "QUOTA_EXCEEDED",
45
79
  RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED",
80
+ /** An anonymous submitter (per verified email, or per client IP) is at the
81
+ * rolling 24-hour submission cap. */
82
+ SUBMISSION_LIMIT = "SUBMISSION_LIMIT",
46
83
  PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE",
47
84
  CONFLICT = "CONFLICT",
48
85
  DUPLICATE_ENTRY = "DUPLICATE_ENTRY",
@@ -51,6 +88,50 @@ export declare enum ErrorCode {
51
88
  * not verify against the platform's plugin-signing key — the registry
52
89
  * content no longer matches what the platform built and signed. */
53
90
  IMAGE_VERIFICATION_FAILED = "IMAGE_VERIFICATION_FAILED",
91
+ /** The plugin version is immutable — a publish request references it
92
+ * (`frozen_at` set) or it is published to a listing — so it can be neither
93
+ * re-uploaded, edited nor deleted (docs/plugin-publishing.md). */
94
+ PLUGIN_VERSION_FROZEN = "PLUGIN_VERSION_FROZEN",
95
+ /** The plugin version is referenced by one of the org's pipelines, or published
96
+ * to an ecosystem listing; deleting it needs `?force=true` plus a step-up. */
97
+ PLUGIN_VERSION_IN_USE = "PLUGIN_VERSION_IN_USE",
98
+ /** A freeze named an image digest that is not the version's stored digest
99
+ * (fail closed: what was requested is not what would be published). */
100
+ PLUGIN_DIGEST_MISMATCH = "PLUGIN_DIGEST_MISMATCH",
101
+ /** A publish request needs the org's publisher profile, which doesn't exist
102
+ * yet (docs/plugin-publishing.md). Claim a handle first. */
103
+ PUBLISHER_REQUIRED = "PUBLISHER_REQUIRED",
104
+ /** The requested publisher handle is reserved (Official/Verified
105
+ * reservations, confusables). Submit a `claim` request instead. */
106
+ PUBLISHER_HANDLE_RESERVED = "PUBLISHER_HANDLE_RESERVED",
107
+ /** A publish request failed a submit gate (public visibility, SPDX license,
108
+ * README, signature, scan, vulnerability gate …); `details.gates` lists them. */
109
+ PUBLISH_GATE_FAILED = "PUBLISH_GATE_FAILED",
110
+ /** A Verified-publisher application (or its decision) from an org whose plan
111
+ * lacks the `verified_publisher` feature (Team+, docs/plugin-publishing.md). */
112
+ VERIFIED_PLAN_REQUIRED = "VERIFIED_PLAN_REQUIRED",
113
+ /** A Verified-publisher application from an org with no DNS-verified domain. */
114
+ VERIFIED_DOMAIN_REQUIRED = "VERIFIED_DOMAIN_REQUIRED",
115
+ /** A Verified-publisher application from an org whose owner has no second
116
+ * factor (passkey or authenticator app). */
117
+ VERIFIED_OWNER_MFA_REQUIRED = "VERIFIED_OWNER_MFA_REQUIRED",
118
+ /** A plugin reference names an ecosystem listing the org hasn't installed (or
119
+ * whose install is pending, denied, or doesn't cover the version asked for;
120
+ * `details.reason`) — docs/plugin-publishing.md */
121
+ PLUGIN_NOT_INSTALLED = "PLUGIN_NOT_INSTALLED",
122
+ /** The org's consumption policy refuses the listing: its tier isn't allowed,
123
+ * the listing is blocked, or an advisory blocks the version (`details.reason`). */
124
+ PLUGIN_BLOCKED_BY_POLICY = "PLUGIN_BLOCKED_BY_POLICY",
125
+ /** The listing or version can't be used: yanked, suspended, or paused for new
126
+ * installs (`details.reason`). */
127
+ PLUGIN_UNAVAILABLE = "PLUGIN_UNAVAILABLE",
128
+ /** An auto-created placeholder plugin can't take the name of a listed plugin
129
+ * — install the listing instead. */
130
+ PLUGIN_NAME_LISTED = "PLUGIN_NAME_LISTED",
131
+ /** An anonymous submission names a community listing another submitter owns,
132
+ * a reserved name, an Official/Verified listing's name, or one confusable
133
+ * with a top listing; `details.reason` says which. */
134
+ NAME_TAKEN = "NAME_TAKEN",
54
135
  PAYMENT_METHOD_REQUIRED = "PAYMENT_METHOD_REQUIRED",// 402
55
136
  DISCOUNT_CEILING_EXCEEDED = "DISCOUNT_CEILING_EXCEEDED",// 400
56
137
  DISCOUNT_NOT_FOUND = "DISCOUNT_NOT_FOUND",// 404