@storyshelf/core 0.3.1 → 0.5.3
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/README.md +38 -31
- package/dist/adapter/capture-queue.d.mts +29 -1
- package/dist/adapter/capture-runner.d.mts +18 -2
- package/dist/adapter/capture-runner.mjs +12 -1
- package/dist/adapter/capture-runner.mjs.map +1 -0
- package/dist/adapter/database.d.mts +67 -17
- package/dist/adapter/database.mjs +22 -55
- package/dist/adapter/database.mjs.map +1 -1
- package/dist/adapter/email-sender.d.mts +27 -0
- package/dist/adapter/email-sender.mjs +4 -0
- package/dist/adapter/metadata.d.mts +21 -15
- package/dist/adapter/notifier.d.mts +7 -0
- package/dist/adapter/notifier.mjs +6 -0
- package/dist/adapter/setup.d.mts +61 -0
- package/dist/adapter/setup.mjs +29 -0
- package/dist/adapter/setup.mjs.map +1 -0
- package/dist/adapter/webhook-events.d.mts +29 -0
- package/dist/adapter/webhook-events.mjs +83 -0
- package/dist/adapter/webhook-events.mjs.map +1 -0
- package/dist/adapters/notifier/events.d.mts +26 -0
- package/dist/adapters/notifier/events.mjs +66 -0
- package/dist/adapters/notifier/events.mjs.map +1 -0
- package/dist/adapters/notifier/format.d.mts +14 -0
- package/dist/adapters/notifier/format.mjs +96 -0
- package/dist/adapters/notifier/format.mjs.map +1 -0
- package/dist/adapters/notifier/provider.d.mts +32 -0
- package/dist/adapters/notifier/types.d.mts +56 -0
- package/dist/adapters/setup-runner.d.mts +23 -0
- package/dist/adapters/setup-runner.mjs +149 -0
- package/dist/adapters/setup-runner.mjs.map +1 -0
- package/dist/adapters/validate.d.mts +30 -0
- package/dist/adapters/validate.mjs +313 -0
- package/dist/adapters/validate.mjs.map +1 -0
- package/dist/auth.d.mts +94 -0
- package/dist/auth.mjs +4 -0
- package/dist/brand-packs.d.mts +16 -0
- package/dist/brand-packs.mjs +130 -0
- package/dist/brand-packs.mjs.map +1 -0
- package/dist/capture/adapter.d.mts +51 -1
- package/dist/capture/adapter.mjs.map +1 -1
- package/dist/capture/affected.d.mts +16 -0
- package/dist/capture/affected.mjs +64 -0
- package/dist/capture/affected.mjs.map +1 -0
- package/dist/capture/diff-record.mjs +30 -0
- package/dist/capture/diff-record.mjs.map +1 -0
- package/dist/capture/dispatch.d.mts +36 -0
- package/dist/capture/dispatch.mjs +88 -31
- package/dist/capture/dispatch.mjs.map +1 -1
- package/dist/capture/guards.mjs +31 -0
- package/dist/capture/guards.mjs.map +1 -0
- package/dist/capture/orchestrator.d.mts +41 -6
- package/dist/capture/orchestrator.mjs +151 -28
- package/dist/capture/orchestrator.mjs.map +1 -1
- package/dist/capture/pipeline.d.mts +30 -16
- package/dist/capture/pipeline.mjs +143 -39
- package/dist/capture/pipeline.mjs.map +1 -1
- package/dist/capture/recovery.d.mts +21 -0
- package/dist/capture/recovery.mjs +83 -0
- package/dist/capture/recovery.mjs.map +1 -0
- package/dist/capture/rediff.d.mts +35 -0
- package/dist/capture/rediff.mjs +77 -0
- package/dist/capture/rediff.mjs.map +1 -0
- package/dist/capture/sizing.d.mts +58 -0
- package/dist/capture/sizing.mjs +119 -0
- package/dist/capture/sizing.mjs.map +1 -0
- package/dist/capture/skip-checks.mjs +3 -3
- package/dist/capture/skip-checks.mjs.map +1 -1
- package/dist/capture/statics.d.mts +38 -0
- package/dist/capture/statics.mjs +38 -4
- package/dist/capture/statics.mjs.map +1 -1
- package/dist/capture/status-fanout.mjs +7 -2
- package/dist/capture/status-fanout.mjs.map +1 -1
- package/dist/capture/storybook.d.mts +31 -2
- package/dist/capture/storybook.mjs +77 -2
- package/dist/capture/storybook.mjs.map +1 -1
- package/dist/capture.d.mts +10 -4
- package/dist/capture.mjs +7 -2
- package/dist/config.d.mts +121 -4
- package/dist/config.mjs +55 -8
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.mts +5 -56
- package/dist/index.mjs +4 -284
- package/dist/logger.d.mts +26 -17
- package/dist/logger.mjs +10 -5
- package/dist/logger.mjs.map +1 -1
- package/dist/models/baseline-status.d.mts +29 -0
- package/dist/models/baseline-status.mjs +26 -0
- package/dist/models/baseline-status.mjs.map +1 -0
- package/dist/models/baseline.d.mts +33 -0
- package/dist/models/baseline.mjs +35 -13
- package/dist/models/baseline.mjs.map +1 -1
- package/dist/models/build.d.mts +87 -0
- package/dist/models/build.mjs +83 -35
- package/dist/models/build.mjs.map +1 -1
- package/dist/models/capture-attempt.d.mts +40 -0
- package/dist/models/capture-attempt.mjs +85 -0
- package/dist/models/capture-attempt.mjs.map +1 -0
- package/dist/models/capture-log.d.mts +21 -0
- package/dist/models/capture-log.mjs +44 -0
- package/dist/models/capture-log.mjs.map +1 -0
- package/dist/models/comment.d.mts +29 -0
- package/dist/models/comment.mjs +11 -8
- package/dist/models/comment.mjs.map +1 -1
- package/dist/models/content-ref.d.mts +21 -0
- package/dist/models/content-ref.mjs +49 -0
- package/dist/models/content-ref.mjs.map +1 -0
- package/dist/models/credentials.d.mts +36 -0
- package/dist/models/credentials.mjs +103 -0
- package/dist/models/credentials.mjs.map +1 -0
- package/dist/models/label.d.mts +58 -0
- package/dist/models/label.mjs +32 -27
- package/dist/models/label.mjs.map +1 -1
- package/dist/models/member.d.mts +34 -0
- package/dist/models/member.mjs +20 -11
- package/dist/models/member.mjs.map +1 -1
- package/dist/models/notification-channel.d.mts +52 -0
- package/dist/models/notification-channel.mjs +93 -0
- package/dist/models/notification-channel.mjs.map +1 -0
- package/dist/models/notification-subscription.d.mts +44 -0
- package/dist/models/notification-subscription.mjs +89 -0
- package/dist/models/notification-subscription.mjs.map +1 -0
- package/dist/models/project-group-mapping.d.mts +30 -0
- package/dist/models/project-group-mapping.mjs +46 -0
- package/dist/models/project-group-mapping.mjs.map +1 -0
- package/dist/models/project.d.mts +54 -0
- package/dist/models/project.mjs +15 -11
- package/dist/models/project.mjs.map +1 -1
- package/dist/models/snapshot.d.mts +58 -0
- package/dist/models/snapshot.mjs +13 -7
- package/dist/models/snapshot.mjs.map +1 -1
- package/dist/models/status-config.d.mts +38 -0
- package/dist/models/status-config.mjs +12 -11
- package/dist/models/status-config.mjs.map +1 -1
- package/dist/models/token.d.mts +44 -0
- package/dist/models/token.mjs +18 -15
- package/dist/models/token.mjs.map +1 -1
- package/dist/models/user.d.mts +42 -0
- package/dist/models/user.mjs +65 -0
- package/dist/models/user.mjs.map +1 -0
- package/dist/models/webhook.d.mts +50 -0
- package/dist/models/webhook.mjs +12 -10
- package/dist/models/webhook.mjs.map +1 -1
- package/dist/models.d.mts +22 -0
- package/dist/models.mjs +23 -0
- package/dist/paths.mjs +29 -0
- package/dist/paths.mjs.map +1 -1
- package/dist/retention.d.mts +45 -0
- package/dist/retention.mjs +145 -0
- package/dist/retention.mjs.map +1 -0
- package/dist/schema/baseline.d.mts +1 -0
- package/dist/schema/build.d.mts +8 -0
- package/dist/schema/capture-attempt.d.mts +38 -0
- package/dist/schema/comment.d.mts +1 -1
- package/dist/schema/content-ref.d.mts +13 -0
- package/dist/schema/member.d.mts +2 -0
- package/dist/schema/notification.d.mts +35 -0
- package/dist/schema/project-group-mapping.d.mts +15 -0
- package/dist/schema/project.d.mts +4 -0
- package/dist/schema/snapshot.d.mts +7 -0
- package/dist/schema/token.d.mts +2 -0
- package/dist/schema/user.d.mts +11 -1
- package/dist/schema.d.mts +9 -46
- package/dist/schema.mjs +1 -55
- package/dist/test-helpers/create-project.d.mts +15 -0
- package/dist/test-helpers/create-project.mjs +28 -0
- package/dist/test-helpers/create-project.mjs.map +1 -0
- package/dist/test-helpers/database-contract.d.mts +13 -0
- package/dist/test-helpers/database-contract.mjs +58 -0
- package/dist/test-helpers/database-contract.mjs.map +1 -0
- package/dist/test-helpers/fake-adapters.d.mts +14 -0
- package/dist/test-helpers/fake-adapters.mjs +20 -0
- package/dist/test-helpers/fake-adapters.mjs.map +1 -0
- package/dist/test-helpers/fake-database.d.mts +11 -0
- package/dist/test-helpers/fake-database.mjs +104 -0
- package/dist/test-helpers/fake-database.mjs.map +1 -0
- package/dist/test-helpers/fake-storage.d.mts +14 -0
- package/dist/test-helpers/fake-storage.mjs +49 -0
- package/dist/test-helpers/fake-storage.mjs.map +1 -0
- package/dist/test-helpers/fake-tables.mjs +276 -0
- package/dist/test-helpers/fake-tables.mjs.map +1 -0
- package/dist/test-helpers/git-contract.d.mts +11 -0
- package/dist/test-helpers/git-contract.mjs +34 -0
- package/dist/test-helpers/git-contract.mjs.map +1 -0
- package/dist/test-helpers/notifier-contract.d.mts +11 -0
- package/dist/test-helpers/notifier-contract.mjs +34 -0
- package/dist/test-helpers/notifier-contract.mjs.map +1 -0
- package/dist/test-helpers/queue-contract.d.mts +11 -0
- package/dist/test-helpers/queue-contract.mjs +64 -0
- package/dist/test-helpers/queue-contract.mjs.map +1 -0
- package/dist/test-helpers/runner-contract.d.mts +11 -0
- package/dist/test-helpers/runner-contract.mjs +32 -0
- package/dist/test-helpers/runner-contract.mjs.map +1 -0
- package/dist/test-helpers/sql-chunks.mjs +138 -0
- package/dist/test-helpers/sql-chunks.mjs.map +1 -0
- package/dist/test-helpers/storage-contract.d.mts +11 -0
- package/dist/test-helpers/storage-contract.mjs +87 -0
- package/dist/test-helpers/storage-contract.mjs.map +1 -0
- package/dist/test-helpers.d.mts +13 -0
- package/dist/test-helpers.mjs +14 -0
- package/dist/tracing.mjs +63 -0
- package/dist/tracing.mjs.map +1 -0
- package/dist/types.d.mts +38 -5
- package/dist/types.mjs +18 -5
- package/dist/types.mjs.map +1 -1
- package/dist/urls.d.mts +12 -1
- package/dist/urls.mjs +22 -3
- package/dist/urls.mjs.map +1 -1
- package/dist/utils/encrypt.d.mts +48 -0
- package/dist/utils/encrypt.mjs +67 -13
- package/dist/utils/encrypt.mjs.map +1 -1
- package/dist/utils/hash.d.mts +17 -0
- package/dist/utils/hash.mjs +8 -2
- package/dist/utils/hash.mjs.map +1 -1
- package/dist/utils/http.d.mts +58 -0
- package/dist/utils/http.mjs +147 -0
- package/dist/utils/http.mjs.map +1 -0
- package/dist/utils/mime.d.mts +9 -0
- package/dist/utils/mime.mjs +33 -0
- package/dist/utils/mime.mjs.map +1 -0
- package/dist/utils/path-security.d.mts +12 -0
- package/dist/utils/path-security.mjs +24 -0
- package/dist/utils/path-security.mjs.map +1 -0
- package/dist/utils/redact.d.mts +17 -0
- package/dist/utils/redact.mjs +42 -0
- package/dist/utils/redact.mjs.map +1 -0
- package/dist/utils/timing.d.mts +19 -0
- package/dist/utils/timing.mjs +46 -0
- package/dist/utils/timing.mjs.map +1 -0
- package/dist/utils/ulid.d.mts +10 -0
- package/dist/utils/ulid.mjs +8 -8
- package/dist/utils/ulid.mjs.map +1 -1
- package/dist/utils.d.mts +12 -0
- package/dist/utils.mjs +13 -0
- package/package.json +69 -28
- package/dist/adapter/auth.d.mts +0 -50
- package/dist/adapter/auth.mjs +0 -10
- package/dist/adapter/auth.mjs.map +0 -1
- package/dist/adapter/init.d.mts +0 -58
- package/dist/adapter/init.mjs +0 -93
- package/dist/adapter/init.mjs.map +0 -1
- package/dist/adapters/webhook-events.mjs +0 -55
- package/dist/adapters/webhook-events.mjs.map +0 -1
- package/dist/ddl.d.mts +0 -8
- package/dist/ddl.mjs +0 -158
- package/dist/ddl.mjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/middleware/auth-gate.mjs +0 -36
- package/dist/middleware/auth-gate.mjs.map +0 -1
- package/dist/middleware/csrf.mjs +0 -40
- package/dist/middleware/csrf.mjs.map +0 -1
- package/dist/middleware/rate-limit.mjs +0 -39
- package/dist/middleware/rate-limit.mjs.map +0 -1
- package/dist/middleware/request-log.mjs +0 -28
- package/dist/middleware/request-log.mjs.map +0 -1
- package/dist/middleware/store-scope.mjs +0 -29
- package/dist/middleware/store-scope.mjs.map +0 -1
- package/dist/pages/build-detail.mjs +0 -339
- package/dist/pages/build-detail.mjs.map +0 -1
- package/dist/pages/build-diff-comments.mjs +0 -113
- package/dist/pages/build-diff-comments.mjs.map +0 -1
- package/dist/pages/build-diff-header.mjs +0 -163
- package/dist/pages/build-diff-header.mjs.map +0 -1
- package/dist/pages/build-diff-nav.mjs +0 -66
- package/dist/pages/build-diff-nav.mjs.map +0 -1
- package/dist/pages/build-diff-viewer.mjs +0 -197
- package/dist/pages/build-diff-viewer.mjs.map +0 -1
- package/dist/pages/build-diff.mjs +0 -90
- package/dist/pages/build-diff.mjs.map +0 -1
- package/dist/pages/compute-jobs.mjs +0 -198
- package/dist/pages/compute-jobs.mjs.map +0 -1
- package/dist/pages/label-detail.mjs +0 -228
- package/dist/pages/label-detail.mjs.map +0 -1
- package/dist/pages/login.mjs +0 -78
- package/dist/pages/login.mjs.map +0 -1
- package/dist/pages/project-builds.mjs +0 -231
- package/dist/pages/project-builds.mjs.map +0 -1
- package/dist/pages/project-create.mjs +0 -169
- package/dist/pages/project-create.mjs.map +0 -1
- package/dist/pages/project-settings.mjs +0 -102
- package/dist/pages/project-settings.mjs.map +0 -1
- package/dist/pages/projects.mjs +0 -184
- package/dist/pages/projects.mjs.map +0 -1
- package/dist/pages/root.mjs +0 -94
- package/dist/pages/root.mjs.map +0 -1
- package/dist/pages/settings-general.mjs +0 -192
- package/dist/pages/settings-general.mjs.map +0 -1
- package/dist/pages/settings-labels.mjs +0 -150
- package/dist/pages/settings-labels.mjs.map +0 -1
- package/dist/pages/settings-members.mjs +0 -125
- package/dist/pages/settings-members.mjs.map +0 -1
- package/dist/pages/settings-status.mjs +0 -152
- package/dist/pages/settings-status.mjs.map +0 -1
- package/dist/pages/settings-tests.mjs +0 -149
- package/dist/pages/settings-tests.mjs.map +0 -1
- package/dist/pages/settings-tokens.mjs +0 -96
- package/dist/pages/settings-tokens.mjs.map +0 -1
- package/dist/pages/settings-webhooks.mjs +0 -150
- package/dist/pages/settings-webhooks.mjs.map +0 -1
- package/dist/pages/storybook.mjs +0 -96
- package/dist/pages/storybook.mjs.map +0 -1
- package/dist/retention/purge.mjs +0 -67
- package/dist/retention/purge.mjs.map +0 -1
- package/dist/routers/admin.mjs +0 -42
- package/dist/routers/admin.mjs.map +0 -1
- package/dist/routers/assets.mjs +0 -25
- package/dist/routers/assets.mjs.map +0 -1
- package/dist/routers/auth.mjs +0 -78
- package/dist/routers/auth.mjs.map +0 -1
- package/dist/routers/builds.handlers.mjs +0 -184
- package/dist/routers/builds.handlers.mjs.map +0 -1
- package/dist/routers/builds.mjs +0 -185
- package/dist/routers/builds.mjs.map +0 -1
- package/dist/routers/comments.mjs +0 -90
- package/dist/routers/comments.mjs.map +0 -1
- package/dist/routers/health.mjs +0 -137
- package/dist/routers/health.mjs.map +0 -1
- package/dist/routers/helpers.mjs +0 -82
- package/dist/routers/helpers.mjs.map +0 -1
- package/dist/routers/htmx.mjs +0 -20
- package/dist/routers/htmx.mjs.map +0 -1
- package/dist/routers/labels.mjs +0 -110
- package/dist/routers/labels.mjs.map +0 -1
- package/dist/routers/media.mjs +0 -55
- package/dist/routers/media.mjs.map +0 -1
- package/dist/routers/members.mjs +0 -102
- package/dist/routers/members.mjs.map +0 -1
- package/dist/routers/projects.mjs +0 -122
- package/dist/routers/projects.mjs.map +0 -1
- package/dist/routers/schemas.mjs +0 -224
- package/dist/routers/schemas.mjs.map +0 -1
- package/dist/routers/settings-general.mjs +0 -95
- package/dist/routers/settings-general.mjs.map +0 -1
- package/dist/routers/settings-labels.mjs +0 -49
- package/dist/routers/settings-labels.mjs.map +0 -1
- package/dist/routers/settings-members.mjs +0 -30
- package/dist/routers/settings-members.mjs.map +0 -1
- package/dist/routers/settings-status.mjs +0 -73
- package/dist/routers/settings-status.mjs.map +0 -1
- package/dist/routers/settings-tokens.mjs +0 -40
- package/dist/routers/settings-tokens.mjs.map +0 -1
- package/dist/routers/settings-webhooks.mjs +0 -63
- package/dist/routers/settings-webhooks.mjs.map +0 -1
- package/dist/routers/settings.handlers.mjs +0 -93
- package/dist/routers/settings.handlers.mjs.map +0 -1
- package/dist/routers/settings.mjs +0 -23
- package/dist/routers/settings.mjs.map +0 -1
- package/dist/routers/snapshots.mjs +0 -144
- package/dist/routers/snapshots.mjs.map +0 -1
- package/dist/routers/status-configs.mjs +0 -101
- package/dist/routers/status-configs.mjs.map +0 -1
- package/dist/routers/storybook.mjs +0 -120
- package/dist/routers/storybook.mjs.map +0 -1
- package/dist/routers/tokens.mjs +0 -81
- package/dist/routers/tokens.mjs.map +0 -1
- package/dist/routers/ui.mjs +0 -165
- package/dist/routers/ui.mjs.map +0 -1
- package/dist/routers/webhooks.mjs +0 -90
- package/dist/routers/webhooks.mjs.map +0 -1
- package/dist/schema/baseline.mjs +0 -22
- package/dist/schema/baseline.mjs.map +0 -1
- package/dist/schema/build.mjs +0 -29
- package/dist/schema/build.mjs.map +0 -1
- package/dist/schema/comment.mjs +0 -26
- package/dist/schema/comment.mjs.map +0 -1
- package/dist/schema/label.mjs +0 -30
- package/dist/schema/label.mjs.map +0 -1
- package/dist/schema/member.mjs +0 -19
- package/dist/schema/member.mjs.map +0 -1
- package/dist/schema/project.mjs +0 -25
- package/dist/schema/project.mjs.map +0 -1
- package/dist/schema/snapshot.mjs +0 -34
- package/dist/schema/snapshot.mjs.map +0 -1
- package/dist/schema/status-config.mjs +0 -20
- package/dist/schema/status-config.mjs.map +0 -1
- package/dist/schema/token.mjs +0 -19
- package/dist/schema/token.mjs.map +0 -1
- package/dist/schema/user.mjs +0 -19
- package/dist/schema/user.mjs.map +0 -1
- package/dist/schema/webhook.mjs +0 -20
- package/dist/schema/webhook.mjs.map +0 -1
- package/dist/schema.mjs.map +0 -1
- package/dist/store.mjs +0 -20
- package/dist/store.mjs.map +0 -1
- package/dist/ui/document.mjs +0 -348
- package/dist/ui/document.mjs.map +0 -1
- package/dist/ui/feedback.mjs +0 -24
- package/dist/ui/feedback.mjs.map +0 -1
- package/dist/ui/forms.mjs +0 -117
- package/dist/ui/forms.mjs.map +0 -1
- package/dist/ui/styles.mjs +0 -174
- package/dist/ui/styles.mjs.map +0 -1
- package/dist/ui/theme.mjs +0 -44
- package/dist/ui/theme.mjs.map +0 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { injectTraceContext, withSpan } from "../tracing.mjs";
|
|
5
|
+
//#region src/utils/http.ts
|
|
6
|
+
/**
|
|
7
|
+
* Fetch JSON with timeout, retries, and structured errors.
|
|
8
|
+
*
|
|
9
|
+
* Retries network failures, 429, and 502/503/504 (honoring `Retry-After`);
|
|
10
|
+
* every other status throws {@link HttpError} immediately.
|
|
11
|
+
*
|
|
12
|
+
* @param url - Absolute request URL.
|
|
13
|
+
* @param options - Method, headers, JSON body, timeout, retries, logger.
|
|
14
|
+
* @returns The parsed JSON response body.
|
|
15
|
+
*/
|
|
16
|
+
async function httpJson(url, options = {}) {
|
|
17
|
+
return await requestWithRetry(url, options, options.retries ?? DEFAULT_RETRIES, options.timeoutMs ?? DEFAULT_TIMEOUT_MS, doFetchJson);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* POST/PUT plain payloads (e.g. Slack/Teams webhook cards) with the same
|
|
21
|
+
* timeout, retry, and `Retry-After` semantics as {@link httpJson}.
|
|
22
|
+
*
|
|
23
|
+
* @param url - Absolute request URL.
|
|
24
|
+
* @param options - Method, headers, text body, timeout, retries, logger.
|
|
25
|
+
* @returns The raw response body text.
|
|
26
|
+
*/
|
|
27
|
+
async function httpText(url, options = {}) {
|
|
28
|
+
return await requestWithRetry(url, options, options.retries ?? DEFAULT_RETRIES, options.timeoutMs ?? DEFAULT_TIMEOUT_MS, doFetchText);
|
|
29
|
+
}
|
|
30
|
+
/** Failed HTTP response: status code plus a snippet of the response body. */
|
|
31
|
+
var HttpError = class extends Error {
|
|
32
|
+
status;
|
|
33
|
+
body;
|
|
34
|
+
headers;
|
|
35
|
+
constructor(status, body, headers) {
|
|
36
|
+
super(`HTTP ${status}: ${body}`);
|
|
37
|
+
this.name = "HttpError";
|
|
38
|
+
this.status = status;
|
|
39
|
+
this.body = body;
|
|
40
|
+
this.headers = headers ?? new Headers();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
44
|
+
const DEFAULT_RETRIES = 3;
|
|
45
|
+
const MAX_RETRY_AFTER_MS = 3e4;
|
|
46
|
+
const BACKOFF_BASE_MS = 1e3;
|
|
47
|
+
const MAX_BODY_SNIPPET = 500;
|
|
48
|
+
/** Whether a failure is worth retrying: network errors, 429, and 502/503/504. */
|
|
49
|
+
function shouldRetry(error, attempt, maxAttempts) {
|
|
50
|
+
if (attempt >= maxAttempts) return false;
|
|
51
|
+
if (!(error instanceof HttpError)) return true;
|
|
52
|
+
return error.status === 429 || error.status >= 502 && error.status <= 504;
|
|
53
|
+
}
|
|
54
|
+
/** Parse a Retry-After value (seconds or HTTP-date) into milliseconds. */
|
|
55
|
+
function parseRetryAfter(value) {
|
|
56
|
+
if (!value) return null;
|
|
57
|
+
const seconds = Number(value);
|
|
58
|
+
if (Number.isFinite(seconds) && seconds >= 0) return Math.min(seconds * 1e3, MAX_RETRY_AFTER_MS);
|
|
59
|
+
const date = Date.parse(value);
|
|
60
|
+
if (!Number.isNaN(date)) return Math.min(Math.max(date - Date.now(), 0), MAX_RETRY_AFTER_MS);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/** Delay before the next attempt: Retry-After when present, else 1s/2s/4s. */
|
|
64
|
+
function retryDelayMs(error, attempt) {
|
|
65
|
+
if (error instanceof HttpError) {
|
|
66
|
+
const retryAfter = parseRetryAfter(error.headers.get("retry-after"));
|
|
67
|
+
if (retryAfter !== null) return retryAfter;
|
|
68
|
+
}
|
|
69
|
+
return Math.min(BACKOFF_BASE_MS * 2 ** (attempt - 1), MAX_RETRY_AFTER_MS);
|
|
70
|
+
}
|
|
71
|
+
/** Sleep helper for retry backoff. */
|
|
72
|
+
async function sleep(ms) {
|
|
73
|
+
await new Promise((resolve) => {
|
|
74
|
+
setTimeout(resolve, ms);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async function requestWithRetry(url, options, maxAttempts, timeoutMs, perform) {
|
|
78
|
+
return await withSpan("http.client", async (span) => {
|
|
79
|
+
for (let attempt = 1;; attempt += 1) try {
|
|
80
|
+
return await perform(url, options, timeoutMs);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
span.recordException(error instanceof Error ? error : String(error));
|
|
83
|
+
if (!shouldRetry(error, attempt, maxAttempts)) throw error;
|
|
84
|
+
span.setAttribute("http.retry.count", attempt);
|
|
85
|
+
await backoff(error, attempt, url, options.logger);
|
|
86
|
+
}
|
|
87
|
+
}, {
|
|
88
|
+
"http.request.method": options.method ?? "GET",
|
|
89
|
+
"url.full": redactUrl(url)
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/** Strip the query string (tokens, signatures) from a URL for span attributes. */
|
|
93
|
+
function redactUrl(url) {
|
|
94
|
+
const query = url.indexOf("?");
|
|
95
|
+
return query === -1 ? url : url.slice(0, query);
|
|
96
|
+
}
|
|
97
|
+
async function backoff(error, attempt, url, logger) {
|
|
98
|
+
const delay = retryDelayMs(error, attempt);
|
|
99
|
+
logger?.warn({
|
|
100
|
+
url,
|
|
101
|
+
attempt,
|
|
102
|
+
delayMs: delay
|
|
103
|
+
}, "http request failed, retrying");
|
|
104
|
+
await sleep(delay);
|
|
105
|
+
}
|
|
106
|
+
function buildRequest(options) {
|
|
107
|
+
const headers = { ...options.headers };
|
|
108
|
+
let body;
|
|
109
|
+
if (options.json !== void 0) {
|
|
110
|
+
headers["content-type"] = "application/json";
|
|
111
|
+
body = JSON.stringify(options.json);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
headers,
|
|
115
|
+
body,
|
|
116
|
+
method: options.method ?? "GET"
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
async function doFetchJson(url, options, timeoutMs) {
|
|
120
|
+
return await (await doFetchResponse(url, options, timeoutMs)).json();
|
|
121
|
+
}
|
|
122
|
+
async function doFetchText(url, options, timeoutMs) {
|
|
123
|
+
return await (await doFetchResponse(url, options, timeoutMs)).text();
|
|
124
|
+
}
|
|
125
|
+
async function doFetchResponse(url, options, timeoutMs) {
|
|
126
|
+
const request = buildRequest(options);
|
|
127
|
+
injectTraceContext(request.headers);
|
|
128
|
+
options.logger?.debug({
|
|
129
|
+
url,
|
|
130
|
+
method: request.method
|
|
131
|
+
}, "http request");
|
|
132
|
+
const response = await fetch(url, {
|
|
133
|
+
method: request.method,
|
|
134
|
+
headers: request.headers,
|
|
135
|
+
body: request.body,
|
|
136
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
137
|
+
});
|
|
138
|
+
if (!response.ok) {
|
|
139
|
+
const text = await response.text();
|
|
140
|
+
throw new HttpError(response.status, text.slice(0, MAX_BODY_SNIPPET), response.headers);
|
|
141
|
+
}
|
|
142
|
+
return response;
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { HttpError, httpJson, httpText };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=http.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.mjs","names":[],"sources":["../../src/utils/http.ts"],"sourcesContent":["import type { Logger } from \"../logger.ts\";\nimport { injectTraceContext, withSpan } from \"../tracing.ts\";\n\n/**\n * Fetch JSON with timeout, retries, and structured errors.\n *\n * Retries network failures, 429, and 502/503/504 (honoring `Retry-After`);\n * every other status throws {@link HttpError} immediately.\n *\n * @param url - Absolute request URL.\n * @param options - Method, headers, JSON body, timeout, retries, logger.\n * @returns The parsed JSON response body.\n */\nexport async function httpJson<T>(url: string, options: HttpRequestOptions = {}): Promise<T> {\n return await requestWithRetry<T>(\n url,\n options,\n options.retries ?? DEFAULT_RETRIES,\n options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n doFetchJson,\n );\n}\n\n/**\n * POST/PUT plain payloads (e.g. Slack/Teams webhook cards) with the same\n * timeout, retry, and `Retry-After` semantics as {@link httpJson}.\n *\n * @param url - Absolute request URL.\n * @param options - Method, headers, text body, timeout, retries, logger.\n * @returns The raw response body text.\n */\nexport async function httpText(url: string, options: HttpTextOptions = {}): Promise<string> {\n return await requestWithRetry<string>(\n url,\n options,\n options.retries ?? DEFAULT_RETRIES,\n options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n doFetchText,\n );\n}\n\n/** Failed HTTP response: status code plus a snippet of the response body. */\nexport class HttpError extends Error {\n readonly status: number;\n readonly body: string;\n readonly headers: Headers;\n\n constructor(status: number, body: string, headers?: Headers) {\n super(`HTTP ${status}: ${body}`);\n this.name = \"HttpError\";\n this.status = status;\n this.body = body;\n this.headers = headers ?? new Headers();\n }\n}\n\n/** Options for {@link httpJson}. */\nexport interface HttpRequestOptions {\n method?: string;\n headers?: Record<string, string>;\n /** Body serialized as JSON with a `content-type` header. */\n json?: unknown;\n /** Per-attempt timeout in milliseconds (default 30s). */\n timeoutMs?: number;\n /** Total attempts including the first (default 3). */\n retries?: number;\n logger?: Logger;\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Options for {@link httpText}. */\nexport interface HttpTextOptions {\n method?: string;\n headers?: Record<string, string>;\n /** Body serialized as JSON with a `content-type` header. */\n json?: unknown;\n /** Per-attempt timeout in milliseconds (default 30s). */\n timeoutMs?: number;\n /** Total attempts including the first (default 3). */\n retries?: number;\n logger?: Logger;\n}\nconst DEFAULT_RETRIES = 3;\nconst MAX_RETRY_AFTER_MS = 30_000;\nconst BACKOFF_BASE_MS = 1000;\nconst MAX_BODY_SNIPPET = 500;\n\n/** Whether a failure is worth retrying: network errors, 429, and 502/503/504. */\nfunction shouldRetry(error: unknown, attempt: number, maxAttempts: number): boolean {\n if (attempt >= maxAttempts) {\n return false;\n }\n if (!(error instanceof HttpError)) {\n return true;\n }\n return error.status === 429 || (error.status >= 502 && error.status <= 504);\n}\n\n/** Parse a Retry-After value (seconds or HTTP-date) into milliseconds. */\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) {\n return null;\n }\n const seconds = Number(value);\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(seconds * 1000, MAX_RETRY_AFTER_MS);\n }\n const date = Date.parse(value);\n if (!Number.isNaN(date)) {\n return Math.min(Math.max(date - Date.now(), 0), MAX_RETRY_AFTER_MS);\n }\n return null;\n}\n\n/** Delay before the next attempt: Retry-After when present, else 1s/2s/4s. */\nfunction retryDelayMs(error: unknown, attempt: number): number {\n if (error instanceof HttpError) {\n const retryAfter = parseRetryAfter(error.headers.get(\"retry-after\"));\n if (retryAfter !== null) {\n return retryAfter;\n }\n }\n return Math.min(BACKOFF_BASE_MS * 2 ** (attempt - 1), MAX_RETRY_AFTER_MS);\n}\n\n/** Sleep helper for retry backoff. */\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/* oxlint-disable eslint/no-await-in-loop -- retry attempts run sequentially by design */\nasync function requestWithRetry<T>(\n url: string,\n options: HttpRequestOptions,\n maxAttempts: number,\n timeoutMs: number,\n perform: (url: string, options: HttpRequestOptions, timeoutMs: number) => Promise<T>,\n): Promise<T> {\n return await withSpan(\n \"http.client\",\n async (span) => {\n for (let attempt = 1; ; attempt += 1) {\n try {\n return await perform(url, options, timeoutMs);\n } catch (error) {\n span.recordException(error instanceof Error ? error : String(error));\n if (!shouldRetry(error, attempt, maxAttempts)) {\n throw error;\n }\n span.setAttribute(\"http.retry.count\", attempt);\n await backoff(error, attempt, url, options.logger);\n }\n }\n },\n { \"http.request.method\": options.method ?? \"GET\", \"url.full\": redactUrl(url) },\n );\n}\n/* oxlint-enable eslint/no-await-in-loop */\n\n/** Strip the query string (tokens, signatures) from a URL for span attributes. */\nfunction redactUrl(url: string): string {\n const query = url.indexOf(\"?\");\n return query === -1 ? url : url.slice(0, query);\n}\n\nasync function backoff(\n error: unknown,\n attempt: number,\n url: string,\n logger?: Logger,\n): Promise<void> {\n const delay = retryDelayMs(error, attempt);\n logger?.warn({ url, attempt, delayMs: delay }, \"http request failed, retrying\");\n await sleep(delay);\n}\n\nfunction buildRequest(options: HttpRequestOptions): {\n headers: Record<string, string>;\n body: string | undefined;\n method: string;\n} {\n const headers: Record<string, string> = { ...options.headers };\n let body: string | undefined;\n if (options.json !== undefined) {\n headers[\"content-type\"] = \"application/json\";\n body = JSON.stringify(options.json);\n }\n return { headers, body, method: options.method ?? \"GET\" };\n}\n\nasync function doFetchJson<T>(\n url: string,\n options: HttpRequestOptions,\n timeoutMs: number,\n): Promise<T> {\n const response = await doFetchResponse(url, options, timeoutMs);\n return (await response.json()) as T;\n}\n\nasync function doFetchText(\n url: string,\n options: HttpRequestOptions,\n timeoutMs: number,\n): Promise<string> {\n const response = await doFetchResponse(url, options, timeoutMs);\n return await response.text();\n}\n\nasync function doFetchResponse(\n url: string,\n options: HttpRequestOptions,\n timeoutMs: number,\n): Promise<Response> {\n const request = buildRequest(options);\n injectTraceContext(request.headers);\n options.logger?.debug({ url, method: request.method }, \"http request\");\n const response = await fetch(url, {\n method: request.method,\n headers: request.headers,\n body: request.body,\n signal: AbortSignal.timeout(timeoutMs),\n });\n if (!response.ok) {\n const text = await response.text();\n throw new HttpError(response.status, text.slice(0, MAX_BODY_SNIPPET), response.headers);\n }\n return response;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/utils/mime.d.ts
|
|
4
|
+
/** Shared MIME types for storybook static serving. */
|
|
5
|
+
declare const MIME_TYPES: Record<string, string>;
|
|
6
|
+
declare function mimeFor(filePath: string): string;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { MIME_TYPES, mimeFor };
|
|
9
|
+
//# sourceMappingURL=mime.d.mts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/utils/mime.ts
|
|
5
|
+
/** Shared MIME types for storybook static serving. */
|
|
6
|
+
const MIME_TYPES = {
|
|
7
|
+
".css": "text/css; charset=utf-8",
|
|
8
|
+
".html": "text/html; charset=utf-8",
|
|
9
|
+
".htm": "text/html; charset=utf-8",
|
|
10
|
+
".ico": "image/x-icon",
|
|
11
|
+
".jpeg": "image/jpeg",
|
|
12
|
+
".jpg": "image/jpeg",
|
|
13
|
+
".js": "application/javascript",
|
|
14
|
+
".json": "application/json; charset=utf-8",
|
|
15
|
+
".map": "application/json; charset=utf-8",
|
|
16
|
+
".mjs": "application/javascript",
|
|
17
|
+
".png": "image/png",
|
|
18
|
+
".svg": "image/svg+xml",
|
|
19
|
+
".webp": "image/webp",
|
|
20
|
+
".woff": "font/woff",
|
|
21
|
+
".woff2": "font/woff2",
|
|
22
|
+
".ttf": "font/ttf",
|
|
23
|
+
".wasm": "application/wasm",
|
|
24
|
+
".gif": "image/gif"
|
|
25
|
+
};
|
|
26
|
+
function mimeFor(filePath) {
|
|
27
|
+
const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
28
|
+
return MIME_TYPES[ext] ?? "application/octet-stream";
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { MIME_TYPES, mimeFor };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=mime.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mime.mjs","names":[],"sources":["../../src/utils/mime.ts"],"sourcesContent":["/** Shared MIME types for storybook static serving. */\nexport const MIME_TYPES: Record<string, string> = {\n \".css\": \"text/css; charset=utf-8\",\n \".html\": \"text/html; charset=utf-8\",\n \".htm\": \"text/html; charset=utf-8\",\n \".ico\": \"image/x-icon\",\n \".jpeg\": \"image/jpeg\",\n \".jpg\": \"image/jpeg\",\n \".js\": \"application/javascript\",\n \".json\": \"application/json; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n \".mjs\": \"application/javascript\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n \".webp\": \"image/webp\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".wasm\": \"application/wasm\",\n \".gif\": \"image/gif\",\n};\n\nexport function mimeFor(filePath: string): string {\n const ext = filePath.slice(filePath.lastIndexOf(\".\")).toLowerCase();\n return MIME_TYPES[ext] ?? \"application/octet-stream\";\n}\n"],"mappings":";;;;;AACA,MAAa,aAAqC;CAChD,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,OAAO;CACP,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,UAAU;CACV,QAAQ;CACR,SAAS;CACT,QAAQ;AACV;AAEA,SAAgB,QAAQ,UAA0B;CAChD,MAAM,MAAM,SAAS,MAAM,SAAS,YAAY,GAAG,CAAC,CAAC,CAAC,YAAY;CAClE,OAAO,WAAW,QAAQ;AAC5B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/utils/path-security.d.ts
|
|
4
|
+
/** Whether a path segment is safe (no traversal). */
|
|
5
|
+
declare function isSafeSegment(segment: string): boolean;
|
|
6
|
+
/** Whether joining root with candidate stays inside root (no traversal). */
|
|
7
|
+
declare function isPathSafe(root: string, candidate: string): boolean;
|
|
8
|
+
/** Check if a path built from root + entry would escape root (for zip extraction). */
|
|
9
|
+
declare function isBlockedTarget(root: string, entryPath: string): boolean;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { isBlockedTarget, isPathSafe, isSafeSegment };
|
|
12
|
+
//# sourceMappingURL=path-security.d.mts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { join, normalize, sep } from "node:path";
|
|
5
|
+
//#region src/utils/path-security.ts
|
|
6
|
+
/** Whether a path segment is safe (no traversal). */
|
|
7
|
+
function isSafeSegment(segment) {
|
|
8
|
+
return segment !== ".." && !segment.startsWith("/") && !segment.includes("\\") && !segment.includes("..");
|
|
9
|
+
}
|
|
10
|
+
/** Whether joining root with candidate stays inside root (no traversal). */
|
|
11
|
+
function isPathSafe(root, candidate) {
|
|
12
|
+
const normalizedRoot = normalize(root);
|
|
13
|
+
const normalizedCandidate = normalize(candidate);
|
|
14
|
+
return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(normalizedRoot + sep) || normalizedCandidate.startsWith(`${normalizedRoot}/`);
|
|
15
|
+
}
|
|
16
|
+
/** Check if a path built from root + entry would escape root (for zip extraction). */
|
|
17
|
+
function isBlockedTarget(root, entryPath) {
|
|
18
|
+
const target = normalize(join(root, entryPath));
|
|
19
|
+
return target !== root && !target.startsWith(normalize(root) + sep);
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { isBlockedTarget, isPathSafe, isSafeSegment };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=path-security.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-security.mjs","names":[],"sources":["../../src/utils/path-security.ts"],"sourcesContent":["import { join, normalize, sep } from \"node:path\";\n\n/** Whether a path segment is safe (no traversal). */\nexport function isSafeSegment(segment: string): boolean {\n return (\n segment !== \"..\" &&\n !segment.startsWith(\"/\") &&\n !segment.includes(\"\\\\\") &&\n !segment.includes(\"..\")\n );\n}\n\n/** Whether joining root with candidate stays inside root (no traversal). */\nexport function isPathSafe(root: string, candidate: string): boolean {\n const normalizedRoot = normalize(root);\n const normalizedCandidate = normalize(candidate);\n return (\n normalizedCandidate === normalizedRoot ||\n normalizedCandidate.startsWith(normalizedRoot + sep) ||\n normalizedCandidate.startsWith(`${normalizedRoot}/`)\n );\n}\n\n/** Check if a path built from root + entry would escape root (for zip extraction). */\nexport function isBlockedTarget(root: string, entryPath: string): boolean {\n const target = normalize(join(root, entryPath));\n return target !== root && !target.startsWith(normalize(root) + sep);\n}\n"],"mappings":";;;;;;AAGA,SAAgB,cAAc,SAA0B;CACtD,OACE,YAAY,QACZ,CAAC,QAAQ,WAAW,GAAG,KACvB,CAAC,QAAQ,SAAS,IAAI,KACtB,CAAC,QAAQ,SAAS,IAAI;AAE1B;;AAGA,SAAgB,WAAW,MAAc,WAA4B;CACnE,MAAM,iBAAiB,UAAU,IAAI;CACrC,MAAM,sBAAsB,UAAU,SAAS;CAC/C,OACE,wBAAwB,kBACxB,oBAAoB,WAAW,iBAAiB,GAAG,KACnD,oBAAoB,WAAW,GAAG,eAAe,EAAE;AAEvD;;AAGA,SAAgB,gBAAgB,MAAc,WAA4B;CACxE,MAAM,SAAS,UAAU,KAAK,MAAM,SAAS,CAAC;CAC9C,OAAO,WAAW,QAAQ,CAAC,OAAO,WAAW,UAAU,IAAI,IAAI,GAAG;AACpE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/utils/redact.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Secret redaction for adapter errors, health details, and logs.
|
|
6
|
+
*
|
|
7
|
+
* Adapter-thrown messages routinely embed connection strings and tokens.
|
|
8
|
+
* Every surface that exposes adapter text (503 gate, health report, error
|
|
9
|
+
* logs) must pass through here before truncation or transport.
|
|
10
|
+
*/
|
|
11
|
+
/** Replace embedded secrets with `[redacted]`. Never throws on weird input. */
|
|
12
|
+
declare function redactSecrets(text: string): string;
|
|
13
|
+
/** Redact secrets, then truncate to `maxLength`. */
|
|
14
|
+
declare function sanitizeErrorText(text: string, maxLength: number): string;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { redactSecrets, sanitizeErrorText };
|
|
17
|
+
//# sourceMappingURL=redact.d.mts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/utils/redact.ts
|
|
5
|
+
/**
|
|
6
|
+
* Secret redaction for adapter errors, health details, and logs.
|
|
7
|
+
*
|
|
8
|
+
* Adapter-thrown messages routinely embed connection strings and tokens.
|
|
9
|
+
* Every surface that exposes adapter text (503 gate, health report, error
|
|
10
|
+
* logs) must pass through here before truncation or transport.
|
|
11
|
+
*/
|
|
12
|
+
const SECRET_PATTERNS = [
|
|
13
|
+
/(:\/\/)[^/\s:]+:[^/\s@]+(?=@)/u,
|
|
14
|
+
/([?&#](?:token|secret|password|api[_-]?key|auth[_-]?token|access[_-]?key)=)[^&#\s]*/giu,
|
|
15
|
+
/((?:password|passwd|secret|token|api[_-]?key|auth[_-]?token|client[_-]?secret|access[_-]?key|private[_-]?key)\s*[:=]\s*['"]?)[^\s'";,[\]&]+/giu,
|
|
16
|
+
/AKIA[0-9A-Z]{16}/gu,
|
|
17
|
+
/gh[pous]_[A-Za-z0-9_]+/gu,
|
|
18
|
+
/github_pat_[A-Za-z0-9_]+/gu,
|
|
19
|
+
/xox[bpasr]-[A-Za-z0-9-]+/gu,
|
|
20
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/gu
|
|
21
|
+
];
|
|
22
|
+
/** Replace embedded secrets with `[redacted]`. Never throws on weird input. */
|
|
23
|
+
function redactSecrets(text) {
|
|
24
|
+
let redacted = text;
|
|
25
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
26
|
+
pattern.lastIndex = 0;
|
|
27
|
+
redacted = redacted.replace(pattern, (...args) => {
|
|
28
|
+
const group = args[1];
|
|
29
|
+
return typeof group === "string" ? `${group}[redacted]` : "[redacted]";
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return redacted;
|
|
33
|
+
}
|
|
34
|
+
/** Redact secrets, then truncate to `maxLength`. */
|
|
35
|
+
function sanitizeErrorText(text, maxLength) {
|
|
36
|
+
const redacted = redactSecrets(text);
|
|
37
|
+
return redacted.length > maxLength ? redacted.slice(0, maxLength) : redacted;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { redactSecrets, sanitizeErrorText };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=redact.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.mjs","names":[],"sources":["../../src/utils/redact.ts"],"sourcesContent":["/**\n * Secret redaction for adapter errors, health details, and logs.\n *\n * Adapter-thrown messages routinely embed connection strings and tokens.\n * Every surface that exposes adapter text (503 gate, health report, error\n * logs) must pass through here before truncation or transport.\n */\n\nconst SECRET_PATTERNS: RegExp[] = [\n /(:\\/\\/)[^/\\s:]+:[^/\\s@]+(?=@)/u,\n /([?&#](?:token|secret|password|api[_-]?key|auth[_-]?token|access[_-]?key)=)[^&#\\s]*/giu,\n /((?:password|passwd|secret|token|api[_-]?key|auth[_-]?token|client[_-]?secret|access[_-]?key|private[_-]?key)\\s*[:=]\\s*['\"]?)[^\\s'\";,[\\]&]+/giu,\n /AKIA[0-9A-Z]{16}/gu,\n /gh[pous]_[A-Za-z0-9_]+/gu,\n /github_pat_[A-Za-z0-9_]+/gu,\n /xox[bpasr]-[A-Za-z0-9-]+/gu,\n /-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----/gu,\n];\n\n/** Replace embedded secrets with `[redacted]`. Never throws on weird input. */\nexport function redactSecrets(text: string): string {\n let redacted = text;\n for (const pattern of SECRET_PATTERNS) {\n pattern.lastIndex = 0;\n redacted = redacted.replace(pattern, (...args: unknown[]) => {\n const group = args[1];\n return typeof group === \"string\" ? `${group}[redacted]` : \"[redacted]\";\n });\n }\n return redacted;\n}\n\n/** Redact secrets, then truncate to `maxLength`. */\nexport function sanitizeErrorText(text: string, maxLength: number): string {\n const redacted = redactSecrets(text);\n return redacted.length > maxLength ? redacted.slice(0, maxLength) : redacted;\n}\n"],"mappings":";;;;;;;;;;;AAQA,MAAM,kBAA4B;CAChC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAgB,cAAc,MAAsB;CAClD,IAAI,WAAW;CACf,KAAK,MAAM,WAAW,iBAAiB;EACrC,QAAQ,YAAY;EACpB,WAAW,SAAS,QAAQ,UAAU,GAAG,SAAoB;GAC3D,MAAM,QAAQ,KAAK;GACnB,OAAO,OAAO,UAAU,WAAW,GAAG,MAAM,cAAc;EAC5D,CAAC;CACH;CACA,OAAO;AACT;;AAGA,SAAgB,kBAAkB,MAAc,WAA2B;CACzE,MAAM,WAAW,cAAc,IAAI;CACnC,OAAO,SAAS,SAAS,YAAY,SAAS,MAAM,GAAG,SAAS,IAAI;AACtE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/utils/timing.d.ts
|
|
4
|
+
/** Aggregated durations for one scope (family/phase name → total ms). */
|
|
5
|
+
type TimingMap = Record<string, number>;
|
|
6
|
+
/** Run `fn` with a fresh timing scope, returning its result and aggregates. */
|
|
7
|
+
declare function runWithTimings<T>(fn: () => T | Promise<T>): Promise<{
|
|
8
|
+
result: T;
|
|
9
|
+
timings: TimingMap;
|
|
10
|
+
}>;
|
|
11
|
+
/** Add `durationMs` to `name` in the active scope (no-op when scopeless). */
|
|
12
|
+
declare function addTiming(name: string, durationMs: number): void;
|
|
13
|
+
/** Run `fn`, recording its wall duration under `name` in the active scope. */
|
|
14
|
+
declare function timed<T>(name: string, fn: () => T | Promise<T>): Promise<T>;
|
|
15
|
+
/** Copy of aggregates with whole-millisecond values for logs and headers. */
|
|
16
|
+
declare function roundedTimings(timings: TimingMap): TimingMap;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { TimingMap, addTiming, roundedTimings, runWithTimings, timed };
|
|
19
|
+
//# sourceMappingURL=timing.d.mts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
//#region src/utils/timing.ts
|
|
6
|
+
/**
|
|
7
|
+
* Per-scope timing recorder: aggregate millisecond sums under shared names.
|
|
8
|
+
*
|
|
9
|
+
* Framework- and telemetry-free (ALS + numbers only) so any host — the Hono
|
|
10
|
+
* app, the remote worker, or a third-party server — can open a scope. The
|
|
11
|
+
* app folds request scopes into `Server-Timing`; background scopes surface
|
|
12
|
+
* as log lines and attempt history. Without an open scope every call is a
|
|
13
|
+
* cheap no-op, keeping unit tests and sleeping workers silent.
|
|
14
|
+
*/
|
|
15
|
+
const scopes = new AsyncLocalStorage();
|
|
16
|
+
/** Run `fn` with a fresh timing scope, returning its result and aggregates. */
|
|
17
|
+
async function runWithTimings(fn) {
|
|
18
|
+
const timings = {};
|
|
19
|
+
return {
|
|
20
|
+
result: await scopes.run(timings, fn),
|
|
21
|
+
timings
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Add `durationMs` to `name` in the active scope (no-op when scopeless). */
|
|
25
|
+
function addTiming(name, durationMs) {
|
|
26
|
+
const timings = scopes.getStore();
|
|
27
|
+
if (!timings) return;
|
|
28
|
+
timings[name] = (timings[name] ?? 0) + durationMs;
|
|
29
|
+
}
|
|
30
|
+
/** Run `fn`, recording its wall duration under `name` in the active scope. */
|
|
31
|
+
async function timed(name, fn) {
|
|
32
|
+
const started = performance.now();
|
|
33
|
+
try {
|
|
34
|
+
return await fn();
|
|
35
|
+
} finally {
|
|
36
|
+
addTiming(name, performance.now() - started);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Copy of aggregates with whole-millisecond values for logs and headers. */
|
|
40
|
+
function roundedTimings(timings) {
|
|
41
|
+
return Object.fromEntries(Object.entries(timings).map(([name, ms]) => [name, Math.round(ms)]));
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { addTiming, roundedTimings, runWithTimings, timed };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=timing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.mjs","names":[],"sources":["../../src/utils/timing.ts"],"sourcesContent":["/**\n * Per-scope timing recorder: aggregate millisecond sums under shared names.\n *\n * Framework- and telemetry-free (ALS + numbers only) so any host — the Hono\n * app, the remote worker, or a third-party server — can open a scope. The\n * app folds request scopes into `Server-Timing`; background scopes surface\n * as log lines and attempt history. Without an open scope every call is a\n * cheap no-op, keeping unit tests and sleeping workers silent.\n */\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\n/** Aggregated durations for one scope (family/phase name → total ms). */\nexport type TimingMap = Record<string, number>;\n\nconst scopes = new AsyncLocalStorage<TimingMap>();\n\n/** Run `fn` with a fresh timing scope, returning its result and aggregates. */\nexport async function runWithTimings<T>(\n fn: () => T | Promise<T>,\n): Promise<{ result: T; timings: TimingMap }> {\n const timings: TimingMap = {};\n const result = await scopes.run(timings, fn);\n return { result, timings };\n}\n\n/** Add `durationMs` to `name` in the active scope (no-op when scopeless). */\nexport function addTiming(name: string, durationMs: number): void {\n const timings = scopes.getStore();\n if (!timings) {\n return;\n }\n timings[name] = (timings[name] ?? 0) + durationMs;\n}\n\n/** Run `fn`, recording its wall duration under `name` in the active scope. */\nexport async function timed<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n const started = performance.now();\n try {\n return await fn();\n } finally {\n addTiming(name, performance.now() - started);\n }\n}\n\n/** Copy of aggregates with whole-millisecond values for logs and headers. */\nexport function roundedTimings(timings: TimingMap): TimingMap {\n return Object.fromEntries(Object.entries(timings).map(([name, ms]) => [name, Math.round(ms)]));\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,MAAM,SAAS,IAAI,kBAA6B;;AAGhD,eAAsB,eACpB,IAC4C;CAC5C,MAAM,UAAqB,CAAC;CAE5B,OAAO;EAAE,QAAA,MADY,OAAO,IAAI,SAAS,EAAE;EAC1B;CAAQ;AAC3B;;AAGA,SAAgB,UAAU,MAAc,YAA0B;CAChE,MAAM,UAAU,OAAO,SAAS;CAChC,IAAI,CAAC,SACH;CAEF,QAAQ,SAAS,QAAQ,SAAS,KAAK;AACzC;;AAGA,eAAsB,MAAS,MAAc,IAAsC;CACjF,MAAM,UAAU,YAAY,IAAI;CAChC,IAAI;EACF,OAAO,MAAM,GAAG;CAClB,UAAU;EACR,UAAU,MAAM,YAAY,IAAI,IAAI,OAAO;CAC7C;AACF;;AAGA,SAAgB,eAAe,SAA+B;CAC5D,OAAO,OAAO,YAAY,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;AAC/F"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/utils/ulid.d.ts
|
|
4
|
+
/** Generate a sortable, collision-resistant ULID. */
|
|
5
|
+
declare function ulid(): string;
|
|
6
|
+
/** Convert a name to a URL-safe slug of at most 63 characters. */
|
|
7
|
+
declare function slugify(value: string): string;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { slugify, ulid };
|
|
10
|
+
//# sourceMappingURL=ulid.d.mts.map
|
package/dist/utils/ulid.mjs
CHANGED
|
@@ -3,6 +3,14 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
//#region src/utils/ulid.ts
|
|
6
|
+
/** Generate a sortable, collision-resistant ULID. */
|
|
7
|
+
function ulid() {
|
|
8
|
+
return encodeTime(Date.now()) + encodeRandom(randomBytes(10));
|
|
9
|
+
}
|
|
10
|
+
/** Convert a name to a URL-safe slug of at most 63 characters. */
|
|
11
|
+
function slugify(value) {
|
|
12
|
+
return value.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 63);
|
|
13
|
+
}
|
|
6
14
|
const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
7
15
|
function encodeTime(time) {
|
|
8
16
|
let out = "";
|
|
@@ -29,14 +37,6 @@ function encodeRandom(bytes) {
|
|
|
29
37
|
if (bits > 0) out += CROCKFORD.charAt(buffer << 5 - bits & 31);
|
|
30
38
|
return out;
|
|
31
39
|
}
|
|
32
|
-
/** Generate a sortable, collision-resistant ULID. */
|
|
33
|
-
function ulid() {
|
|
34
|
-
return encodeTime(Date.now()) + encodeRandom(randomBytes(10));
|
|
35
|
-
}
|
|
36
|
-
/** Convert a name to a URL-safe slug of at most 63 characters. */
|
|
37
|
-
function slugify(value) {
|
|
38
|
-
return value.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 63);
|
|
39
|
-
}
|
|
40
40
|
//#endregion
|
|
41
41
|
export { slugify, ulid };
|
|
42
42
|
|
package/dist/utils/ulid.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ulid.mjs","names":[],"sources":["../../src/utils/ulid.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\n\nconst CROCKFORD = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\n\nfunction encodeTime(time: number): string {\n let out = \"\";\n let remaining = time;\n for (let i = 9; i >= 0; i -= 1) {\n const mod = remaining % 32;\n out = CROCKFORD.charAt(mod) + out;\n remaining = (remaining - mod) / 32;\n }\n return out;\n}\n\n/* eslint-disable no-bitwise, no-non-null-assertion -- ULID encoding is inherently bitwise. */\nfunction encodeRandom(bytes: Buffer): string {\n let out = \"\";\n let buffer = 0;\n let bits = 0;\n for (const byte of bytes) {\n buffer = (buffer << 8) | byte;\n bits += 8;\n while (bits >= 5) {\n out += CROCKFORD.charAt((buffer >>> (bits - 5)) & 31);\n bits -= 5;\n }\n }\n if (bits > 0) {\n out += CROCKFORD.charAt((buffer << (5 - bits)) & 31);\n }\n return out;\n}\n/* eslint-enable no-bitwise, no-non-null-assertion */\n
|
|
1
|
+
{"version":3,"file":"ulid.mjs","names":[],"sources":["../../src/utils/ulid.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\n\n/** Generate a sortable, collision-resistant ULID. */\nexport function ulid(): string {\n return encodeTime(Date.now()) + encodeRandom(randomBytes(10));\n}\n\n/** Convert a name to a URL-safe slug of at most 63 characters. */\nexport function slugify(value: string): string {\n return value\n .toLowerCase()\n .replaceAll(/[^a-z0-9]+/gu, \"-\")\n .replaceAll(/^-+|-+$/gu, \"\")\n .slice(0, 63);\n}\n\nconst CROCKFORD = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\n\nfunction encodeTime(time: number): string {\n let out = \"\";\n let remaining = time;\n for (let i = 9; i >= 0; i -= 1) {\n const mod = remaining % 32;\n out = CROCKFORD.charAt(mod) + out;\n remaining = (remaining - mod) / 32;\n }\n return out;\n}\n\n/* eslint-disable no-bitwise, no-non-null-assertion -- ULID encoding is inherently bitwise. */\nfunction encodeRandom(bytes: Buffer): string {\n let out = \"\";\n let buffer = 0;\n let bits = 0;\n for (const byte of bytes) {\n buffer = (buffer << 8) | byte;\n bits += 8;\n while (bits >= 5) {\n out += CROCKFORD.charAt((buffer >>> (bits - 5)) & 31);\n bits -= 5;\n }\n }\n if (bits > 0) {\n out += CROCKFORD.charAt((buffer << (5 - bits)) & 31);\n }\n return out;\n}\n/* eslint-enable no-bitwise, no-non-null-assertion */\n"],"mappings":";;;;;;AAGA,SAAgB,OAAe;CAC7B,OAAO,WAAW,KAAK,IAAI,CAAC,IAAI,aAAa,YAAY,EAAE,CAAC;AAC9D;;AAGA,SAAgB,QAAQ,OAAuB;CAC7C,OAAO,MACJ,YAAY,CAAC,CACb,WAAW,gBAAgB,GAAG,CAAC,CAC/B,WAAW,aAAa,EAAE,CAAC,CAC3B,MAAM,GAAG,EAAE;AAChB;AAEA,MAAM,YAAY;AAElB,SAAS,WAAW,MAAsB;CACxC,IAAI,MAAM;CACV,IAAI,YAAY;CAChB,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG;EAC9B,MAAM,MAAM,YAAY;EACxB,MAAM,UAAU,OAAO,GAAG,IAAI;EAC9B,aAAa,YAAY,OAAO;CAClC;CACA,OAAO;AACT;AAGA,SAAS,aAAa,OAAuB;CAC3C,IAAI,MAAM;CACV,IAAI,SAAS;CACb,IAAI,OAAO;CACX,KAAK,MAAM,QAAQ,OAAO;EACxB,SAAU,UAAU,IAAK;EACzB,QAAQ;EACR,OAAO,QAAQ,GAAG;GAChB,OAAO,UAAU,OAAQ,WAAY,OAAO,IAAM,EAAE;GACpD,QAAQ;EACV;CACF;CACA,IAAI,OAAO,GACT,OAAO,UAAU,OAAQ,UAAW,IAAI,OAAS,EAAE;CAErD,OAAO;AACT"}
|
package/dist/utils.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { KeyUsed, SecretInput, SecretKeys, UndecryptableCredentialError, decrypt, decryptCredential, decryptWithKey, encrypt } from "./utils/encrypt.mjs";
|
|
4
|
+
import { hmacSha256, randomToken, sha256, timingSafeEqualString } from "./utils/hash.mjs";
|
|
5
|
+
import { HttpError, HttpRequestOptions, HttpTextOptions, httpJson, httpText } from "./utils/http.mjs";
|
|
6
|
+
import { baselinePath, diffPath, screenshotPath, storybookDir, storybookZipPath } from "./paths.mjs";
|
|
7
|
+
import { MIME_TYPES, mimeFor } from "./utils/mime.mjs";
|
|
8
|
+
import { isBlockedTarget, isPathSafe, isSafeSegment } from "./utils/path-security.mjs";
|
|
9
|
+
import { redactSecrets, sanitizeErrorText } from "./utils/redact.mjs";
|
|
10
|
+
import { TimingMap, addTiming, roundedTimings, runWithTimings, timed } from "./utils/timing.mjs";
|
|
11
|
+
import { slugify, ulid } from "./utils/ulid.mjs";
|
|
12
|
+
export { HttpError, type HttpRequestOptions, type HttpTextOptions, type KeyUsed, MIME_TYPES, type SecretInput, type SecretKeys, type TimingMap, UndecryptableCredentialError, addTiming, baselinePath, decrypt, decryptCredential, decryptWithKey, diffPath, encrypt, hmacSha256, httpJson, httpText, isBlockedTarget, isPathSafe, isSafeSegment, mimeFor, randomToken, redactSecrets, roundedTimings, runWithTimings, sanitizeErrorText, screenshotPath, sha256, slugify, storybookDir, storybookZipPath, timed, timingSafeEqualString, ulid };
|
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { redactSecrets, sanitizeErrorText } from "./utils/redact.mjs";
|
|
5
|
+
import { UndecryptableCredentialError, decrypt, decryptCredential, decryptWithKey, encrypt } from "./utils/encrypt.mjs";
|
|
6
|
+
import { slugify, ulid } from "./utils/ulid.mjs";
|
|
7
|
+
import { hmacSha256, randomToken, sha256, timingSafeEqualString } from "./utils/hash.mjs";
|
|
8
|
+
import { addTiming, roundedTimings, runWithTimings, timed } from "./utils/timing.mjs";
|
|
9
|
+
import { isBlockedTarget, isPathSafe, isSafeSegment } from "./utils/path-security.mjs";
|
|
10
|
+
import { baselinePath, diffPath, screenshotPath, storybookDir, storybookZipPath } from "./paths.mjs";
|
|
11
|
+
import { HttpError, httpJson, httpText } from "./utils/http.mjs";
|
|
12
|
+
import { MIME_TYPES, mimeFor } from "./utils/mime.mjs";
|
|
13
|
+
export { HttpError, MIME_TYPES, UndecryptableCredentialError, addTiming, baselinePath, decrypt, decryptCredential, decryptWithKey, diffPath, encrypt, hmacSha256, httpJson, httpText, isBlockedTarget, isPathSafe, isSafeSegment, mimeFor, randomToken, redactSecrets, roundedTimings, runWithTimings, sanitizeErrorText, screenshotPath, sha256, slugify, storybookDir, storybookZipPath, timed, timingSafeEqualString, ulid };
|