@pipeline-builder/api-core 4.1.20 → 4.1.21
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.
- package/lib/helpers/access-helpers.d.ts +50 -2
- package/lib/helpers/access-helpers.js +44 -3
- package/lib/helpers/index.d.ts +1 -1
- package/lib/helpers/index.js +2 -2
- package/lib/middleware/ask-provenance.d.ts +53 -0
- package/lib/middleware/ask-provenance.js +26 -0
- package/lib/middleware/index.d.ts +1 -0
- package/lib/middleware/index.js +2 -1
- package/lib/services/http-client.d.ts +0 -1
- package/lib/services/http-client.js +5 -7
- package/lib/services/index.d.ts +2 -2
- package/lib/services/index.js +3 -3
- package/lib/services/remote-audit-client.d.ts +1 -15
- package/lib/services/remote-audit-client.js +2 -295
- package/lib/services/s3-client.d.ts +54 -0
- package/lib/services/s3-client.js +106 -0
- package/lib/types/ask-proposals.d.ts +269 -0
- package/lib/types/ask-proposals.js +308 -0
- package/lib/types/compliance-exemption.d.ts +24 -0
- package/lib/types/compliance-exemption.js +4 -0
- package/lib/types/index.d.ts +5 -2
- package/lib/types/index.js +5 -2
- package/lib/types/remote-audit-actions.d.ts +23 -0
- package/lib/types/remote-audit-actions.js +305 -0
- package/lib/utils/date.d.ts +19 -0
- package/lib/utils/date.js +22 -0
- package/lib/utils/dsse.d.ts +32 -0
- package/lib/utils/dsse.js +55 -0
- package/lib/utils/index.d.ts +3 -1
- package/lib/utils/index.js +4 -2
- package/lib/utils/response.d.ts +34 -4
- package/lib/utils/response.js +30 -5
- package/lib/utils/sensitive-patterns.js +17 -1
- package/lib/validation/index.d.ts +2 -2
- package/lib/validation/index.js +3 -3
- package/package.json +13 -1
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* The remote (non-platform) audit ACTION VOCABULARY.
|
|
5
|
+
*
|
|
6
|
+
* Kept apart from the client that ships the events (`services/remote-audit-client.ts`)
|
|
7
|
+
* because it is an allow-list, not machinery: it is the thing a reviewer reads
|
|
8
|
+
* end to end when deciding whether a service may emit a given action, and it is
|
|
9
|
+
* what platform's ingest validates against.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The exact set of audit actions a NON-PLATFORM (remote) service is permitted to
|
|
13
|
+
* emit through `POST /audit/events`. This is the SINGLE SOURCE — `RemoteAuditAction`
|
|
14
|
+
* is derived from it, so the type and the runtime allow-list can never drift.
|
|
15
|
+
*
|
|
16
|
+
* SECURITY: platform's ingest validates `action` against this subset (via
|
|
17
|
+
* {@link isRemoteAuditAction}), NOT the full platform `AuditAction` union — a
|
|
18
|
+
* `service:*` token must not be able to forge platform-authority events
|
|
19
|
+
* (`admin.superadmin.grant`, `org.ownership.transfer`, `user.login`, …). Keep
|
|
20
|
+
* this list free of any platform-only action.
|
|
21
|
+
*/
|
|
22
|
+
export const REMOTE_AUDIT_ACTIONS = [
|
|
23
|
+
'plugin.build.completed',
|
|
24
|
+
'plugin.build.failed',
|
|
25
|
+
'plugin.build.timeout',
|
|
26
|
+
// A version persisted UNSCANNED because the build-time scan could not run and
|
|
27
|
+
// the operator escape hatch `PLUGIN_ALLOW_UNSCANNED` is on (without it the
|
|
28
|
+
// build fails `IMAGE_SCAN_UNAVAILABLE`). `details` carry name/version/digest.
|
|
29
|
+
'plugin.scan.skipped',
|
|
30
|
+
// Plugin lifecycle mutations (api/plugin route handlers) — the destructive /
|
|
31
|
+
// publishing surface that builds already audit's counterpart: registry delete,
|
|
32
|
+
// source upload, and deploy-to-cluster. `targetId` is the plugin id.
|
|
33
|
+
'plugin.delete',
|
|
34
|
+
'plugin.restore',
|
|
35
|
+
// Manual purge: permanent hard-delete of a soft-deleted plugin tombstone on
|
|
36
|
+
// demand (finalizes what the retention sweep would otherwise do later).
|
|
37
|
+
'plugin.purge',
|
|
38
|
+
'plugin.update',
|
|
39
|
+
'plugin.upload',
|
|
40
|
+
'plugin.deploy',
|
|
41
|
+
// Plugin bulk mutations (api/plugin bulk-plugin route) + DLQ purge (drops all
|
|
42
|
+
// dead-lettered build jobs, cross-org, sysadmin). `details` carries counts.
|
|
43
|
+
'plugin.bulk.update',
|
|
44
|
+
'plugin.bulk.delete',
|
|
45
|
+
'plugin.dlq.purge',
|
|
46
|
+
// Build re-runs from the queue-triage surface: re-enqueue a FAILED build
|
|
47
|
+
// (`plugin.build.retry`) or a dead-lettered one (`plugin.dlq.replay`). Both
|
|
48
|
+
// re-run an image build + plugin persist on the caller's authority, so they
|
|
49
|
+
// are audited mutations; `affectedOrgId` carries the job's owning org.
|
|
50
|
+
'plugin.build.retry',
|
|
51
|
+
'plugin.dlq.replay',
|
|
52
|
+
// Pipeline mutations — emitted by api/pipeline's route handlers
|
|
53
|
+
// (create/update/delete + CodePipeline execution trigger/cancel) and
|
|
54
|
+
// posted to platform's `POST /audit/events` ingest.
|
|
55
|
+
'pipeline.create',
|
|
56
|
+
'pipeline.update',
|
|
57
|
+
'pipeline.delete',
|
|
58
|
+
'pipeline.restore',
|
|
59
|
+
// Manual purge: permanent hard-delete of a soft-deleted pipeline /
|
|
60
|
+
// pipeline_template tombstone on demand (finalizes what the retention sweep
|
|
61
|
+
// would otherwise do later). `targetId` is the purged id.
|
|
62
|
+
'pipeline.purge',
|
|
63
|
+
'pipeline_template.create',
|
|
64
|
+
'pipeline_template.update',
|
|
65
|
+
'pipeline_template.delete',
|
|
66
|
+
'pipeline_template.restore',
|
|
67
|
+
'pipeline_template.purge',
|
|
68
|
+
'pipeline.execution.start',
|
|
69
|
+
'pipeline.execution.cancel',
|
|
70
|
+
// CodePipeline ARN-registry config (api/pipeline registry route) — registering /
|
|
71
|
+
// deregistering the external CodePipeline that backs a pipeline (deploy-affecting).
|
|
72
|
+
'pipeline.registry.register',
|
|
73
|
+
'pipeline.registry.deregister',
|
|
74
|
+
// Quota administration (api/quota) — a superadmin resetting an org's usage
|
|
75
|
+
// counter or editing its tier limits. `affectedOrgId` is the org changed;
|
|
76
|
+
// `details` carries the quotaType + old/new value.
|
|
77
|
+
'quota.reset',
|
|
78
|
+
'quota.limit.update',
|
|
79
|
+
// A superadmin deleting an org's entire quota document.
|
|
80
|
+
'quota.delete',
|
|
81
|
+
// Compliance administration (api/compliance) — the enforcement-posture surface.
|
|
82
|
+
// Approving/revoking an exemption, toggling/authoring/deleting a rule,
|
|
83
|
+
// authoring/deleting a policy, managing scan schedules, applying a template,
|
|
84
|
+
// or cancelling a running scan. `targetId` is the rule/policy/exemption/scan id.
|
|
85
|
+
'compliance.exemption.approve',
|
|
86
|
+
'compliance.exemption.revoke',
|
|
87
|
+
'compliance.rule.toggle',
|
|
88
|
+
'compliance.rule.create',
|
|
89
|
+
'compliance.rule.update',
|
|
90
|
+
'compliance.rule.delete',
|
|
91
|
+
'compliance.rule.restore',
|
|
92
|
+
// Manual on-demand hard-delete (PURGE) of a soft-deleted rule/policy tombstone —
|
|
93
|
+
// the caller-initiated counterpart to the retention sweep's auto-purge. Destroys
|
|
94
|
+
// the tombstone permanently, so it carries the durable, tamper-evident trail.
|
|
95
|
+
'compliance.rule.purge',
|
|
96
|
+
'compliance.policy.create',
|
|
97
|
+
'compliance.policy.update',
|
|
98
|
+
'compliance.policy.delete',
|
|
99
|
+
'compliance.policy.restore',
|
|
100
|
+
'compliance.policy.purge',
|
|
101
|
+
'compliance.scan-schedule.create',
|
|
102
|
+
'compliance.scan-schedule.update',
|
|
103
|
+
'compliance.scan-schedule.delete',
|
|
104
|
+
'compliance.template.apply',
|
|
105
|
+
// Launching an org-wide re-evaluation (the counterpart to `.cancel`) — it
|
|
106
|
+
// persists a scan and can block entities that passed before.
|
|
107
|
+
'compliance.scan.create',
|
|
108
|
+
'compliance.scan.cancel',
|
|
109
|
+
// Per-org compliance notification settings: recipients + the outbound webhook
|
|
110
|
+
// URL/secret. Bearer-equivalent config that redirects violation notices, so a
|
|
111
|
+
// change carries the durable trail (never the secret itself).
|
|
112
|
+
'compliance.notification-preference.update',
|
|
113
|
+
// Image-registry destructive ops (api/image-registry) — garbage-collection
|
|
114
|
+
// sweeps and explicit image/tag deletes.
|
|
115
|
+
'registry.gc',
|
|
116
|
+
'registry.image.delete',
|
|
117
|
+
// Cross-repo tag/image copy (api/image-registry POST /api/images/copy). A
|
|
118
|
+
// cross-tenant copy moves data across customer boundaries, so it needs the
|
|
119
|
+
// durable, tamper-evident trail — not just the Loki operator line.
|
|
120
|
+
'registry.image.copy',
|
|
121
|
+
// A plugin image signed + SBOM-attested by the platform's plugin-signing key
|
|
122
|
+
// (api/image-registry POST /internal/plugin-signatures, called by the plugin
|
|
123
|
+
// build worker). The key is what synth trusts, so every use is on the trail.
|
|
124
|
+
'registry.image.sign',
|
|
125
|
+
// Messaging (api/message) — admin BROADCAST announcements + destructive
|
|
126
|
+
// deletes. 1:1 user messages are intentionally NOT audited (noise + they would
|
|
127
|
+
// pull private content into the trail). `details` carry metadata only
|
|
128
|
+
// (subject/type/scope), NEVER message body content.
|
|
129
|
+
'message.announcement.create',
|
|
130
|
+
'message.delete',
|
|
131
|
+
'message.restore',
|
|
132
|
+
// Manual on-demand PURGE (permanent hard-delete) of an already-soft-deleted
|
|
133
|
+
// message tombstone — the destructive finalizer the retention sweep would
|
|
134
|
+
// otherwise perform at the purge deadline. `details` carry metadata only.
|
|
135
|
+
'message.purge',
|
|
136
|
+
// Billing (api/billing) — subscription + entitlement mutations, mirrored to the
|
|
137
|
+
// central audit trail (these also write to the service-local billing_events
|
|
138
|
+
// collection). `details` carry plan/tier/addon ids only — never card/payment
|
|
139
|
+
// secrets or an AWS account id.
|
|
140
|
+
// Subscription lifecycle a CUSTOMER drives (the admin counterpart is
|
|
141
|
+
// `billing.tier.override`): self-serve create (direct or Marketplace claim),
|
|
142
|
+
// plan/interval change, cancel-at-period-end, undo-cancel, cascade delete.
|
|
143
|
+
'billing.subscription.create',
|
|
144
|
+
'billing.subscription.update',
|
|
145
|
+
'billing.subscription.reactivate',
|
|
146
|
+
'billing.subscription.cancel',
|
|
147
|
+
'billing.subscription.delete',
|
|
148
|
+
'billing.tier.override',
|
|
149
|
+
// Operator-only reseed of the invoice ledger from the payment provider's
|
|
150
|
+
// history (POST /billing/admin/backfill) — mutates finance data fleet-wide.
|
|
151
|
+
'billing.addon.add',
|
|
152
|
+
'billing.addon.remove',
|
|
153
|
+
// System-initiated removal of a tier-included add-on on a plan upgrade (the
|
|
154
|
+
// account's new tier now bundles the feature) — distinct from a user-initiated
|
|
155
|
+
// `remove` so finance can tell an auto-prune from a customer action.
|
|
156
|
+
'billing.addon.prune',
|
|
157
|
+
// Discounts (docs/billing-discounts.md) — mint/issue/apply/remove/revoke of a
|
|
158
|
+
// price coupon or usage credit. `details` carry the discount id + kind/value
|
|
159
|
+
// only, never the opaque token or signing key.
|
|
160
|
+
'billing.discount.generate',
|
|
161
|
+
'billing.discount.issue',
|
|
162
|
+
'billing.discount.apply',
|
|
163
|
+
'billing.discount.remove',
|
|
164
|
+
'billing.discount.revoke',
|
|
165
|
+
// Promotions (docs/billing-discounts.md#promotions) — rule-driven auto-grant
|
|
166
|
+
// campaigns. `details` carry the promotion id + cents/event only.
|
|
167
|
+
'billing.promotion.create',
|
|
168
|
+
'billing.promotion.update',
|
|
169
|
+
'billing.promotion.revoke',
|
|
170
|
+
'billing.promotion.grant',
|
|
171
|
+
'billing.promotion.activate',
|
|
172
|
+
// Usage-credit realization — a customer/compliance-visible record of credit
|
|
173
|
+
// movement: `consumed` (Marketplace metered drawdown), `exhausted` (balance hit
|
|
174
|
+
// zero), and a combo ending. `details` carry cents/ids only, no payment secrets.
|
|
175
|
+
'billing.credit.consumed',
|
|
176
|
+
'billing.credit.exhausted',
|
|
177
|
+
'billing.combo.expired',
|
|
178
|
+
// Reporting (api/reporting) — the three reporting mutations whose effect
|
|
179
|
+
// outlives a request log: the per-org correlation-window config write, a
|
|
180
|
+
// post-deploy outcome marker (it moves the org's DORA CFR/MTTR), and the
|
|
181
|
+
// inbound billing→reporting retention-entitlement sync (a retention cut is a
|
|
182
|
+
// data-destroying change applied by the next sweep). `details` carry the
|
|
183
|
+
// settings/outcome values only.
|
|
184
|
+
'reporting.settings.update',
|
|
185
|
+
'reporting.deployment.outcome',
|
|
186
|
+
'reporting.retention.sync',
|
|
187
|
+
// Denied authorization attempt — emitted best-effort by the shared
|
|
188
|
+
// `requirePermission` / `requireSystemAdmin` gate when a state-changing
|
|
189
|
+
// (non-GET) request is rejected, so probing/escalation attempts are visible
|
|
190
|
+
// rather than invisible. `details` carries the required permission + path;
|
|
191
|
+
// `outcome` is 'failure'.
|
|
192
|
+
'authz.denied',
|
|
193
|
+
// "Ask" assistant activity — visibility into what the assistant did on a user's
|
|
194
|
+
// behalf. `ask.query` is a read-only how-to turn; `ask.agent.turn` is a tool-calling
|
|
195
|
+
// turn. `details` carry SAFE METADATA ONLY (tools used, proposal kinds, query
|
|
196
|
+
// length, outcome), never the raw query text.
|
|
197
|
+
'ask.query',
|
|
198
|
+
'ask.agent.turn',
|
|
199
|
+
// Plugin ecosystem (docs/runbooks/ecosystem-moderation.md). Governance actions
|
|
200
|
+
// are recorded with `orgId` = the system org; `affectedOrgId` is the
|
|
201
|
+
// publisher's org (listing/version/review/advisory/publisher moderation) or
|
|
202
|
+
// the installing org (installs + policy). Anonymous submissions use the
|
|
203
|
+
// `ANONYMOUS_ACTOR_ID` actor with `details.submissionId`. `details` carry ids,
|
|
204
|
+
// versions, digests, tier, state and reason codes only — never review bodies,
|
|
205
|
+
// README content, secrets or emails.
|
|
206
|
+
// Publishers.
|
|
207
|
+
'publisher.create',
|
|
208
|
+
'publisher.update',
|
|
209
|
+
'publisher.terms.accept',
|
|
210
|
+
'publisher.verify.request',
|
|
211
|
+
'publisher.verify.approve',
|
|
212
|
+
'publisher.verify.reject',
|
|
213
|
+
'publisher.tier.change',
|
|
214
|
+
'publisher.suspend',
|
|
215
|
+
'publisher.unsuspend',
|
|
216
|
+
'publisher.transfer.request',
|
|
217
|
+
'publisher.transfer.accept',
|
|
218
|
+
'publisher.transfer.decline',
|
|
219
|
+
'publisher.transfer.approve',
|
|
220
|
+
'publisher.transfer.reject',
|
|
221
|
+
'publisher.profile-change.approve',
|
|
222
|
+
'publisher.profile-change.reject',
|
|
223
|
+
// Publish requests (tenant → system org). `details.kind` names the request.
|
|
224
|
+
'plugin.request.submit',
|
|
225
|
+
'plugin.request.withdraw',
|
|
226
|
+
'plugin.request.approve',
|
|
227
|
+
'plugin.request.second-approve',
|
|
228
|
+
'plugin.request.reject',
|
|
229
|
+
'plugin.request.auto-approve',
|
|
230
|
+
// Listings and versions (system org, except the tenant pause).
|
|
231
|
+
'plugin.listing.publish',
|
|
232
|
+
'plugin.listing.unlist',
|
|
233
|
+
'plugin.listing.update',
|
|
234
|
+
'plugin.listing.state.change',
|
|
235
|
+
'plugin.listing.pause',
|
|
236
|
+
'plugin.listing.unpause',
|
|
237
|
+
'plugin.version.pause',
|
|
238
|
+
'plugin.version.yank',
|
|
239
|
+
'plugin.version.unyank',
|
|
240
|
+
'plugin.version.deprecate',
|
|
241
|
+
'plugin.collection.update',
|
|
242
|
+
// Ecosystem configuration (system org).
|
|
243
|
+
'ecosystem.auto-approval-rule.create',
|
|
244
|
+
'ecosystem.auto-approval-rule.update',
|
|
245
|
+
'ecosystem.auto-approval-rule.delete',
|
|
246
|
+
'ecosystem.reserved-name.update',
|
|
247
|
+
'ecosystem.sla.update',
|
|
248
|
+
// Public registry namespace (`public/*`): copy + sign + attest on publish,
|
|
249
|
+
// the tier-change/suspension re-sign job, tag removal on yank/takedown, and
|
|
250
|
+
// the retention sweep.
|
|
251
|
+
'registry.image.publish',
|
|
252
|
+
'registry.image.resign',
|
|
253
|
+
'registry.image.yank',
|
|
254
|
+
'registry.image.gc',
|
|
255
|
+
// Installs and the installing org's consumption policy (org-local).
|
|
256
|
+
'plugin.install.request',
|
|
257
|
+
'plugin.install.approve',
|
|
258
|
+
'plugin.install.deny',
|
|
259
|
+
'plugin.install.create',
|
|
260
|
+
'plugin.install.upgrade',
|
|
261
|
+
// A member's request to change an install past what they may do alone, and its decision.
|
|
262
|
+
'plugin.install.change-request',
|
|
263
|
+
'plugin.install.change-approve',
|
|
264
|
+
'plugin.install.change-reject',
|
|
265
|
+
'plugin.install.remove',
|
|
266
|
+
'org.plugin-install-policy.update',
|
|
267
|
+
// Reviews and replies.
|
|
268
|
+
'plugin.review.create',
|
|
269
|
+
'plugin.review.update',
|
|
270
|
+
'plugin.review.delete',
|
|
271
|
+
'plugin.review.report',
|
|
272
|
+
'plugin.review.hold',
|
|
273
|
+
'plugin.review.release',
|
|
274
|
+
'plugin.review.remove',
|
|
275
|
+
'plugin.review.anonymize',
|
|
276
|
+
'plugin.review.reply.create',
|
|
277
|
+
'plugin.review.reply.update',
|
|
278
|
+
'plugin.review.reply.delete',
|
|
279
|
+
// Anonymous submissions.
|
|
280
|
+
'plugin.submission.create',
|
|
281
|
+
'plugin.submission.verify',
|
|
282
|
+
'plugin.submission.gate-fail',
|
|
283
|
+
'plugin.submission.approve',
|
|
284
|
+
'plugin.submission.reject',
|
|
285
|
+
'plugin.submission.claim',
|
|
286
|
+
'plugin.submission.expire',
|
|
287
|
+
// Security advisories (publish/withdraw are system-org only; update = a
|
|
288
|
+
// moderator editing a draft before it is published).
|
|
289
|
+
'plugin.advisory.create',
|
|
290
|
+
'plugin.advisory.update',
|
|
291
|
+
'plugin.advisory.publish',
|
|
292
|
+
'plugin.advisory.withdraw',
|
|
293
|
+
// Per-org plugin security notifications (plugin scan gates): the settings
|
|
294
|
+
// (recipients, digest, webhook, external address — changed field names and
|
|
295
|
+
// the webhook host only, never the secret or the address), an external
|
|
296
|
+
// address confirmed through its emailed single-use link, and a test send.
|
|
297
|
+
'plugin.security_notifications.update',
|
|
298
|
+
'plugin.security_notifications.external_email.verify',
|
|
299
|
+
'plugin.security_notifications.test',
|
|
300
|
+
];
|
|
301
|
+
/** Whether `value` is an action a remote service may emit (the ingest allow-list). */
|
|
302
|
+
export function isRemoteAuditAction(value) {
|
|
303
|
+
return REMOTE_AUDIT_ACTIONS.includes(value);
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3RlLWF1ZGl0LWFjdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMvcmVtb3RlLWF1ZGl0LWFjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7OztHQU9HO0FBR0g7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHO0lBQ2xDLHdCQUF3QjtJQUN4QixxQkFBcUI7SUFDckIsc0JBQXNCO0lBQ3RCLDhFQUE4RTtJQUM5RSwyRUFBMkU7SUFDM0UsOEVBQThFO0lBQzlFLHFCQUFxQjtJQUNyQiw2RUFBNkU7SUFDN0UsK0VBQStFO0lBQy9FLHFFQUFxRTtJQUNyRSxlQUFlO0lBQ2YsZ0JBQWdCO0lBQ2hCLDRFQUE0RTtJQUM1RSx3RUFBd0U7SUFDeEUsY0FBYztJQUNkLGVBQWU7SUFDZixlQUFlO0lBQ2YsZUFBZTtJQUNmLDhFQUE4RTtJQUM5RSw0RUFBNEU7SUFDNUUsb0JBQW9CO0lBQ3BCLG9CQUFvQjtJQUNwQixrQkFBa0I7SUFDbEIseUVBQXlFO0lBQ3pFLDRFQUE0RTtJQUM1RSw0RUFBNEU7SUFDNUUsdUVBQXVFO0lBQ3ZFLG9CQUFvQjtJQUNwQixtQkFBbUI7SUFDbkIsZ0VBQWdFO0lBQ2hFLHFFQUFxRTtJQUNyRSxvREFBb0Q7SUFDcEQsaUJBQWlCO0lBQ2pCLGlCQUFpQjtJQUNqQixpQkFBaUI7SUFDakIsa0JBQWtCO0lBQ2xCLG1FQUFtRTtJQUNuRSw0RUFBNEU7SUFDNUUsMERBQTBEO0lBQzFELGdCQUFnQjtJQUNoQiwwQkFBMEI7SUFDMUIsMEJBQTBCO0lBQzFCLDBCQUEwQjtJQUMxQiwyQkFBMkI7SUFDM0IseUJBQXlCO0lBQ3pCLDBCQUEwQjtJQUMxQiwyQkFBMkI7SUFDM0IsaUZBQWlGO0lBQ2pGLG9GQUFvRjtJQUNwRiw0QkFBNEI7SUFDNUIsOEJBQThCO0lBQzlCLDJFQUEyRTtJQUMzRSww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QjtJQUMxQix5QkFBeUI7SUFDekIsMEJBQTBCO0lBQzFCLHdFQUF3RTtJQUN4RSxxREFBcUQ7SUFDckQsd0JBQXdCO0lBQ3hCLHdCQUF3QjtJQUN4Qix5QkFBeUI7SUFDekIsMEJBQTBCO0lBQzFCLDBFQUEwRTtJQUMxRSwyRUFBMkU7SUFDM0UsdUVBQXVFO0lBQ3ZFLDBFQUEwRTtJQUMxRSxzQ0FBc0M7SUFDdEMscURBQXFEO0lBQ3JELG9DQUFvQztDQUM1QixDQUFDO0FBSVgsc0ZBQXNGO0FBQ3RGLE1BQU0sVUFBVSxtQkFBbUIsQ0FBQyxLQUFhO0lBQy9DLE9BQVEsb0JBQTBDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ3JFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBUaGUgcmVtb3RlIChub24tcGxhdGZvcm0pIGF1ZGl0IEFDVElPTiBWT0NBQlVMQVJZLlxuICpcbiAqIEtlcHQgYXBhcnQgZnJvbSB0aGUgY2xpZW50IHRoYXQgc2hpcHMgdGhlIGV2ZW50cyAoYHNlcnZpY2VzL3JlbW90ZS1hdWRpdC1jbGllbnQudHNgKVxuICogYmVjYXVzZSBpdCBpcyBhbiBhbGxvdy1saXN0LCBub3QgbWFjaGluZXJ5OiBpdCBpcyB0aGUgdGhpbmcgYSByZXZpZXdlciByZWFkc1xuICogZW5kIHRvIGVuZCB3aGVuIGRlY2lkaW5nIHdoZXRoZXIgYSBzZXJ2aWNlIG1heSBlbWl0IGEgZ2l2ZW4gYWN0aW9uLCBhbmQgaXQgaXNcbiAqIHdoYXQgcGxhdGZvcm0ncyBpbmdlc3QgdmFsaWRhdGVzIGFnYWluc3QuXG4gKi9cblxuXG4vKipcbiAqIFRoZSBleGFjdCBzZXQgb2YgYXVkaXQgYWN0aW9ucyBhIE5PTi1QTEFURk9STSAocmVtb3RlKSBzZXJ2aWNlIGlzIHBlcm1pdHRlZCB0b1xuICogZW1pdCB0aHJvdWdoIGBQT1NUIC9hdWRpdC9ldmVudHNgLiBUaGlzIGlzIHRoZSBTSU5HTEUgU09VUkNFIOKAlCBgUmVtb3RlQXVkaXRBY3Rpb25gXG4gKiBpcyBkZXJpdmVkIGZyb20gaXQsIHNvIHRoZSB0eXBlIGFuZCB0aGUgcnVudGltZSBhbGxvdy1saXN0IGNhbiBuZXZlciBkcmlmdC5cbiAqXG4gKiBTRUNVUklUWTogcGxhdGZvcm0ncyBpbmdlc3QgdmFsaWRhdGVzIGBhY3Rpb25gIGFnYWluc3QgdGhpcyBzdWJzZXQgKHZpYVxuICoge0BsaW5rIGlzUmVtb3RlQXVkaXRBY3Rpb259KSwgTk9UIHRoZSBmdWxsIHBsYXRmb3JtIGBBdWRpdEFjdGlvbmAgdW5pb24g4oCUIGFcbiAqIGBzZXJ2aWNlOipgIHRva2VuIG11c3Qgbm90IGJlIGFibGUgdG8gZm9yZ2UgcGxhdGZvcm0tYXV0aG9yaXR5IGV2ZW50c1xuICogKGBhZG1pbi5zdXBlcmFkbWluLmdyYW50YCwgYG9yZy5vd25lcnNoaXAudHJhbnNmZXJgLCBgdXNlci5sb2dpbmAsIOKApikuIEtlZXBcbiAqIHRoaXMgbGlzdCBmcmVlIG9mIGFueSBwbGF0Zm9ybS1vbmx5IGFjdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IFJFTU9URV9BVURJVF9BQ1RJT05TID0gW1xuICAncGx1Z2luLmJ1aWxkLmNvbXBsZXRlZCcsXG4gICdwbHVnaW4uYnVpbGQuZmFpbGVkJyxcbiAgJ3BsdWdpbi5idWlsZC50aW1lb3V0JyxcbiAgLy8gQSB2ZXJzaW9uIHBlcnNpc3RlZCBVTlNDQU5ORUQgYmVjYXVzZSB0aGUgYnVpbGQtdGltZSBzY2FuIGNvdWxkIG5vdCBydW4gYW5kXG4gIC8vIHRoZSBvcGVyYXRvciBlc2NhcGUgaGF0Y2ggYFBMVUdJTl9BTExPV19VTlNDQU5ORURgIGlzIG9uICh3aXRob3V0IGl0IHRoZVxuICAvLyBidWlsZCBmYWlscyBgSU1BR0VfU0NBTl9VTkFWQUlMQUJMRWApLiBgZGV0YWlsc2AgY2FycnkgbmFtZS92ZXJzaW9uL2RpZ2VzdC5cbiAgJ3BsdWdpbi5zY2FuLnNraXBwZWQnLFxuICAvLyBQbHVnaW4gbGlmZWN5Y2xlIG11dGF0aW9ucyAoYXBpL3BsdWdpbiByb3V0ZSBoYW5kbGVycykg4oCUIHRoZSBkZXN0cnVjdGl2ZSAvXG4gIC8vIHB1Ymxpc2hpbmcgc3VyZmFjZSB0aGF0IGJ1aWxkcyBhbHJlYWR5IGF1ZGl0J3MgY291bnRlcnBhcnQ6IHJlZ2lzdHJ5IGRlbGV0ZSxcbiAgLy8gc291cmNlIHVwbG9hZCwgYW5kIGRlcGxveS10by1jbHVzdGVyLiBgdGFyZ2V0SWRgIGlzIHRoZSBwbHVnaW4gaWQuXG4gICdwbHVnaW4uZGVsZXRlJyxcbiAgJ3BsdWdpbi5yZXN0b3JlJyxcbiAgLy8gTWFudWFsIHB1cmdlOiBwZXJtYW5lbnQgaGFyZC1kZWxldGUgb2YgYSBzb2Z0LWRlbGV0ZWQgcGx1Z2luIHRvbWJzdG9uZSBvblxuICAvLyBkZW1hbmQgKGZpbmFsaXplcyB3aGF0IHRoZSByZXRlbnRpb24gc3dlZXAgd291bGQgb3RoZXJ3aXNlIGRvIGxhdGVyKS5cbiAgJ3BsdWdpbi5wdXJnZScsXG4gICdwbHVnaW4udXBkYXRlJyxcbiAgJ3BsdWdpbi51cGxvYWQnLFxuICAncGx1Z2luLmRlcGxveScsXG4gIC8vIFBsdWdpbiBidWxrIG11dGF0aW9ucyAoYXBpL3BsdWdpbiBidWxrLXBsdWdpbiByb3V0ZSkgKyBETFEgcHVyZ2UgKGRyb3BzIGFsbFxuICAvLyBkZWFkLWxldHRlcmVkIGJ1aWxkIGpvYnMsIGNyb3NzLW9yZywgc3lzYWRtaW4pLiBgZGV0YWlsc2AgY2FycmllcyBjb3VudHMuXG4gICdwbHVnaW4uYnVsay51cGRhdGUnLFxuICAncGx1Z2luLmJ1bGsuZGVsZXRlJyxcbiAgJ3BsdWdpbi5kbHEucHVyZ2UnLFxuICAvLyBCdWlsZCByZS1ydW5zIGZyb20gdGhlIHF1ZXVlLXRyaWFnZSBzdXJmYWNlOiByZS1lbnF1ZXVlIGEgRkFJTEVEIGJ1aWxkXG4gIC8vIChgcGx1Z2luLmJ1aWxkLnJldHJ5YCkgb3IgYSBkZWFkLWxldHRlcmVkIG9uZSAoYHBsdWdpbi5kbHEucmVwbGF5YCkuIEJvdGhcbiAgLy8gcmUtcnVuIGFuIGltYWdlIGJ1aWxkICsgcGx1Z2luIHBlcnNpc3Qgb24gdGhlIGNhbGxlcidzIGF1dGhvcml0eSwgc28gdGhleVxuICAvLyBhcmUgYXVkaXRlZCBtdXRhdGlvbnM7IGBhZmZlY3RlZE9yZ0lkYCBjYXJyaWVzIHRoZSBqb2IncyBvd25pbmcgb3JnLlxuICAncGx1Z2luLmJ1aWxkLnJldHJ5JyxcbiAgJ3BsdWdpbi5kbHEucmVwbGF5JyxcbiAgLy8gUGlwZWxpbmUgbXV0YXRpb25zIOKAlCBlbWl0dGVkIGJ5IGFwaS9waXBlbGluZSdzIHJvdXRlIGhhbmRsZXJzXG4gIC8vIChjcmVhdGUvdXBkYXRlL2RlbGV0ZSArIENvZGVQaXBlbGluZSBleGVjdXRpb24gdHJpZ2dlci9jYW5jZWwpIGFuZFxuICAvLyBwb3N0ZWQgdG8gcGxhdGZvcm0ncyBgUE9TVCAvYXVkaXQvZXZlbnRzYCBpbmdlc3QuXG4gICdwaXBlbGluZS5jcmVhdGUnLFxuICAncGlwZWxpbmUudXBkYXRlJyxcbiAgJ3BpcGVsaW5lLmRlbGV0ZScsXG4gICdwaXBlbGluZS5yZXN0b3JlJyxcbiAgLy8gTWFudWFsIHB1cmdlOiBwZXJtYW5lbnQgaGFyZC1kZWxldGUgb2YgYSBzb2Z0LWRlbGV0ZWQgcGlwZWxpbmUgL1xuICAvLyBwaXBlbGluZV90ZW1wbGF0ZSB0b21ic3RvbmUgb24gZGVtYW5kIChmaW5hbGl6ZXMgd2hhdCB0aGUgcmV0ZW50aW9uIHN3ZWVwXG4gIC8vIHdvdWxkIG90aGVyd2lzZSBkbyBsYXRlcikuIGB0YXJnZXRJZGAgaXMgdGhlIHB1cmdlZCBpZC5cbiAgJ3BpcGVsaW5lLnB1cmdlJyxcbiAgJ3BpcGVsaW5lX3RlbXBsYXRlLmNyZWF0ZScsXG4gICdwaXBlbGluZV90ZW1wbGF0ZS51cGRhdGUnLFxuICAncGlwZWxpbmVfdGVtcGxhdGUuZGVsZXRlJyxcbiAgJ3BpcGVsaW5lX3RlbXBsYXRlLnJlc3RvcmUnLFxuICAncGlwZWxpbmVfdGVtcGxhdGUucHVyZ2UnLFxuICAncGlwZWxpbmUuZXhlY3V0aW9uLnN0YXJ0JyxcbiAgJ3BpcGVsaW5lLmV4ZWN1dGlvbi5jYW5jZWwnLFxuICAvLyBDb2RlUGlwZWxpbmUgQVJOLXJlZ2lzdHJ5IGNvbmZpZyAoYXBpL3BpcGVsaW5lIHJlZ2lzdHJ5IHJvdXRlKSDigJQgcmVnaXN0ZXJpbmcgL1xuICAvLyBkZXJlZ2lzdGVyaW5nIHRoZSBleHRlcm5hbCBDb2RlUGlwZWxpbmUgdGhhdCBiYWNrcyBhIHBpcGVsaW5lIChkZXBsb3ktYWZmZWN0aW5nKS5cbiAgJ3BpcGVsaW5lLnJlZ2lzdHJ5LnJlZ2lzdGVyJyxcbiAgJ3BpcGVsaW5lLnJlZ2lzdHJ5LmRlcmVnaXN0ZXInLFxuICAvLyBRdW90YSBhZG1pbmlzdHJhdGlvbiAoYXBpL3F1b3RhKSDigJQgYSBzdXBlcmFkbWluIHJlc2V0dGluZyBhbiBvcmcncyB1c2FnZVxuICAvLyBjb3VudGVyIG9yIGVkaXRpbmcgaXRzIHRpZXIgbGltaXRzLiBgYWZmZWN0ZWRPcmdJZGAgaXMgdGhlIG9yZyBjaGFuZ2VkO1xuICAvLyBgZGV0YWlsc2AgY2FycmllcyB0aGUgcXVvdGFUeXBlICsgb2xkL25ldyB2YWx1ZS5cbiAgJ3F1b3RhLnJlc2V0JyxcbiAgJ3F1b3RhLmxpbWl0LnVwZGF0ZScsXG4gIC8vIEEgc3VwZXJhZG1pbiBkZWxldGluZyBhbiBvcmcncyBlbnRpcmUgcXVvdGEgZG9jdW1lbnQuXG4gICdxdW90YS5kZWxldGUnLFxuICAvLyBDb21wbGlhbmNlIGFkbWluaXN0cmF0aW9uIChhcGkvY29tcGxpYW5jZSkg4oCUIHRoZSBlbmZvcmNlbWVudC1wb3N0dXJlIHN1cmZhY2UuXG4gIC8vIEFwcHJvdmluZy9yZXZva2luZyBhbiBleGVtcHRpb24sIHRvZ2dsaW5nL2F1dGhvcmluZy9kZWxldGluZyBhIHJ1bGUsXG4gIC8vIGF1dGhvcmluZy9kZWxldGluZyBhIHBvbGljeSwgbWFuYWdpbmcgc2NhbiBzY2hlZHVsZXMsIGFwcGx5aW5nIGEgdGVtcGxhdGUsXG4gIC8vIG9yIGNhbmNlbGxpbmcgYSBydW5uaW5nIHNjYW4uIGB0YXJnZXRJZGAgaXMgdGhlIHJ1bGUvcG9saWN5L2V4ZW1wdGlvbi9zY2FuIGlkLlxuICAnY29tcGxpYW5jZS5leGVtcHRpb24uYXBwcm92ZScsXG4gICdjb21wbGlhbmNlLmV4ZW1wdGlvbi5yZXZva2UnLFxuICAnY29tcGxpYW5jZS5ydWxlLnRvZ2dsZScsXG4gICdjb21wbGlhbmNlLnJ1bGUuY3JlYXRlJyxcbiAgJ2NvbXBsaWFuY2UucnVsZS51cGRhdGUnLFxuICAnY29tcGxpYW5jZS5ydWxlLmRlbGV0ZScsXG4gICdjb21wbGlhbmNlLnJ1bGUucmVzdG9yZScsXG4gIC8vIE1hbnVhbCBvbi1kZW1hbmQgaGFyZC1kZWxldGUgKFBVUkdFKSBvZiBhIHNvZnQtZGVsZXRlZCBydWxlL3BvbGljeSB0b21ic3RvbmUg4oCUXG4gIC8vIHRoZSBjYWxsZXItaW5pdGlhdGVkIGNvdW50ZXJwYXJ0IHRvIHRoZSByZXRlbnRpb24gc3dlZXAncyBhdXRvLXB1cmdlLiBEZXN0cm95c1xuICAvLyB0aGUgdG9tYnN0b25lIHBlcm1hbmVudGx5LCBzbyBpdCBjYXJyaWVzIHRoZSBkdXJhYmxlLCB0YW1wZXItZXZpZGVudCB0cmFpbC5cbiAgJ2NvbXBsaWFuY2UucnVsZS5wdXJnZScsXG4gICdjb21wbGlhbmNlLnBvbGljeS5jcmVhdGUnLFxuICAnY29tcGxpYW5jZS5wb2xpY3kudXBkYXRlJyxcbiAgJ2NvbXBsaWFuY2UucG9saWN5LmRlbGV0ZScsXG4gICdjb21wbGlhbmNlLnBvbGljeS5yZXN0b3JlJyxcbiAgJ2NvbXBsaWFuY2UucG9saWN5LnB1cmdlJyxcbiAgJ2NvbXBsaWFuY2Uuc2Nhbi1zY2hlZHVsZS5jcmVhdGUnLFxuICAnY29tcGxpYW5jZS5zY2FuLXNjaGVkdWxlLnVwZGF0ZScsXG4gICdjb21wbGlhbmNlLnNjYW4tc2NoZWR1bGUuZGVsZXRlJyxcbiAgJ2NvbXBsaWFuY2UudGVtcGxhdGUuYXBwbHknLFxuICAvLyBMYXVuY2hpbmcgYW4gb3JnLXdpZGUgcmUtZXZhbHVhdGlvbiAodGhlIGNvdW50ZXJwYXJ0IHRvIGAuY2FuY2VsYCkg4oCUIGl0XG4gIC8vIHBlcnNpc3RzIGEgc2NhbiBhbmQgY2FuIGJsb2NrIGVudGl0aWVzIHRoYXQgcGFzc2VkIGJlZm9yZS5cbiAgJ2NvbXBsaWFuY2Uuc2Nhbi5jcmVhdGUnLFxuICAnY29tcGxpYW5jZS5zY2FuLmNhbmNlbCcsXG4gIC8vIFBlci1vcmcgY29tcGxpYW5jZSBub3RpZmljYXRpb24gc2V0dGluZ3M6IHJlY2lwaWVudHMgKyB0aGUgb3V0Ym91bmQgd2ViaG9va1xuICAvLyBVUkwvc2VjcmV0LiBCZWFyZXItZXF1aXZhbGVudCBjb25maWcgdGhhdCByZWRpcmVjdHMgdmlvbGF0aW9uIG5vdGljZXMsIHNvIGFcbiAgLy8gY2hhbmdlIGNhcnJpZXMgdGhlIGR1cmFibGUgdHJhaWwgKG5ldmVyIHRoZSBzZWNyZXQgaXRzZWxmKS5cbiAgJ2NvbXBsaWFuY2Uubm90aWZpY2F0aW9uLXByZWZlcmVuY2UudXBkYXRlJyxcbiAgLy8gSW1hZ2UtcmVnaXN0cnkgZGVzdHJ1Y3RpdmUgb3BzIChhcGkvaW1hZ2UtcmVnaXN0cnkpIOKAlCBnYXJiYWdlLWNvbGxlY3Rpb25cbiAgLy8gc3dlZXBzIGFuZCBleHBsaWNpdCBpbWFnZS90YWcgZGVsZXRlcy5cbiAgJ3JlZ2lzdHJ5LmdjJyxcbiAgJ3JlZ2lzdHJ5LmltYWdlLmRlbGV0ZScsXG4gIC8vIENyb3NzLXJlcG8gdGFnL2ltYWdlIGNvcHkgKGFwaS9pbWFnZS1yZWdpc3RyeSBQT1NUIC9hcGkvaW1hZ2VzL2NvcHkpLiBBXG4gIC8vIGNyb3NzLXRlbmFudCBjb3B5IG1vdmVzIGRhdGEgYWNyb3NzIGN1c3RvbWVyIGJvdW5kYXJpZXMsIHNvIGl0IG5lZWRzIHRoZVxuICAvLyBkdXJhYmxlLCB0YW1wZXItZXZpZGVudCB0cmFpbCDigJQgbm90IGp1c3QgdGhlIExva2kgb3BlcmF0b3IgbGluZS5cbiAgJ3JlZ2lzdHJ5LmltYWdlLmNvcHknLFxuICAvLyBBIHBsdWdpbiBpbWFnZSBzaWduZWQgKyBTQk9NLWF0dGVzdGVkIGJ5IHRoZSBwbGF0Zm9ybSdzIHBsdWdpbi1zaWduaW5nIGtleVxuICAvLyAoYXBpL2ltYWdlLXJlZ2lzdHJ5IFBPU1QgL2ludGVybmFsL3BsdWdpbi1zaWduYXR1cmVzLCBjYWxsZWQgYnkgdGhlIHBsdWdpblxuICAvLyBidWlsZCB3b3JrZXIpLiBUaGUga2V5IGlzIHdoYXQgc3ludGggdHJ1c3RzLCBzbyBldmVyeSB1c2UgaXMgb24gdGhlIHRyYWlsLlxuICAncmVnaXN0cnkuaW1hZ2Uuc2lnbicsXG4gIC8vIE1lc3NhZ2luZyAoYXBpL21lc3NhZ2UpIOKAlCBhZG1pbiBCUk9BRENBU1QgYW5ub3VuY2VtZW50cyArIGRlc3RydWN0aXZlXG4gIC8vIGRlbGV0ZXMuIDE6MSB1c2VyIG1lc3NhZ2VzIGFyZSBpbnRlbnRpb25hbGx5IE5PVCBhdWRpdGVkIChub2lzZSArIHRoZXkgd291bGRcbiAgLy8gcHVsbCBwcml2YXRlIGNvbnRlbnQgaW50byB0aGUgdHJhaWwpLiBgZGV0YWlsc2AgY2FycnkgbWV0YWRhdGEgb25seVxuICAvLyAoc3ViamVjdC90eXBlL3Njb3BlKSwgTkVWRVIgbWVzc2FnZSBib2R5IGNvbnRlbnQuXG4gICdtZXNzYWdlLmFubm91bmNlbWVudC5jcmVhdGUnLFxuICAnbWVzc2FnZS5kZWxldGUnLFxuICAnbWVzc2FnZS5yZXN0b3JlJyxcbiAgLy8gTWFudWFsIG9uLWRlbWFuZCBQVVJHRSAocGVybWFuZW50IGhhcmQtZGVsZXRlKSBvZiBhbiBhbHJlYWR5LXNvZnQtZGVsZXRlZFxuICAvLyBtZXNzYWdlIHRvbWJzdG9uZSDigJQgdGhlIGRlc3RydWN0aXZlIGZpbmFsaXplciB0aGUgcmV0ZW50aW9uIHN3ZWVwIHdvdWxkXG4gIC8vIG90aGVyd2lzZSBwZXJmb3JtIGF0IHRoZSBwdXJnZSBkZWFkbGluZS4gYGRldGFpbHNgIGNhcnJ5IG1ldGFkYXRhIG9ubHkuXG4gICdtZXNzYWdlLnB1cmdlJyxcbiAgLy8gQmlsbGluZyAoYXBpL2JpbGxpbmcpIOKAlCBzdWJzY3JpcHRpb24gKyBlbnRpdGxlbWVudCBtdXRhdGlvbnMsIG1pcnJvcmVkIHRvIHRoZVxuICAvLyBjZW50cmFsIGF1ZGl0IHRyYWlsICh0aGVzZSBhbHNvIHdyaXRlIHRvIHRoZSBzZXJ2aWNlLWxvY2FsIGJpbGxpbmdfZXZlbnRzXG4gIC8vIGNvbGxlY3Rpb24pLiBgZGV0YWlsc2AgY2FycnkgcGxhbi90aWVyL2FkZG9uIGlkcyBvbmx5IOKAlCBuZXZlciBjYXJkL3BheW1lbnRcbiAgLy8gc2VjcmV0cyBvciBhbiBBV1MgYWNjb3VudCBpZC5cbiAgLy8gU3Vic2NyaXB0aW9uIGxpZmVjeWNsZSBhIENVU1RPTUVSIGRyaXZlcyAodGhlIGFkbWluIGNvdW50ZXJwYXJ0IGlzXG4gIC8vIGBiaWxsaW5nLnRpZXIub3ZlcnJpZGVgKTogc2VsZi1zZXJ2ZSBjcmVhdGUgKGRpcmVjdCBvciBNYXJrZXRwbGFjZSBjbGFpbSksXG4gIC8vIHBsYW4vaW50ZXJ2YWwgY2hhbmdlLCBjYW5jZWwtYXQtcGVyaW9kLWVuZCwgdW5kby1jYW5jZWwsIGNhc2NhZGUgZGVsZXRlLlxuICAnYmlsbGluZy5zdWJzY3JpcHRpb24uY3JlYXRlJyxcbiAgJ2JpbGxpbmcuc3Vic2NyaXB0aW9uLnVwZGF0ZScsXG4gICdiaWxsaW5nLnN1YnNjcmlwdGlvbi5yZWFjdGl2YXRlJyxcbiAgJ2JpbGxpbmcuc3Vic2NyaXB0aW9uLmNhbmNlbCcsXG4gICdiaWxsaW5nLnN1YnNjcmlwdGlvbi5kZWxldGUnLFxuICAnYmlsbGluZy50aWVyLm92ZXJyaWRlJyxcbiAgLy8gT3BlcmF0b3Itb25seSByZXNlZWQgb2YgdGhlIGludm9pY2UgbGVkZ2VyIGZyb20gdGhlIHBheW1lbnQgcHJvdmlkZXInc1xuICAvLyBoaXN0b3J5IChQT1NUIC9iaWxsaW5nL2FkbWluL2JhY2tmaWxsKSDigJQgbXV0YXRlcyBmaW5hbmNlIGRhdGEgZmxlZXQtd2lkZS5cbiAgJ2JpbGxpbmcuYWRkb24uYWRkJyxcbiAgJ2JpbGxpbmcuYWRkb24ucmVtb3ZlJyxcbiAgLy8gU3lzdGVtLWluaXRpYXRlZCByZW1vdmFsIG9mIGEgdGllci1pbmNsdWRlZCBhZGQtb24gb24gYSBwbGFuIHVwZ3JhZGUgKHRoZVxuICAvLyBhY2NvdW50J3MgbmV3IHRpZXIgbm93IGJ1bmRsZXMgdGhlIGZlYXR1cmUpIOKAlCBkaXN0aW5jdCBmcm9tIGEgdXNlci1pbml0aWF0ZWRcbiAgLy8gYHJlbW92ZWAgc28gZmluYW5jZSBjYW4gdGVsbCBhbiBhdXRvLXBydW5lIGZyb20gYSBjdXN0b21lciBhY3Rpb24uXG4gICdiaWxsaW5nLmFkZG9uLnBydW5lJyxcbiAgLy8gRGlzY291bnRzIChkb2NzL2JpbGxpbmctZGlzY291bnRzLm1kKSDigJQgbWludC9pc3N1ZS9hcHBseS9yZW1vdmUvcmV2b2tlIG9mIGFcbiAgLy8gcHJpY2UgY291cG9uIG9yIHVzYWdlIGNyZWRpdC4gYGRldGFpbHNgIGNhcnJ5IHRoZSBkaXNjb3VudCBpZCArIGtpbmQvdmFsdWVcbiAgLy8gb25seSwgbmV2ZXIgdGhlIG9wYXF1ZSB0b2tlbiBvciBzaWduaW5nIGtleS5cbiAgJ2JpbGxpbmcuZGlzY291bnQuZ2VuZXJhdGUnLFxuICAnYmlsbGluZy5kaXNjb3VudC5pc3N1ZScsXG4gICdiaWxsaW5nLmRpc2NvdW50LmFwcGx5JyxcbiAgJ2JpbGxpbmcuZGlzY291bnQucmVtb3ZlJyxcbiAgJ2JpbGxpbmcuZGlzY291bnQucmV2b2tlJyxcbiAgLy8gUHJvbW90aW9ucyAoZG9jcy9iaWxsaW5nLWRpc2NvdW50cy5tZCNwcm9tb3Rpb25zKSDigJQgcnVsZS1kcml2ZW4gYXV0by1ncmFudFxuICAvLyBjYW1wYWlnbnMuIGBkZXRhaWxzYCBjYXJyeSB0aGUgcHJvbW90aW9uIGlkICsgY2VudHMvZXZlbnQgb25seS5cbiAgJ2JpbGxpbmcucHJvbW90aW9uLmNyZWF0ZScsXG4gICdiaWxsaW5nLnByb21vdGlvbi51cGRhdGUnLFxuICAnYmlsbGluZy5wcm9tb3Rpb24ucmV2b2tlJyxcbiAgJ2JpbGxpbmcucHJvbW90aW9uLmdyYW50JyxcbiAgJ2JpbGxpbmcucHJvbW90aW9uLmFjdGl2YXRlJyxcbiAgLy8gVXNhZ2UtY3JlZGl0IHJlYWxpemF0aW9uIOKAlCBhIGN1c3RvbWVyL2NvbXBsaWFuY2UtdmlzaWJsZSByZWNvcmQgb2YgY3JlZGl0XG4gIC8vIG1vdmVtZW50OiBgY29uc3VtZWRgIChNYXJrZXRwbGFjZSBtZXRlcmVkIGRyYXdkb3duKSwgYGV4aGF1c3RlZGAgKGJhbGFuY2UgaGl0XG4gIC8vIHplcm8pLCBhbmQgYSBjb21ibyBlbmRpbmcuIGBkZXRhaWxzYCBjYXJyeSBjZW50cy9pZHMgb25seSwgbm8gcGF5bWVudCBzZWNyZXRzLlxuICAnYmlsbGluZy5jcmVkaXQuY29uc3VtZWQnLFxuICAnYmlsbGluZy5jcmVkaXQuZXhoYXVzdGVkJyxcbiAgJ2JpbGxpbmcuY29tYm8uZXhwaXJlZCcsXG4gIC8vIFJlcG9ydGluZyAoYXBpL3JlcG9ydGluZykg4oCUIHRoZSB0aHJlZSByZXBvcnRpbmcgbXV0YXRpb25zIHdob3NlIGVmZmVjdFxuICAvLyBvdXRsaXZlcyBhIHJlcXVlc3QgbG9nOiB0aGUgcGVyLW9yZyBjb3JyZWxhdGlvbi13aW5kb3cgY29uZmlnIHdyaXRlLCBhXG4gIC8vIHBvc3QtZGVwbG95IG91dGNvbWUgbWFya2VyIChpdCBtb3ZlcyB0aGUgb3JnJ3MgRE9SQSBDRlIvTVRUUiksIGFuZCB0aGVcbiAgLy8gaW5ib3VuZCBiaWxsaW5n4oaScmVwb3J0aW5nIHJldGVudGlvbi1lbnRpdGxlbWVudCBzeW5jIChhIHJldGVudGlvbiBjdXQgaXMgYVxuICAvLyBkYXRhLWRlc3Ryb3lpbmcgY2hhbmdlIGFwcGxpZWQgYnkgdGhlIG5leHQgc3dlZXApLiBgZGV0YWlsc2AgY2FycnkgdGhlXG4gIC8vIHNldHRpbmdzL291dGNvbWUgdmFsdWVzIG9ubHkuXG4gICdyZXBvcnRpbmcuc2V0dGluZ3MudXBkYXRlJyxcbiAgJ3JlcG9ydGluZy5kZXBsb3ltZW50Lm91dGNvbWUnLFxuICAncmVwb3J0aW5nLnJldGVudGlvbi5zeW5jJyxcbiAgLy8gRGVuaWVkIGF1dGhvcml6YXRpb24gYXR0ZW1wdCDigJQgZW1pdHRlZCBiZXN0LWVmZm9ydCBieSB0aGUgc2hhcmVkXG4gIC8vIGByZXF1aXJlUGVybWlzc2lvbmAgLyBgcmVxdWlyZVN5c3RlbUFkbWluYCBnYXRlIHdoZW4gYSBzdGF0ZS1jaGFuZ2luZ1xuICAvLyAobm9uLUdFVCkgcmVxdWVzdCBpcyByZWplY3RlZCwgc28gcHJvYmluZy9lc2NhbGF0aW9uIGF0dGVtcHRzIGFyZSB2aXNpYmxlXG4gIC8vIHJhdGhlciB0aGFuIGludmlzaWJsZS4gYGRldGFpbHNgIGNhcnJpZXMgdGhlIHJlcXVpcmVkIHBlcm1pc3Npb24gKyBwYXRoO1xuICAvLyBgb3V0Y29tZWAgaXMgJ2ZhaWx1cmUnLlxuICAnYXV0aHouZGVuaWVkJyxcbiAgLy8gXCJBc2tcIiBhc3Npc3RhbnQgYWN0aXZpdHkg4oCUIHZpc2liaWxpdHkgaW50byB3aGF0IHRoZSBhc3Npc3RhbnQgZGlkIG9uIGEgdXNlcidzXG4gIC8vIGJlaGFsZi4gYGFzay5xdWVyeWAgaXMgYSByZWFkLW9ubHkgaG93LXRvIHR1cm47IGBhc2suYWdlbnQudHVybmAgaXMgYSB0b29sLWNhbGxpbmdcbiAgLy8gdHVybi4gYGRldGFpbHNgIGNhcnJ5IFNBRkUgTUVUQURBVEEgT05MWSAodG9vbHMgdXNlZCwgcHJvcG9zYWwga2luZHMsIHF1ZXJ5XG4gIC8vIGxlbmd0aCwgb3V0Y29tZSksIG5ldmVyIHRoZSByYXcgcXVlcnkgdGV4dC5cbiAgJ2Fzay5xdWVyeScsXG4gICdhc2suYWdlbnQudHVybicsXG4gIC8vIFBsdWdpbiBlY29zeXN0ZW0gKGRvY3MvcnVuYm9va3MvZWNvc3lzdGVtLW1vZGVyYXRpb24ubWQpLiBHb3Zlcm5hbmNlIGFjdGlvbnNcbiAgLy8gYXJlIHJlY29yZGVkIHdpdGggYG9yZ0lkYCA9IHRoZSBzeXN0ZW0gb3JnOyBgYWZmZWN0ZWRPcmdJZGAgaXMgdGhlXG4gIC8vIHB1Ymxpc2hlcidzIG9yZyAobGlzdGluZy92ZXJzaW9uL3Jldmlldy9hZHZpc29yeS9wdWJsaXNoZXIgbW9kZXJhdGlvbikgb3JcbiAgLy8gdGhlIGluc3RhbGxpbmcgb3JnIChpbnN0YWxscyArIHBvbGljeSkuIEFub255bW91cyBzdWJtaXNzaW9ucyB1c2UgdGhlXG4gIC8vIGBBTk9OWU1PVVNfQUNUT1JfSURgIGFjdG9yIHdpdGggYGRldGFpbHMuc3VibWlzc2lvbklkYC4gYGRldGFpbHNgIGNhcnJ5IGlkcyxcbiAgLy8gdmVyc2lvbnMsIGRpZ2VzdHMsIHRpZXIsIHN0YXRlIGFuZCByZWFzb24gY29kZXMgb25seSDigJQgbmV2ZXIgcmV2aWV3IGJvZGllcyxcbiAgLy8gUkVBRE1FIGNvbnRlbnQsIHNlY3JldHMgb3IgZW1haWxzLlxuICAvLyBQdWJsaXNoZXJzLlxuICAncHVibGlzaGVyLmNyZWF0ZScsXG4gICdwdWJsaXNoZXIudXBkYXRlJyxcbiAgJ3B1Ymxpc2hlci50ZXJtcy5hY2NlcHQnLFxuICAncHVibGlzaGVyLnZlcmlmeS5yZXF1ZXN0JyxcbiAgJ3B1Ymxpc2hlci52ZXJpZnkuYXBwcm92ZScsXG4gICdwdWJsaXNoZXIudmVyaWZ5LnJlamVjdCcsXG4gICdwdWJsaXNoZXIudGllci5jaGFuZ2UnLFxuICAncHVibGlzaGVyLnN1c3BlbmQnLFxuICAncHVibGlzaGVyLnVuc3VzcGVuZCcsXG4gICdwdWJsaXNoZXIudHJhbnNmZXIucmVxdWVzdCcsXG4gICdwdWJsaXNoZXIudHJhbnNmZXIuYWNjZXB0JyxcbiAgJ3B1Ymxpc2hlci50cmFuc2Zlci5kZWNsaW5lJyxcbiAgJ3B1Ymxpc2hlci50cmFuc2Zlci5hcHByb3ZlJyxcbiAgJ3B1Ymxpc2hlci50cmFuc2Zlci5yZWplY3QnLFxuICAncHVibGlzaGVyLnByb2ZpbGUtY2hhbmdlLmFwcHJvdmUnLFxuICAncHVibGlzaGVyLnByb2ZpbGUtY2hhbmdlLnJlamVjdCcsXG4gIC8vIFB1Ymxpc2ggcmVxdWVzdHMgKHRlbmFudCDihpIgc3lzdGVtIG9yZykuIGBkZXRhaWxzLmtpbmRgIG5hbWVzIHRoZSByZXF1ZXN0LlxuICAncGx1Z2luLnJlcXVlc3Quc3VibWl0JyxcbiAgJ3BsdWdpbi5yZXF1ZXN0LndpdGhkcmF3JyxcbiAgJ3BsdWdpbi5yZXF1ZXN0LmFwcHJvdmUnLFxuICAncGx1Z2luLnJlcXVlc3Quc2Vjb25kLWFwcHJvdmUnLFxuICAncGx1Z2luLnJlcXVlc3QucmVqZWN0JyxcbiAgJ3BsdWdpbi5yZXF1ZXN0LmF1dG8tYXBwcm92ZScsXG4gIC8vIExpc3RpbmdzIGFuZCB2ZXJzaW9ucyAoc3lzdGVtIG9yZywgZXhjZXB0IHRoZSB0ZW5hbnQgcGF1c2UpLlxuICAncGx1Z2luLmxpc3RpbmcucHVibGlzaCcsXG4gICdwbHVnaW4ubGlzdGluZy51bmxpc3QnLFxuICAncGx1Z2luLmxpc3RpbmcudXBkYXRlJyxcbiAgJ3BsdWdpbi5saXN0aW5nLnN0YXRlLmNoYW5nZScsXG4gICdwbHVnaW4ubGlzdGluZy5wYXVzZScsXG4gICdwbHVnaW4ubGlzdGluZy51bnBhdXNlJyxcbiAgJ3BsdWdpbi52ZXJzaW9uLnBhdXNlJyxcbiAgJ3BsdWdpbi52ZXJzaW9uLnlhbmsnLFxuICAncGx1Z2luLnZlcnNpb24udW55YW5rJyxcbiAgJ3BsdWdpbi52ZXJzaW9uLmRlcHJlY2F0ZScsXG4gICdwbHVnaW4uY29sbGVjdGlvbi51cGRhdGUnLFxuICAvLyBFY29zeXN0ZW0gY29uZmlndXJhdGlvbiAoc3lzdGVtIG9yZykuXG4gICdlY29zeXN0ZW0uYXV0by1hcHByb3ZhbC1ydWxlLmNyZWF0ZScsXG4gICdlY29zeXN0ZW0uYXV0by1hcHByb3ZhbC1ydWxlLnVwZGF0ZScsXG4gICdlY29zeXN0ZW0uYXV0by1hcHByb3ZhbC1ydWxlLmRlbGV0ZScsXG4gICdlY29zeXN0ZW0ucmVzZXJ2ZWQtbmFtZS51cGRhdGUnLFxuICAnZWNvc3lzdGVtLnNsYS51cGRhdGUnLFxuICAvLyBQdWJsaWMgcmVnaXN0cnkgbmFtZXNwYWNlIChgcHVibGljLypgKTogY29weSArIHNpZ24gKyBhdHRlc3Qgb24gcHVibGlzaCxcbiAgLy8gdGhlIHRpZXItY2hhbmdlL3N1c3BlbnNpb24gcmUtc2lnbiBqb2IsIHRhZyByZW1vdmFsIG9uIHlhbmsvdGFrZWRvd24sIGFuZFxuICAvLyB0aGUgcmV0ZW50aW9uIHN3ZWVwLlxuICAncmVnaXN0cnkuaW1hZ2UucHVibGlzaCcsXG4gICdyZWdpc3RyeS5pbWFnZS5yZXNpZ24nLFxuICAncmVnaXN0cnkuaW1hZ2UueWFuaycsXG4gICdyZWdpc3RyeS5pbWFnZS5nYycsXG4gIC8vIEluc3RhbGxzIGFuZCB0aGUgaW5zdGFsbGluZyBvcmcncyBjb25zdW1wdGlvbiBwb2xpY3kgKG9yZy1sb2NhbCkuXG4gICdwbHVnaW4uaW5zdGFsbC5yZXF1ZXN0JyxcbiAgJ3BsdWdpbi5pbnN0YWxsLmFwcHJvdmUnLFxuICAncGx1Z2luLmluc3RhbGwuZGVueScsXG4gICdwbHVnaW4uaW5zdGFsbC5jcmVhdGUnLFxuICAncGx1Z2luLmluc3RhbGwudXBncmFkZScsXG4gIC8vIEEgbWVtYmVyJ3MgcmVxdWVzdCB0byBjaGFuZ2UgYW4gaW5zdGFsbCBwYXN0IHdoYXQgdGhleSBtYXkgZG8gYWxvbmUsIGFuZCBpdHMgZGVjaXNpb24uXG4gICdwbHVnaW4uaW5zdGFsbC5jaGFuZ2UtcmVxdWVzdCcsXG4gICdwbHVnaW4uaW5zdGFsbC5jaGFuZ2UtYXBwcm92ZScsXG4gICdwbHVnaW4uaW5zdGFsbC5jaGFuZ2UtcmVqZWN0JyxcbiAgJ3BsdWdpbi5pbnN0YWxsLnJlbW92ZScsXG4gICdvcmcucGx1Z2luLWluc3RhbGwtcG9saWN5LnVwZGF0ZScsXG4gIC8vIFJldmlld3MgYW5kIHJlcGxpZXMuXG4gICdwbHVnaW4ucmV2aWV3LmNyZWF0ZScsXG4gICdwbHVnaW4ucmV2aWV3LnVwZGF0ZScsXG4gICdwbHVnaW4ucmV2aWV3LmRlbGV0ZScsXG4gICdwbHVnaW4ucmV2aWV3LnJlcG9ydCcsXG4gICdwbHVnaW4ucmV2aWV3LmhvbGQnLFxuICAncGx1Z2luLnJldmlldy5yZWxlYXNlJyxcbiAgJ3BsdWdpbi5yZXZpZXcucmVtb3ZlJyxcbiAgJ3BsdWdpbi5yZXZpZXcuYW5vbnltaXplJyxcbiAgJ3BsdWdpbi5yZXZpZXcucmVwbHkuY3JlYXRlJyxcbiAgJ3BsdWdpbi5yZXZpZXcucmVwbHkudXBkYXRlJyxcbiAgJ3BsdWdpbi5yZXZpZXcucmVwbHkuZGVsZXRlJyxcbiAgLy8gQW5vbnltb3VzIHN1Ym1pc3Npb25zLlxuICAncGx1Z2luLnN1Ym1pc3Npb24uY3JlYXRlJyxcbiAgJ3BsdWdpbi5zdWJtaXNzaW9uLnZlcmlmeScsXG4gICdwbHVnaW4uc3VibWlzc2lvbi5nYXRlLWZhaWwnLFxuICAncGx1Z2luLnN1Ym1pc3Npb24uYXBwcm92ZScsXG4gICdwbHVnaW4uc3VibWlzc2lvbi5yZWplY3QnLFxuICAncGx1Z2luLnN1Ym1pc3Npb24uY2xhaW0nLFxuICAncGx1Z2luLnN1Ym1pc3Npb24uZXhwaXJlJyxcbiAgLy8gU2VjdXJpdHkgYWR2aXNvcmllcyAocHVibGlzaC93aXRoZHJhdyBhcmUgc3lzdGVtLW9yZyBvbmx5OyB1cGRhdGUgPSBhXG4gIC8vIG1vZGVyYXRvciBlZGl0aW5nIGEgZHJhZnQgYmVmb3JlIGl0IGlzIHB1Ymxpc2hlZCkuXG4gICdwbHVnaW4uYWR2aXNvcnkuY3JlYXRlJyxcbiAgJ3BsdWdpbi5hZHZpc29yeS51cGRhdGUnLFxuICAncGx1Z2luLmFkdmlzb3J5LnB1Ymxpc2gnLFxuICAncGx1Z2luLmFkdmlzb3J5LndpdGhkcmF3JyxcbiAgLy8gUGVyLW9yZyBwbHVnaW4gc2VjdXJpdHkgbm90aWZpY2F0aW9ucyAocGx1Z2luIHNjYW4gZ2F0ZXMpOiB0aGUgc2V0dGluZ3NcbiAgLy8gKHJlY2lwaWVudHMsIGRpZ2VzdCwgd2ViaG9vaywgZXh0ZXJuYWwgYWRkcmVzcyDigJQgY2hhbmdlZCBmaWVsZCBuYW1lcyBhbmRcbiAgLy8gdGhlIHdlYmhvb2sgaG9zdCBvbmx5LCBuZXZlciB0aGUgc2VjcmV0IG9yIHRoZSBhZGRyZXNzKSwgYW4gZXh0ZXJuYWxcbiAgLy8gYWRkcmVzcyBjb25maXJtZWQgdGhyb3VnaCBpdHMgZW1haWxlZCBzaW5nbGUtdXNlIGxpbmssIGFuZCBhIHRlc3Qgc2VuZC5cbiAgJ3BsdWdpbi5zZWN1cml0eV9ub3RpZmljYXRpb25zLnVwZGF0ZScsXG4gICdwbHVnaW4uc2VjdXJpdHlfbm90aWZpY2F0aW9ucy5leHRlcm5hbF9lbWFpbC52ZXJpZnknLFxuICAncGx1Z2luLnNlY3VyaXR5X25vdGlmaWNhdGlvbnMudGVzdCcsXG5dIGFzIGNvbnN0O1xuXG5leHBvcnQgdHlwZSBSZW1vdGVBdWRpdEFjdGlvbiA9IHR5cGVvZiBSRU1PVEVfQVVESVRfQUNUSU9OU1tudW1iZXJdO1xuXG4vKiogV2hldGhlciBgdmFsdWVgIGlzIGFuIGFjdGlvbiBhIHJlbW90ZSBzZXJ2aWNlIG1heSBlbWl0ICh0aGUgaW5nZXN0IGFsbG93LWxpc3QpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUmVtb3RlQXVkaXRBY3Rpb24odmFsdWU6IHN0cmluZyk6IHZhbHVlIGlzIFJlbW90ZUF1ZGl0QWN0aW9uIHtcbiAgcmV0dXJuIChSRU1PVEVfQVVESVRfQUNUSU9OUyBhcyByZWFkb25seSBzdHJpbmdbXSkuaW5jbHVkZXModmFsdWUpO1xufVxuIl19
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Date coercions for the JSON boundary. */
|
|
2
|
+
/**
|
|
3
|
+
* A nullable timestamp as an ISO-8601 string, or `null` when there is no date.
|
|
4
|
+
*
|
|
5
|
+
* The shape every API response needs at the DB→JSON boundary: Postgres and
|
|
6
|
+
* Mongo hand back `Date | null`, the wire wants `string | null`, and a bare
|
|
7
|
+
* `row.x?.toISOString() ?? null` breaks the moment the driver returns a string
|
|
8
|
+
* instead (Mongo aggregation output, a `::text` cast, a cached row rehydrated
|
|
9
|
+
* from JSON). Normalizing through `new Date(d)` handles both.
|
|
10
|
+
*
|
|
11
|
+
* Falsy in, `null` out — which folds the epoch (`new Date(0)`) to `null` too.
|
|
12
|
+
* That is intentional and matches every hand-rolled copy this replaces: a
|
|
13
|
+
* zero timestamp in this codebase means "unset", never 1970.
|
|
14
|
+
*
|
|
15
|
+
* Throws `RangeError` on an unparseable string, deliberately: a malformed
|
|
16
|
+
* timestamp is a data-integrity problem, and silently serving `null` for it
|
|
17
|
+
* would hide a corrupt row behind a plausible-looking response.
|
|
18
|
+
*/
|
|
19
|
+
export declare const isoOrNull: (d: Date | string | number | null | undefined) => string | null;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/** Date coercions for the JSON boundary. */
|
|
4
|
+
/**
|
|
5
|
+
* A nullable timestamp as an ISO-8601 string, or `null` when there is no date.
|
|
6
|
+
*
|
|
7
|
+
* The shape every API response needs at the DB→JSON boundary: Postgres and
|
|
8
|
+
* Mongo hand back `Date | null`, the wire wants `string | null`, and a bare
|
|
9
|
+
* `row.x?.toISOString() ?? null` breaks the moment the driver returns a string
|
|
10
|
+
* instead (Mongo aggregation output, a `::text` cast, a cached row rehydrated
|
|
11
|
+
* from JSON). Normalizing through `new Date(d)` handles both.
|
|
12
|
+
*
|
|
13
|
+
* Falsy in, `null` out — which folds the epoch (`new Date(0)`) to `null` too.
|
|
14
|
+
* That is intentional and matches every hand-rolled copy this replaces: a
|
|
15
|
+
* zero timestamp in this codebase means "unset", never 1970.
|
|
16
|
+
*
|
|
17
|
+
* Throws `RangeError` on an unparseable string, deliberately: a malformed
|
|
18
|
+
* timestamp is a data-integrity problem, and silently serving `null` for it
|
|
19
|
+
* would hide a corrupt row behind a plausible-looking response.
|
|
20
|
+
*/
|
|
21
|
+
export const isoOrNull = (d) => (d ? new Date(d).toISOString() : null);
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9kYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsNENBQTRDO0FBRTVDOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBNEMsRUFBaUIsRUFBRSxDQUN2RixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKiBEYXRlIGNvZXJjaW9ucyBmb3IgdGhlIEpTT04gYm91bmRhcnkuICovXG5cbi8qKlxuICogQSBudWxsYWJsZSB0aW1lc3RhbXAgYXMgYW4gSVNPLTg2MDEgc3RyaW5nLCBvciBgbnVsbGAgd2hlbiB0aGVyZSBpcyBubyBkYXRlLlxuICpcbiAqIFRoZSBzaGFwZSBldmVyeSBBUEkgcmVzcG9uc2UgbmVlZHMgYXQgdGhlIERC4oaSSlNPTiBib3VuZGFyeTogUG9zdGdyZXMgYW5kXG4gKiBNb25nbyBoYW5kIGJhY2sgYERhdGUgfCBudWxsYCwgdGhlIHdpcmUgd2FudHMgYHN0cmluZyB8IG51bGxgLCBhbmQgYSBiYXJlXG4gKiBgcm93Lng/LnRvSVNPU3RyaW5nKCkgPz8gbnVsbGAgYnJlYWtzIHRoZSBtb21lbnQgdGhlIGRyaXZlciByZXR1cm5zIGEgc3RyaW5nXG4gKiBpbnN0ZWFkIChNb25nbyBhZ2dyZWdhdGlvbiBvdXRwdXQsIGEgYDo6dGV4dGAgY2FzdCwgYSBjYWNoZWQgcm93IHJlaHlkcmF0ZWRcbiAqIGZyb20gSlNPTikuIE5vcm1hbGl6aW5nIHRocm91Z2ggYG5ldyBEYXRlKGQpYCBoYW5kbGVzIGJvdGguXG4gKlxuICogRmFsc3kgaW4sIGBudWxsYCBvdXQg4oCUIHdoaWNoIGZvbGRzIHRoZSBlcG9jaCAoYG5ldyBEYXRlKDApYCkgdG8gYG51bGxgIHRvby5cbiAqIFRoYXQgaXMgaW50ZW50aW9uYWwgYW5kIG1hdGNoZXMgZXZlcnkgaGFuZC1yb2xsZWQgY29weSB0aGlzIHJlcGxhY2VzOiBhXG4gKiB6ZXJvIHRpbWVzdGFtcCBpbiB0aGlzIGNvZGViYXNlIG1lYW5zIFwidW5zZXRcIiwgbmV2ZXIgMTk3MC5cbiAqXG4gKiBUaHJvd3MgYFJhbmdlRXJyb3JgIG9uIGFuIHVucGFyc2VhYmxlIHN0cmluZywgZGVsaWJlcmF0ZWx5OiBhIG1hbGZvcm1lZFxuICogdGltZXN0YW1wIGlzIGEgZGF0YS1pbnRlZ3JpdHkgcHJvYmxlbSwgYW5kIHNpbGVudGx5IHNlcnZpbmcgYG51bGxgIGZvciBpdFxuICogd291bGQgaGlkZSBhIGNvcnJ1cHQgcm93IGJlaGluZCBhIHBsYXVzaWJsZS1sb29raW5nIHJlc3BvbnNlLlxuICovXG5leHBvcnQgY29uc3QgaXNvT3JOdWxsID0gKGQ6IERhdGUgfCBzdHJpbmcgfCBudW1iZXIgfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgbnVsbCA9PlxuICAoZCA/IG5ldyBEYXRlKGQpLnRvSVNPU3RyaW5nKCkgOiBudWxsKTtcbiJdfQ==
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSSE-envelope parsing for cosign attestation output.
|
|
3
|
+
*
|
|
4
|
+
* `cosign verify-attestation` prints one DSSE envelope per VERIFIED attestation,
|
|
5
|
+
* one JSON object per line:
|
|
6
|
+
* `{ payloadType, payload: base64(in-toto statement), signatures }`.
|
|
7
|
+
* Signature verification has already happened in cosign by the time we see this
|
|
8
|
+
* — this module only decodes what cosign vouched for.
|
|
9
|
+
*
|
|
10
|
+
* This lives in api-core because BOTH the plugin service (build-time SBOM read)
|
|
11
|
+
* and the image-registry service (registry-side signed-SBOM read) parse the same
|
|
12
|
+
* output. Two hand-copied parse loops in supply-chain verification code is a
|
|
13
|
+
* security risk, not untidiness: a fix applied to one copy silently leaves the
|
|
14
|
+
* other accepting what it should not.
|
|
15
|
+
*
|
|
16
|
+
* Callers keep their OWN not-found policy on top (throw vs. return null) —
|
|
17
|
+
* that is a per-service decision, the parse is not.
|
|
18
|
+
*/
|
|
19
|
+
/** in-toto predicate type for an SPDX SBOM, as cosign's `--type spdxjson` emits. */
|
|
20
|
+
export declare const SPDX_PREDICATE_TYPE = "https://spdx.dev/Document";
|
|
21
|
+
/**
|
|
22
|
+
* Return the predicate of the LAST envelope in `stdout` whose in-toto statement
|
|
23
|
+
* carries `predicateType`, or null when none does.
|
|
24
|
+
*
|
|
25
|
+
* LAST, not first: a rebuild re-attests the same digest and cosign lists
|
|
26
|
+
* attestations oldest-first, so the newest attestation is the final line.
|
|
27
|
+
*
|
|
28
|
+
* Lines that are not parseable envelopes are skipped rather than fatal — cosign
|
|
29
|
+
* prints nothing else on stdout today, but stray output must not turn a valid
|
|
30
|
+
* attestation into a verification failure.
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractPredicate(stdout: string, predicateType: string): Record<string, unknown> | null;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* DSSE-envelope parsing for cosign attestation output.
|
|
5
|
+
*
|
|
6
|
+
* `cosign verify-attestation` prints one DSSE envelope per VERIFIED attestation,
|
|
7
|
+
* one JSON object per line:
|
|
8
|
+
* `{ payloadType, payload: base64(in-toto statement), signatures }`.
|
|
9
|
+
* Signature verification has already happened in cosign by the time we see this
|
|
10
|
+
* — this module only decodes what cosign vouched for.
|
|
11
|
+
*
|
|
12
|
+
* This lives in api-core because BOTH the plugin service (build-time SBOM read)
|
|
13
|
+
* and the image-registry service (registry-side signed-SBOM read) parse the same
|
|
14
|
+
* output. Two hand-copied parse loops in supply-chain verification code is a
|
|
15
|
+
* security risk, not untidiness: a fix applied to one copy silently leaves the
|
|
16
|
+
* other accepting what it should not.
|
|
17
|
+
*
|
|
18
|
+
* Callers keep their OWN not-found policy on top (throw vs. return null) —
|
|
19
|
+
* that is a per-service decision, the parse is not.
|
|
20
|
+
*/
|
|
21
|
+
/** in-toto predicate type for an SPDX SBOM, as cosign's `--type spdxjson` emits. */
|
|
22
|
+
export const SPDX_PREDICATE_TYPE = 'https://spdx.dev/Document';
|
|
23
|
+
/**
|
|
24
|
+
* Return the predicate of the LAST envelope in `stdout` whose in-toto statement
|
|
25
|
+
* carries `predicateType`, or null when none does.
|
|
26
|
+
*
|
|
27
|
+
* LAST, not first: a rebuild re-attests the same digest and cosign lists
|
|
28
|
+
* attestations oldest-first, so the newest attestation is the final line.
|
|
29
|
+
*
|
|
30
|
+
* Lines that are not parseable envelopes are skipped rather than fatal — cosign
|
|
31
|
+
* prints nothing else on stdout today, but stray output must not turn a valid
|
|
32
|
+
* attestation into a verification failure.
|
|
33
|
+
*/
|
|
34
|
+
export function extractPredicate(stdout, predicateType) {
|
|
35
|
+
let predicate = null;
|
|
36
|
+
for (const line of stdout.split('\n')) {
|
|
37
|
+
const trimmed = line.trim();
|
|
38
|
+
if (!trimmed.startsWith('{'))
|
|
39
|
+
continue;
|
|
40
|
+
try {
|
|
41
|
+
const envelope = JSON.parse(trimmed);
|
|
42
|
+
if (!envelope.payload)
|
|
43
|
+
continue;
|
|
44
|
+
const statement = JSON.parse(Buffer.from(envelope.payload, 'base64').toString('utf-8'));
|
|
45
|
+
if (statement.predicateType === predicateType && statement.predicate && typeof statement.predicate === 'object') {
|
|
46
|
+
predicate = statement.predicate;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Not an envelope line.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return predicate;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHNzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9kc3NlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBRUgsb0ZBQW9GO0FBQ3BGLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLDJCQUEyQixDQUFDO0FBRS9EOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsTUFBYyxFQUFFLGFBQXFCO0lBQ3BFLElBQUksU0FBUyxHQUFtQyxJQUFJLENBQUM7SUFDckQsS0FBSyxNQUFNLElBQUksSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDdEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzVCLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztZQUFFLFNBQVM7UUFDdkMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQXlCLENBQUM7WUFDN0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPO2dCQUFFLFNBQVM7WUFDaEMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUdyRixDQUFDO1lBQ0YsSUFBSSxTQUFTLENBQUMsYUFBYSxLQUFLLGFBQWEsSUFBSSxTQUFTLENBQUMsU0FBUyxJQUFJLE9BQU8sU0FBUyxDQUFDLFNBQVMsS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDaEgsU0FBUyxHQUFHLFNBQVMsQ0FBQyxTQUFvQyxDQUFDO1lBQzdELENBQUM7UUFDSCxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1Asd0JBQXdCO1FBQzFCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIERTU0UtZW52ZWxvcGUgcGFyc2luZyBmb3IgY29zaWduIGF0dGVzdGF0aW9uIG91dHB1dC5cbiAqXG4gKiBgY29zaWduIHZlcmlmeS1hdHRlc3RhdGlvbmAgcHJpbnRzIG9uZSBEU1NFIGVudmVsb3BlIHBlciBWRVJJRklFRCBhdHRlc3RhdGlvbixcbiAqIG9uZSBKU09OIG9iamVjdCBwZXIgbGluZTpcbiAqIGB7IHBheWxvYWRUeXBlLCBwYXlsb2FkOiBiYXNlNjQoaW4tdG90byBzdGF0ZW1lbnQpLCBzaWduYXR1cmVzIH1gLlxuICogU2lnbmF0dXJlIHZlcmlmaWNhdGlvbiBoYXMgYWxyZWFkeSBoYXBwZW5lZCBpbiBjb3NpZ24gYnkgdGhlIHRpbWUgd2Ugc2VlIHRoaXNcbiAqIOKAlCB0aGlzIG1vZHVsZSBvbmx5IGRlY29kZXMgd2hhdCBjb3NpZ24gdm91Y2hlZCBmb3IuXG4gKlxuICogVGhpcyBsaXZlcyBpbiBhcGktY29yZSBiZWNhdXNlIEJPVEggdGhlIHBsdWdpbiBzZXJ2aWNlIChidWlsZC10aW1lIFNCT00gcmVhZClcbiAqIGFuZCB0aGUgaW1hZ2UtcmVnaXN0cnkgc2VydmljZSAocmVnaXN0cnktc2lkZSBzaWduZWQtU0JPTSByZWFkKSBwYXJzZSB0aGUgc2FtZVxuICogb3V0cHV0LiBUd28gaGFuZC1jb3BpZWQgcGFyc2UgbG9vcHMgaW4gc3VwcGx5LWNoYWluIHZlcmlmaWNhdGlvbiBjb2RlIGlzIGFcbiAqIHNlY3VyaXR5IHJpc2ssIG5vdCB1bnRpZGluZXNzOiBhIGZpeCBhcHBsaWVkIHRvIG9uZSBjb3B5IHNpbGVudGx5IGxlYXZlcyB0aGVcbiAqIG90aGVyIGFjY2VwdGluZyB3aGF0IGl0IHNob3VsZCBub3QuXG4gKlxuICogQ2FsbGVycyBrZWVwIHRoZWlyIE9XTiBub3QtZm91bmQgcG9saWN5IG9uIHRvcCAodGhyb3cgdnMuIHJldHVybiBudWxsKSDigJRcbiAqIHRoYXQgaXMgYSBwZXItc2VydmljZSBkZWNpc2lvbiwgdGhlIHBhcnNlIGlzIG5vdC5cbiAqL1xuXG4vKiogaW4tdG90byBwcmVkaWNhdGUgdHlwZSBmb3IgYW4gU1BEWCBTQk9NLCBhcyBjb3NpZ24ncyBgLS10eXBlIHNwZHhqc29uYCBlbWl0cy4gKi9cbmV4cG9ydCBjb25zdCBTUERYX1BSRURJQ0FURV9UWVBFID0gJ2h0dHBzOi8vc3BkeC5kZXYvRG9jdW1lbnQnO1xuXG4vKipcbiAqIFJldHVybiB0aGUgcHJlZGljYXRlIG9mIHRoZSBMQVNUIGVudmVsb3BlIGluIGBzdGRvdXRgIHdob3NlIGluLXRvdG8gc3RhdGVtZW50XG4gKiBjYXJyaWVzIGBwcmVkaWNhdGVUeXBlYCwgb3IgbnVsbCB3aGVuIG5vbmUgZG9lcy5cbiAqXG4gKiBMQVNULCBub3QgZmlyc3Q6IGEgcmVidWlsZCByZS1hdHRlc3RzIHRoZSBzYW1lIGRpZ2VzdCBhbmQgY29zaWduIGxpc3RzXG4gKiBhdHRlc3RhdGlvbnMgb2xkZXN0LWZpcnN0LCBzbyB0aGUgbmV3ZXN0IGF0dGVzdGF0aW9uIGlzIHRoZSBmaW5hbCBsaW5lLlxuICpcbiAqIExpbmVzIHRoYXQgYXJlIG5vdCBwYXJzZWFibGUgZW52ZWxvcGVzIGFyZSBza2lwcGVkIHJhdGhlciB0aGFuIGZhdGFsIOKAlCBjb3NpZ25cbiAqIHByaW50cyBub3RoaW5nIGVsc2Ugb24gc3Rkb3V0IHRvZGF5LCBidXQgc3RyYXkgb3V0cHV0IG11c3Qgbm90IHR1cm4gYSB2YWxpZFxuICogYXR0ZXN0YXRpb24gaW50byBhIHZlcmlmaWNhdGlvbiBmYWlsdXJlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFByZWRpY2F0ZShzdGRvdXQ6IHN0cmluZywgcHJlZGljYXRlVHlwZTogc3RyaW5nKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsIHtcbiAgbGV0IHByZWRpY2F0ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsID0gbnVsbDtcbiAgZm9yIChjb25zdCBsaW5lIG9mIHN0ZG91dC5zcGxpdCgnXFxuJykpIHtcbiAgICBjb25zdCB0cmltbWVkID0gbGluZS50cmltKCk7XG4gICAgaWYgKCF0cmltbWVkLnN0YXJ0c1dpdGgoJ3snKSkgY29udGludWU7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGVudmVsb3BlID0gSlNPTi5wYXJzZSh0cmltbWVkKSBhcyB7IHBheWxvYWQ/OiBzdHJpbmcgfTtcbiAgICAgIGlmICghZW52ZWxvcGUucGF5bG9hZCkgY29udGludWU7XG4gICAgICBjb25zdCBzdGF0ZW1lbnQgPSBKU09OLnBhcnNlKEJ1ZmZlci5mcm9tKGVudmVsb3BlLnBheWxvYWQsICdiYXNlNjQnKS50b1N0cmluZygndXRmLTgnKSkgYXMge1xuICAgICAgICBwcmVkaWNhdGVUeXBlPzogc3RyaW5nO1xuICAgICAgICBwcmVkaWNhdGU/OiB1bmtub3duO1xuICAgICAgfTtcbiAgICAgIGlmIChzdGF0ZW1lbnQucHJlZGljYXRlVHlwZSA9PT0gcHJlZGljYXRlVHlwZSAmJiBzdGF0ZW1lbnQucHJlZGljYXRlICYmIHR5cGVvZiBzdGF0ZW1lbnQucHJlZGljYXRlID09PSAnb2JqZWN0Jykge1xuICAgICAgICBwcmVkaWNhdGUgPSBzdGF0ZW1lbnQucHJlZGljYXRlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTm90IGFuIGVudmVsb3BlIGxpbmUuXG4gICAgfVxuICB9XG4gIHJldHVybiBwcmVkaWNhdGU7XG59XG4iXX0=
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -3,13 +3,14 @@ export * from './api-key.js';
|
|
|
3
3
|
export * from './safe-require.js';
|
|
4
4
|
export * from './secure-compare.js';
|
|
5
5
|
export * from './crash-handlers.js';
|
|
6
|
-
export { sendSuccess, sendError, sendQuotaExceeded, sendPaginatedNested, extractDbError, errorMessage, sendBadRequest, sendInternalError, parsePaginationParams,
|
|
6
|
+
export { sendSuccess, sendError, sendQuotaExceeded, sendPaginatedNested, paginationMeta, type PaginationMeta, extractDbError, errorMessage, sendBadRequest, sendInternalError, parsePaginationParams, type PaginationParams, type SortParams, } from './response.js';
|
|
7
7
|
export { getParam, parseQueryInt, parseQueryString, parseOptionalDate, parsePositiveInt, parseQueryIntClamped, parsePage, validateBulkArray, parseReportInterval, parseDateRange, type Page, REPORT_INTERVALS, } from './params.js';
|
|
8
8
|
export * from './headers.js';
|
|
9
9
|
export * from './identity.js';
|
|
10
10
|
export { USER_TOKEN_ALGORITHM, USER_TOKEN_CURVE, JWKS_PATH, decodeJwtHeader, isJwksDocument, publicJwkFrom, derToJoseSignature, encodeJwsSigningInput, compactJws, } from './jwk.js';
|
|
11
11
|
export type { PublicJwk, JwksDocument, } from './jwk.js';
|
|
12
12
|
export * from './object.js';
|
|
13
|
+
export * from './date.js';
|
|
13
14
|
export { resetSupportAliasesCache, getPrimarySupportAlias, getAllSupportAliases, resolveRecipientAlias, DEFAULT_SUPPORT_ALIAS, } from './alias-resolver.js';
|
|
14
15
|
export * from './concurrency.js';
|
|
15
16
|
export * from './audit.js';
|
|
@@ -17,6 +18,7 @@ export { getDefaultKeyProvider, resetDefaultKeyProvider, setKeyProvider, encrypt
|
|
|
17
18
|
export * from './secret-rotation.js';
|
|
18
19
|
export { setCounterEmitter, resetCounterEmitter, emitCounter, } from './metric-emitter.js';
|
|
19
20
|
export * from './aws-scrub.js';
|
|
21
|
+
export { extractPredicate, SPDX_PREDICATE_TYPE, } from './dsse.js';
|
|
20
22
|
export { maskLine, looksSensitive, REDACTED, SENSITIVE_VALUE_PATTERNS, } from './sensitive-patterns.js';
|
|
21
23
|
export { isPrivateAddress, assertSafeUrl, safeFetch, type SafeFetchResponse, } from './ssrf.js';
|
|
22
24
|
export * from './env.js';
|
package/lib/utils/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export * from './api-key.js';
|
|
|
5
5
|
export * from './safe-require.js';
|
|
6
6
|
export * from './secure-compare.js';
|
|
7
7
|
export * from './crash-handlers.js';
|
|
8
|
-
export { sendSuccess, sendError, sendQuotaExceeded, sendPaginatedNested, extractDbError, errorMessage, sendBadRequest, sendInternalError, parsePaginationParams,
|
|
8
|
+
export { sendSuccess, sendError, sendQuotaExceeded, sendPaginatedNested, paginationMeta, extractDbError, errorMessage, sendBadRequest, sendInternalError, parsePaginationParams, } from './response.js';
|
|
9
9
|
export { getParam, parseQueryInt, parseQueryString, parseOptionalDate, parsePositiveInt, parseQueryIntClamped, parsePage, validateBulkArray, parseReportInterval, parseDateRange, REPORT_INTERVALS, } from './params.js';
|
|
10
10
|
export * from './headers.js';
|
|
11
11
|
export * from './identity.js';
|
|
@@ -16,6 +16,7 @@ export * from './identity.js';
|
|
|
16
16
|
// leaking them to every service.
|
|
17
17
|
export { USER_TOKEN_ALGORITHM, USER_TOKEN_CURVE, JWKS_PATH, decodeJwtHeader, isJwksDocument, publicJwkFrom, derToJoseSignature, encodeJwsSigningInput, compactJws, } from './jwk.js';
|
|
18
18
|
export * from './object.js';
|
|
19
|
+
export * from './date.js';
|
|
19
20
|
export { resetSupportAliasesCache, getPrimarySupportAlias, getAllSupportAliases, resolveRecipientAlias, DEFAULT_SUPPORT_ALIAS, } from './alias-resolver.js';
|
|
20
21
|
export * from './concurrency.js';
|
|
21
22
|
export * from './audit.js';
|
|
@@ -23,6 +24,7 @@ export { getDefaultKeyProvider, resetDefaultKeyProvider, setKeyProvider, encrypt
|
|
|
23
24
|
export * from './secret-rotation.js';
|
|
24
25
|
export { setCounterEmitter, resetCounterEmitter, emitCounter, } from './metric-emitter.js';
|
|
25
26
|
export * from './aws-scrub.js';
|
|
27
|
+
export { extractPredicate, SPDX_PREDICATE_TYPE, } from './dsse.js';
|
|
26
28
|
export { maskLine, looksSensitive, REDACTED, SENSITIVE_VALUE_PATTERNS, } from './sensitive-patterns.js';
|
|
27
29
|
export { isPrivateAddress, assertSafeUrl, safeFetch, } from './ssrf.js';
|
|
28
30
|
export * from './env.js';
|
|
@@ -30,4 +32,4 @@ export * from './service-registry.js';
|
|
|
30
32
|
export * from './retention.js';
|
|
31
33
|
export * from './compliance-attributes.js';
|
|
32
34
|
export { leadingZeroBits, proofOfWorkHash, challengeKey, clampDifficulty, createProofOfWorkChallenge, parseProofOfWorkChallenge, verifyProofOfWork, solveProofOfWork, POW_DEFAULT_DIFFICULTY, POW_MAX_DIFFICULTY, POW_CHALLENGE_TTL_MS, } from './proof-of-work.js';
|
|
33
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
35
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLGVBQWUsRUFDZixZQUFZLEVBRVosTUFBTSxFQUNOLE9BQU8sR0FDUixNQUFNLGFBQWEsQ0FBQztBQUNyQixjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLFNBQVMsRUFDVCxpQkFBaUIsRUFDakIsbUJBQW1CLEVBQ25CLGNBQWMsRUFFZCxjQUFjLEVBQ2QsWUFBWSxFQUNaLGNBQWMsRUFDZCxpQkFBaUIsRUFDakIscUJBQXFCLEdBR3RCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFDTCxRQUFRLEVBQ1IsYUFBYSxFQUNiLGdCQUFnQixFQUNoQixpQkFBaUIsRUFDakIsZ0JBQWdCLEVBQ2hCLG9CQUFvQixFQUNwQixTQUFTLEVBQ1QsaUJBQWlCLEVBQ2pCLG1CQUFtQixFQUNuQixjQUFjLEVBRWQsZ0JBQWdCLEdBQ2pCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsZUFBZSxDQUFDO0FBQzlCLHlFQUF5RTtBQUN6RSxtRUFBbUU7QUFDbkUseUVBQXlFO0FBQ3pFLDhFQUE4RTtBQUM5RSxpQ0FBaUM7QUFDakMsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixnQkFBZ0IsRUFDaEIsU0FBUyxFQUNULGVBQWUsRUFDZixjQUFjLEVBQ2QsYUFBYSxFQUNiLGtCQUFrQixFQUNsQixxQkFBcUIsRUFDckIsVUFBVSxHQUNYLE1BQU0sVUFBVSxDQUFDO0FBS2xCLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsV0FBVyxDQUFDO0FBQzFCLE9BQU8sRUFDTCx3QkFBd0IsRUFDeEIsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNwQixxQkFBcUIsRUFDckIscUJBQXFCLEdBQ3RCLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLFlBQVksQ0FBQztBQUMzQixPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLHVCQUF1QixFQUN2QixjQUFjLEVBQ2QsYUFBYSxFQUNiLGFBQWEsRUFDYixlQUFlLEVBR2YsY0FBYyxFQUNkLGNBQWMsRUFHZCxvQkFBb0IsR0FDckIsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLE9BQU8sRUFDTCxpQkFBaUIsRUFDakIsbUJBQW1CLEVBQ25CLFdBQVcsR0FDWixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixtQkFBbUIsR0FDcEIsTUFBTSxXQUFXLENBQUM7QUFDbkIsT0FBTyxFQUNMLFFBQVEsRUFDUixjQUFjLEVBQ2QsUUFBUSxFQUNSLHdCQUF3QixHQUN6QixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFDTCxnQkFBZ0IsRUFDaEIsYUFBYSxFQUNiLFNBQVMsR0FFVixNQUFNLFdBQVcsQ0FBQztBQUNuQixjQUFjLFVBQVUsQ0FBQztBQUN6QixjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxPQUFPLEVBQ0wsZUFBZSxFQUNmLGVBQWUsRUFDZixZQUFZLEVBQ1osZUFBZSxFQUNmLDBCQUEwQixFQUMxQix5QkFBeUIsRUFDekIsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQixzQkFBc0IsRUFDdEIsa0JBQWtCLEVBQ2xCLG9CQUFvQixHQUdyQixNQUFNLG9CQUFvQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmV4cG9ydCB7XG4gIHNldExvZ0NvbnRleHRQcm92aWRlcixcbiAgcmVkYWN0U2Vuc2l0aXZlLFxuICBjcmVhdGVMb2dnZXIsXG4gIHR5cGUgTG9nZ2VyLFxuICBsb2dnZXIsXG4gIGRlZmF1bHQsXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vYXBpLWtleS5qcyc7XG5leHBvcnQgKiBmcm9tICcuL3NhZmUtcmVxdWlyZS5qcyc7XG5leHBvcnQgKiBmcm9tICcuL3NlY3VyZS1jb21wYXJlLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vY3Jhc2gtaGFuZGxlcnMuanMnO1xuZXhwb3J0IHtcbiAgc2VuZFN1Y2Nlc3MsXG4gIHNlbmRFcnJvcixcbiAgc2VuZFF1b3RhRXhjZWVkZWQsXG4gIHNlbmRQYWdpbmF0ZWROZXN0ZWQsXG4gIHBhZ2luYXRpb25NZXRhLFxuICB0eXBlIFBhZ2luYXRpb25NZXRhLFxuICBleHRyYWN0RGJFcnJvcixcbiAgZXJyb3JNZXNzYWdlLFxuICBzZW5kQmFkUmVxdWVzdCxcbiAgc2VuZEludGVybmFsRXJyb3IsXG4gIHBhcnNlUGFnaW5hdGlvblBhcmFtcyxcbiAgdHlwZSBQYWdpbmF0aW9uUGFyYW1zLFxuICB0eXBlIFNvcnRQYXJhbXMsXG59IGZyb20gJy4vcmVzcG9uc2UuanMnO1xuZXhwb3J0IHtcbiAgZ2V0UGFyYW0sXG4gIHBhcnNlUXVlcnlJbnQsXG4gIHBhcnNlUXVlcnlTdHJpbmcsXG4gIHBhcnNlT3B0aW9uYWxEYXRlLFxuICBwYXJzZVBvc2l0aXZlSW50LFxuICBwYXJzZVF1ZXJ5SW50Q2xhbXBlZCxcbiAgcGFyc2VQYWdlLFxuICB2YWxpZGF0ZUJ1bGtBcnJheSxcbiAgcGFyc2VSZXBvcnRJbnRlcnZhbCxcbiAgcGFyc2VEYXRlUmFuZ2UsXG4gIHR5cGUgUGFnZSxcbiAgUkVQT1JUX0lOVEVSVkFMUyxcbn0gZnJvbSAnLi9wYXJhbXMuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9oZWFkZXJzLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vaWRlbnRpdHkuanMnO1xuLy8gSldLIHByaW1pdGl2ZXMuIFBsYXRmb3JtIElTIHRoZSB0b2tlbiBzaWduZXIsIHNvIGl0IGxlZ2l0aW1hdGVseSBuZWVkc1xuLy8gYHB1YmxpY0p3a0Zyb21gICsgYGRlclRvSm9zZVNpZ25hdHVyZWAgZnJvbSB0aGUgcGFja2FnZSBzdXJmYWNlLlxuLy8gYGp3a1RodW1icHJpbnRgIGFuZCBgcHVibGljS2V5RnJvbUp3a2AgYXJlIGtpZC1kZXJpdmF0aW9uL3ZlcmlmaWNhdGlvblxuLy8gcGx1bWJpbmcgdXNlZCBvbmx5IGluc2lkZSBhcGktY29yZSDigJQgZGVlcC1pbXBvcnQgdGhlbSBmcm9tIHRoZXJlIGluc3RlYWQgb2Zcbi8vIGxlYWtpbmcgdGhlbSB0byBldmVyeSBzZXJ2aWNlLlxuZXhwb3J0IHtcbiAgVVNFUl9UT0tFTl9BTEdPUklUSE0sXG4gIFVTRVJfVE9LRU5fQ1VSVkUsXG4gIEpXS1NfUEFUSCxcbiAgZGVjb2RlSnd0SGVhZGVyLFxuICBpc0p3a3NEb2N1bWVudCxcbiAgcHVibGljSndrRnJvbSxcbiAgZGVyVG9Kb3NlU2lnbmF0dXJlLFxuICBlbmNvZGVKd3NTaWduaW5nSW5wdXQsXG4gIGNvbXBhY3RKd3MsXG59IGZyb20gJy4vandrLmpzJztcbmV4cG9ydCB0eXBlIHtcbiAgUHVibGljSndrLFxuICBKd2tzRG9jdW1lbnQsXG59IGZyb20gJy4vandrLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vb2JqZWN0LmpzJztcbmV4cG9ydCAqIGZyb20gJy4vZGF0ZS5qcyc7XG5leHBvcnQge1xuICByZXNldFN1cHBvcnRBbGlhc2VzQ2FjaGUsXG4gIGdldFByaW1hcnlTdXBwb3J0QWxpYXMsXG4gIGdldEFsbFN1cHBvcnRBbGlhc2VzLFxuICByZXNvbHZlUmVjaXBpZW50QWxpYXMsXG4gIERFRkFVTFRfU1VQUE9SVF9BTElBUyxcbn0gZnJvbSAnLi9hbGlhcy1yZXNvbHZlci5qcyc7XG5leHBvcnQgKiBmcm9tICcuL2NvbmN1cnJlbmN5LmpzJztcbmV4cG9ydCAqIGZyb20gJy4vYXVkaXQuanMnO1xuZXhwb3J0IHtcbiAgZ2V0RGVmYXVsdEtleVByb3ZpZGVyLFxuICByZXNldERlZmF1bHRLZXlQcm92aWRlcixcbiAgc2V0S2V5UHJvdmlkZXIsXG4gIGVuY3J5cHRTZWNyZXQsXG4gIGRlY3J5cHRTZWNyZXQsXG4gIGlzRW5jcnlwdGVkQmxvYixcbiAgdHlwZSBFbmNyeXB0ZWRCbG9iLFxuICB0eXBlIEtleVByb3ZpZGVyLFxuICBFbnZLZXlQcm92aWRlcixcbiAgS21zS2V5UHJvdmlkZXIsXG4gIHR5cGUgUGVyT3JnS21zQ29uZmlnLFxuICB0eXBlIFBlck9yZ0ttc1Jlc29sdmVyLFxuICBQZXJPcmdLbXNLZXlQcm92aWRlcixcbn0gZnJvbSAnLi9zZWNyZXQtZW5jcnlwdGlvbi5qcyc7XG5leHBvcnQgKiBmcm9tICcuL3NlY3JldC1yb3RhdGlvbi5qcyc7XG5leHBvcnQge1xuICBzZXRDb3VudGVyRW1pdHRlcixcbiAgcmVzZXRDb3VudGVyRW1pdHRlcixcbiAgZW1pdENvdW50ZXIsXG59IGZyb20gJy4vbWV0cmljLWVtaXR0ZXIuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9hd3Mtc2NydWIuanMnO1xuZXhwb3J0IHtcbiAgZXh0cmFjdFByZWRpY2F0ZSxcbiAgU1BEWF9QUkVESUNBVEVfVFlQRSxcbn0gZnJvbSAnLi9kc3NlLmpzJztcbmV4cG9ydCB7XG4gIG1hc2tMaW5lLFxuICBsb29rc1NlbnNpdGl2ZSxcbiAgUkVEQUNURUQsXG4gIFNFTlNJVElWRV9WQUxVRV9QQVRURVJOUyxcbn0gZnJvbSAnLi9zZW5zaXRpdmUtcGF0dGVybnMuanMnO1xuZXhwb3J0IHtcbiAgaXNQcml2YXRlQWRkcmVzcyxcbiAgYXNzZXJ0U2FmZVVybCxcbiAgc2FmZUZldGNoLFxuICB0eXBlIFNhZmVGZXRjaFJlc3BvbnNlLFxufSBmcm9tICcuL3NzcmYuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9lbnYuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9zZXJ2aWNlLXJlZ2lzdHJ5LmpzJztcbmV4cG9ydCAqIGZyb20gJy4vcmV0ZW50aW9uLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vY29tcGxpYW5jZS1hdHRyaWJ1dGVzLmpzJztcbmV4cG9ydCB7XG4gIGxlYWRpbmdaZXJvQml0cyxcbiAgcHJvb2ZPZldvcmtIYXNoLFxuICBjaGFsbGVuZ2VLZXksXG4gIGNsYW1wRGlmZmljdWx0eSxcbiAgY3JlYXRlUHJvb2ZPZldvcmtDaGFsbGVuZ2UsXG4gIHBhcnNlUHJvb2ZPZldvcmtDaGFsbGVuZ2UsXG4gIHZlcmlmeVByb29mT2ZXb3JrLFxuICBzb2x2ZVByb29mT2ZXb3JrLFxuICBQT1dfREVGQVVMVF9ESUZGSUNVTFRZLFxuICBQT1dfTUFYX0RJRkZJQ1VMVFksXG4gIFBPV19DSEFMTEVOR0VfVFRMX01TLFxuICB0eXBlIFByb29mT2ZXb3JrQ2hhbGxlbmdlLFxuICB0eXBlIFByb29mT2ZXb3JrU29sdXRpb24sXG59IGZyb20gJy4vcHJvb2Ytb2Ytd29yay5qcyc7XG4iXX0=
|