@apifuse/provider-sdk 2.2.0-beta.69 → 2.2.0-beta.70
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/AUTHORING.md +17 -0
- package/CHANGELOG.md +4 -0
- package/README.md +2 -0
- package/dist/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +7 -4
- package/dist/health-scenario.d.ts +34 -13
- package/dist/health-scenario.js +34 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lint.js +37 -1
- package/dist/provider.d.ts +11 -11
- package/dist/provider.js +6 -6
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/runtime-diagnostics.d.ts +165 -0
- package/dist/server/runtime-diagnostics.js +360 -0
- package/dist/server/serve-implementation.js +16 -0
- package/package.json +1 -1
- package/src/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +7 -4
- package/src/health-scenario.ts +60 -13
- package/src/index.ts +1 -0
- package/src/lint.ts +42 -1
- package/src/provider.ts +130 -129
- package/src/server/index.ts +28 -0
- package/src/server/runtime-diagnostics.ts +522 -0
- package/src/server/serve-implementation.ts +22 -0
package/AUTHORING.md
CHANGED
|
@@ -167,6 +167,23 @@ only for a provider already pinned to an SDK release that serves the route.
|
|
|
167
167
|
Earlier pins answer `404`, and a failing readiness/startup probe is not
|
|
168
168
|
self-healing, so manifests move to `/readyz` after the pin wave, never before.
|
|
169
169
|
|
|
170
|
+
`GET /__apifuse/diagnostics/runtime` is the internal runtime diagnostics route on
|
|
171
|
+
the same listener. It answers one JSON report (`schemaVersion: 1`) sampled over a
|
|
172
|
+
short window (`?windowMs=`, default 250, clamped to 50..5000): `cpu.window`
|
|
173
|
+
(`process.cpuUsage()` delta as cores, user/system split), `cpu.lifetime`,
|
|
174
|
+
`memory`, `eventLoop` (`performance.eventLoopUtilization`), `activeResources`
|
|
175
|
+
(`process.getActiveResourcesInfo()` counts by type) and, on Linux, `procfs`
|
|
176
|
+
with per-thread CPU ticks, context switches, wait channel and file-descriptor
|
|
177
|
+
counts by kind from `/proc/self`. Bun 1.2 and 1.3 stub the two Node APIs, so
|
|
178
|
+
their `reported` flag is `false` there; `cpu.window` and `procfs.threads`
|
|
179
|
+
(sorted hottest first, named `bun`, `HTTP Client`, `HeapHelper`, ...) are the
|
|
180
|
+
signals that tell an idle process that still burns CPU apart from a busy one.
|
|
181
|
+
The route is read-only and carries no secrets. It is internal by the same
|
|
182
|
+
boundary as `/health` and `/readyz`: the generated provider NetworkPolicy admits
|
|
183
|
+
only the gateway on this port and the gateway dials canonical operation paths
|
|
184
|
+
only, so operators reach it with `kubectl port-forward` and the tenant-facing
|
|
185
|
+
API never does.
|
|
186
|
+
|
|
170
187
|
### Deployment intent
|
|
171
188
|
|
|
172
189
|
Deployment intent (runtime profile, resources, HPA, Redis, extra TCP ports) has
|
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -40,6 +40,8 @@ Do not use internal monorepo placement for bounty workspaces. Accepted provider
|
|
|
40
40
|
- Dev default: `3900`
|
|
41
41
|
- Start/Docker/container contract: `3000`
|
|
42
42
|
- `GET /health`
|
|
43
|
+
- `GET /readyz`
|
|
44
|
+
- `GET /__apifuse/diagnostics/runtime` (internal runtime diagnostics, see `AUTHORING.md`)
|
|
43
45
|
- `POST /v1/{operation}`
|
|
44
46
|
- `POST /auth/start`
|
|
45
47
|
- `POST /auth/continue`
|
package/dist/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl
CHANGED
|
@@ -116,7 +116,7 @@ Add ONE guard step per stale-if-error probe:
|
|
|
116
116
|
{
|
|
117
117
|
operationId: "list-items",
|
|
118
118
|
status: "degraded",
|
|
119
|
-
reasonCode: "
|
|
119
|
+
reasonCode: "served_stale_cache",
|
|
120
120
|
reasonKey: "health.operations.list-items.dense-district.servedStaleCache",
|
|
121
121
|
},
|
|
122
122
|
],
|
|
@@ -128,9 +128,12 @@ Add ONE guard step per stale-if-error probe:
|
|
|
128
128
|
- `degraded`, not `down`: the cache policy is behaving as promised and callers
|
|
129
129
|
are still served; it is the upstream that is unavailable, and that has to be
|
|
130
130
|
visible instead of green.
|
|
131
|
-
- `
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
- `served_stale_cache`, not `expected_absence`: the platform publishes a
|
|
132
|
+
stale serve as `degraded` (an upstream fault that opens incidents), while
|
|
133
|
+
`expected_absence` is published as a non-incident status — neither ok nor
|
|
134
|
+
degraded, excluded from uptime — for an absence the provider declares in
|
|
135
|
+
advance (no alert today, a closed shelf, a feed outside its hours). The
|
|
136
|
+
tenant-facing wording lives in the localized `reasonKey`.
|
|
134
137
|
- Place the freshness guard BEFORE any row or emptiness guard. A stale serve
|
|
135
138
|
that happens to be empty would otherwise be attributed to the emptiness
|
|
136
139
|
reason, which is a confident answer to the wrong question.
|
|
@@ -1549,7 +1549,25 @@ export type StepBase = {
|
|
|
1549
1549
|
result: string;
|
|
1550
1550
|
timeoutMs?: number;
|
|
1551
1551
|
};
|
|
1552
|
-
|
|
1552
|
+
/**
|
|
1553
|
+
* Why a guard stopped the scenario. The platform decides what each reason
|
|
1554
|
+
* publishes; the attribution's `status` is only the scenario rollup.
|
|
1555
|
+
*
|
|
1556
|
+
* - `expected_absence`: the upstream answered exactly as this provider says it
|
|
1557
|
+
* does when there is nothing to return — no weather alert today, an empty
|
|
1558
|
+
* shelf, a transit feed outside its operating hours. Published as the
|
|
1559
|
+
* non-incident status `expected_absence`: neither ok nor degraded, excluded
|
|
1560
|
+
* from uptime, never an incident. Use it only for an absence the provider
|
|
1561
|
+
* can declare in advance. Data that must be there (a product that must have
|
|
1562
|
+
* options) is a failing assertion, not an expected absence.
|
|
1563
|
+
* - `served_stale_cache`: the operation step was answered from the
|
|
1564
|
+
* stale-if-error window (`served_stale_cache` on the step result) instead
|
|
1565
|
+
* of a live read. A measured upstream verdict: published `degraded`, opens
|
|
1566
|
+
* incidents.
|
|
1567
|
+
*/
|
|
1568
|
+
export type GuardReasonCode = "expected_absence" | "served_stale_cache";
|
|
1569
|
+
/** The closed vocabulary as a non-empty tuple, for schema and lint consumers. */
|
|
1570
|
+
export declare const GUARD_REASON_CODES: [GuardReasonCode, ...GuardReasonCode[]];
|
|
1553
1571
|
export type GuardAttribution = {
|
|
1554
1572
|
operationId: string;
|
|
1555
1573
|
status: "degraded";
|
|
@@ -1579,7 +1597,10 @@ export type OperationResult = {
|
|
|
1579
1597
|
* fails the step rather than projecting as fresh.
|
|
1580
1598
|
*
|
|
1581
1599
|
* Providers that serve stale-if-error should guard on it, so an outage the
|
|
1582
|
-
* cache is absorbing stops reading as green
|
|
1600
|
+
* cache is absorbing stops reading as green. Attribute it
|
|
1601
|
+
* `served_stale_cache`, not `expected_absence`: a stale serve is an upstream
|
|
1602
|
+
* fault the platform publishes as `degraded`, while an expected absence is
|
|
1603
|
+
* published as a non-incident status.
|
|
1583
1604
|
*
|
|
1584
1605
|
* ```ts
|
|
1585
1606
|
* {
|
|
@@ -1593,7 +1614,7 @@ export type OperationResult = {
|
|
|
1593
1614
|
* expected: true,
|
|
1594
1615
|
* },
|
|
1595
1616
|
* onFail: {
|
|
1596
|
-
* attribute: [{ operationId, status: "degraded", reasonCode: "
|
|
1617
|
+
* attribute: [{ operationId, status: "degraded", reasonCode: "served_stale_cache", reasonKey }],
|
|
1597
1618
|
* stop: "scenario",
|
|
1598
1619
|
* },
|
|
1599
1620
|
* }
|
|
@@ -1719,27 +1740,27 @@ export declare const HealthStepSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1719
1740
|
attribute: z.ZodPipe<z.ZodArray<z.ZodType<{
|
|
1720
1741
|
operationId: string;
|
|
1721
1742
|
status: "degraded";
|
|
1722
|
-
reasonCode: "expected_absence";
|
|
1743
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1723
1744
|
reasonKey: string;
|
|
1724
1745
|
}, unknown, z.core.$ZodTypeInternals<{
|
|
1725
1746
|
operationId: string;
|
|
1726
1747
|
status: "degraded";
|
|
1727
|
-
reasonCode: "expected_absence";
|
|
1748
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1728
1749
|
reasonKey: string;
|
|
1729
1750
|
}, unknown>>>, z.ZodTransform<[{
|
|
1730
1751
|
operationId: string;
|
|
1731
1752
|
status: "degraded";
|
|
1732
|
-
reasonCode: "expected_absence";
|
|
1753
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1733
1754
|
reasonKey: string;
|
|
1734
1755
|
}, ...{
|
|
1735
1756
|
operationId: string;
|
|
1736
1757
|
status: "degraded";
|
|
1737
|
-
reasonCode: "expected_absence";
|
|
1758
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1738
1759
|
reasonKey: string;
|
|
1739
1760
|
}[]], {
|
|
1740
1761
|
operationId: string;
|
|
1741
1762
|
status: "degraded";
|
|
1742
|
-
reasonCode: "expected_absence";
|
|
1763
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1743
1764
|
reasonKey: string;
|
|
1744
1765
|
}[]>>;
|
|
1745
1766
|
stop: z.ZodLiteral<"scenario">;
|
|
@@ -1811,27 +1832,27 @@ export declare const GuardStepSchema: z.ZodObject<{
|
|
|
1811
1832
|
attribute: z.ZodPipe<z.ZodArray<z.ZodType<{
|
|
1812
1833
|
operationId: string;
|
|
1813
1834
|
status: "degraded";
|
|
1814
|
-
reasonCode: "expected_absence";
|
|
1835
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1815
1836
|
reasonKey: string;
|
|
1816
1837
|
}, unknown, z.core.$ZodTypeInternals<{
|
|
1817
1838
|
operationId: string;
|
|
1818
1839
|
status: "degraded";
|
|
1819
|
-
reasonCode: "expected_absence";
|
|
1840
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1820
1841
|
reasonKey: string;
|
|
1821
1842
|
}, unknown>>>, z.ZodTransform<[{
|
|
1822
1843
|
operationId: string;
|
|
1823
1844
|
status: "degraded";
|
|
1824
|
-
reasonCode: "expected_absence";
|
|
1845
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1825
1846
|
reasonKey: string;
|
|
1826
1847
|
}, ...{
|
|
1827
1848
|
operationId: string;
|
|
1828
1849
|
status: "degraded";
|
|
1829
|
-
reasonCode: "expected_absence";
|
|
1850
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1830
1851
|
reasonKey: string;
|
|
1831
1852
|
}[]], {
|
|
1832
1853
|
operationId: string;
|
|
1833
1854
|
status: "degraded";
|
|
1834
|
-
reasonCode: "expected_absence";
|
|
1855
|
+
reasonCode: "expected_absence" | "served_stale_cache";
|
|
1835
1856
|
reasonKey: string;
|
|
1836
1857
|
}[]>>;
|
|
1837
1858
|
stop: z.ZodLiteral<"scenario">;
|
package/dist/health-scenario.js
CHANGED
|
@@ -172,16 +172,32 @@ export const SafeRegexSchema = z
|
|
|
172
172
|
.strict()
|
|
173
173
|
.superRefine((value, ctx) => {
|
|
174
174
|
if (/\\[1-9kg]/.test(value.pattern))
|
|
175
|
-
ctx.addIssue({
|
|
175
|
+
ctx.addIssue({
|
|
176
|
+
code: "custom",
|
|
177
|
+
path: ["pattern"],
|
|
178
|
+
message: "backreferences are not supported by RE2",
|
|
179
|
+
});
|
|
176
180
|
if (/\(\?/.test(value.pattern))
|
|
177
|
-
ctx.addIssue({
|
|
181
|
+
ctx.addIssue({
|
|
182
|
+
code: "custom",
|
|
183
|
+
path: ["pattern"],
|
|
184
|
+
message: "extended groups are not supported by RE2",
|
|
185
|
+
});
|
|
178
186
|
if (containsNestedRegexQuantifier(value.pattern))
|
|
179
|
-
ctx.addIssue({
|
|
187
|
+
ctx.addIssue({
|
|
188
|
+
code: "custom",
|
|
189
|
+
path: ["pattern"],
|
|
190
|
+
message: "nested regex quantifiers are not permitted",
|
|
191
|
+
});
|
|
180
192
|
try {
|
|
181
193
|
new RegExp(value.pattern, value.flags);
|
|
182
194
|
}
|
|
183
195
|
catch {
|
|
184
|
-
ctx.addIssue({
|
|
196
|
+
ctx.addIssue({
|
|
197
|
+
code: "custom",
|
|
198
|
+
path: ["pattern"],
|
|
199
|
+
message: "pattern must be valid regular-expression syntax",
|
|
200
|
+
});
|
|
185
201
|
}
|
|
186
202
|
});
|
|
187
203
|
const operandLiteralSchema = jsonValueSchema.superRefine((value, ctx) => {
|
|
@@ -414,11 +430,24 @@ const stepBaseSchema = z
|
|
|
414
430
|
timeoutMs: finiteInt(1, 600_000).optional(),
|
|
415
431
|
})
|
|
416
432
|
.strict();
|
|
433
|
+
/**
|
|
434
|
+
* Every member of the union, pinned in both directions: a code missing here
|
|
435
|
+
* fails `satisfies Record<GuardReasonCode, true>`, a code added here without
|
|
436
|
+
* the union fails the excess-property check. The union itself stays a
|
|
437
|
+
* literal so the type-only entry points (contract, server, testing) do not
|
|
438
|
+
* have to re-export the runtime tuple.
|
|
439
|
+
*/
|
|
440
|
+
const GUARD_REASON_CODE_SET = {
|
|
441
|
+
expected_absence: true,
|
|
442
|
+
served_stale_cache: true,
|
|
443
|
+
};
|
|
444
|
+
/** The closed vocabulary as a non-empty tuple, for schema and lint consumers. */
|
|
445
|
+
export const GUARD_REASON_CODES = Object.keys(GUARD_REASON_CODE_SET);
|
|
417
446
|
const attributionSchema = z
|
|
418
447
|
.object({
|
|
419
448
|
operationId: z.string().min(1),
|
|
420
449
|
status: z.literal("degraded"),
|
|
421
|
-
reasonCode: z.
|
|
450
|
+
reasonCode: z.enum(GUARD_REASON_CODES),
|
|
422
451
|
reasonKey: z.string().min(1),
|
|
423
452
|
})
|
|
424
453
|
.strict();
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type { ApiFuseConfig, BrowserConfig, ProxyCacheStatus, ProxyProtocol, Pro
|
|
|
4
4
|
export { defineConfig, loadApiFuseConfig, resolveProxy } from "./config/loader.js";
|
|
5
5
|
export { canonicalJson, digestProviderContract, extractProviderContract, type JsonPrimitive, type JsonValue, PROVIDER_CONTRACT_SCHEMA_VERSION, type ProviderContractOperation, type ProviderContractSnapshot, } from "./contract.js";
|
|
6
6
|
export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, type AuthStartNoInputGuard, type OperationDefinitionFor, type ProviderBuilder, type ProviderContextOf, type ProviderDeclaration, type ProviderDefinitionFor, } from "./define.js";
|
|
7
|
-
export { AssertionExpressionSchema, AssertionPredicateSchema, AssertStepSchema, BoundedJsonPathSchema, CandidateBlockSchema, CandidatePolicySchema, CredentialRefDeclarationSchema, defineHealthScenario, HealthScenarioSchema, HealthStepSchema, ExtractStepSchema, FindFirstSchema, GuardStepSchema, JournalPolicySchema, JsonTemplateSchema, ManualTriggerPolicySchema, OperandSchema, OperationStepSchema, QuantifierSchema, ReferenceSchema, RetryPolicySchema, SafeRegexSchema, ScopedAssertionExpressionSchema, ScopedAssertionPredicateSchema, ScopedItemReferenceSchema, ScopedOperandSchema, StepReferenceSchema, RelativeDateNodeSchema, ValueTypeSchema, } from "./health-scenario.js";
|
|
7
|
+
export { AssertionExpressionSchema, AssertionPredicateSchema, AssertStepSchema, BoundedJsonPathSchema, CandidateBlockSchema, CandidatePolicySchema, CredentialRefDeclarationSchema, defineHealthScenario, HealthScenarioSchema, HealthStepSchema, ExtractStepSchema, FindFirstSchema, GUARD_REASON_CODES, GuardStepSchema, JournalPolicySchema, JsonTemplateSchema, ManualTriggerPolicySchema, OperandSchema, OperationStepSchema, QuantifierSchema, ReferenceSchema, RetryPolicySchema, SafeRegexSchema, ScopedAssertionExpressionSchema, ScopedAssertionPredicateSchema, ScopedItemReferenceSchema, ScopedOperandSchema, StepReferenceSchema, RelativeDateNodeSchema, ValueTypeSchema, } from "./health-scenario.js";
|
|
8
8
|
export type { AssertionExpression, AssertionPredicate, AttemptReference, AssertResult, AssertStep, BoundedJsonPath, CandidateBlock, CandidatePolicy, CandidateReference, CredentialReference, CredentialRefDeclaration, EstablishedConnectionReference, ExtractStep, FindFirst, GuardAttribution, GuardReasonCode, GuardResult, GuardStep, HealthScenario, HealthStep, JsonTemplate, JournalPolicy, ManualTriggerPolicy, NonEmpty, OperationResult, OperationStep, Operand, Quantifier, ReferenceNode, Reference, RelativeDateNode, RetryPolicy, SafeRegex, ScopedAssertionExpression, ScopedAssertionPredicate, ScopedItemReference, ScopedOperand, StepBase, StepReference, ExtractResult, ValueType, } from "./health-scenario.js";
|
|
9
9
|
export type { DevServerOptions } from "./dev.js";
|
|
10
10
|
export { createDevServer, startDevServer } from "./dev.js";
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export * from "./ceremonies/index.js";
|
|
|
4
4
|
export { defineConfig, loadApiFuseConfig, resolveProxy } from "./config/loader.js";
|
|
5
5
|
export { canonicalJson, digestProviderContract, extractProviderContract, PROVIDER_CONTRACT_SCHEMA_VERSION, } from "./contract.js";
|
|
6
6
|
export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, } from "./define.js";
|
|
7
|
-
export { AssertionExpressionSchema, AssertionPredicateSchema, AssertStepSchema, BoundedJsonPathSchema, CandidateBlockSchema, CandidatePolicySchema, CredentialRefDeclarationSchema, defineHealthScenario, HealthScenarioSchema, HealthStepSchema, ExtractStepSchema, FindFirstSchema, GuardStepSchema, JournalPolicySchema, JsonTemplateSchema, ManualTriggerPolicySchema, OperandSchema, OperationStepSchema, QuantifierSchema, ReferenceSchema, RetryPolicySchema, SafeRegexSchema, ScopedAssertionExpressionSchema, ScopedAssertionPredicateSchema, ScopedItemReferenceSchema, ScopedOperandSchema, StepReferenceSchema, RelativeDateNodeSchema, ValueTypeSchema, } from "./health-scenario.js";
|
|
7
|
+
export { AssertionExpressionSchema, AssertionPredicateSchema, AssertStepSchema, BoundedJsonPathSchema, CandidateBlockSchema, CandidatePolicySchema, CredentialRefDeclarationSchema, defineHealthScenario, HealthScenarioSchema, HealthStepSchema, ExtractStepSchema, FindFirstSchema, GUARD_REASON_CODES, GuardStepSchema, JournalPolicySchema, JsonTemplateSchema, ManualTriggerPolicySchema, OperandSchema, OperationStepSchema, QuantifierSchema, ReferenceSchema, RetryPolicySchema, SafeRegexSchema, ScopedAssertionExpressionSchema, ScopedAssertionPredicateSchema, ScopedItemReferenceSchema, ScopedOperandSchema, StepReferenceSchema, RelativeDateNodeSchema, ValueTypeSchema, } from "./health-scenario.js";
|
|
8
8
|
export { createDevServer, startDevServer } from "./dev.js";
|
|
9
9
|
export * from "./errors.js";
|
|
10
10
|
export * from "./engine.js";
|
package/dist/lint.js
CHANGED
|
@@ -2740,6 +2740,30 @@ function resultBindingChecksFreshness(steps, binding, operationId, siblingBindin
|
|
|
2740
2740
|
}
|
|
2741
2741
|
return false;
|
|
2742
2742
|
}
|
|
2743
|
+
/**
|
|
2744
|
+
* Whether a freshness guard for this operation still attributes
|
|
2745
|
+
* `expected_absence` — the only code the attribution schema admitted before
|
|
2746
|
+
* `served_stale_cache` existed, so earlier guidance recommended it. It IS
|
|
2747
|
+
* freshness coverage (the guard runs and stops the scenario), which is why
|
|
2748
|
+
* `scenarioChecksFreshness` accepts it; but the platform publishes
|
|
2749
|
+
* `expected_absence` as a non-incident status, so the stale serve it catches
|
|
2750
|
+
* would read as "nothing to return" instead of `degraded`.
|
|
2751
|
+
*/
|
|
2752
|
+
function freshnessGuardAttributesExpectedAbsence(scenario, operationId) {
|
|
2753
|
+
if (!isLintRecord(scenario) || !Array.isArray(scenario.steps))
|
|
2754
|
+
return false;
|
|
2755
|
+
const bindings = operationStepBindings(scenario.steps, operationId);
|
|
2756
|
+
if (bindings.size === 0)
|
|
2757
|
+
return false;
|
|
2758
|
+
return scenario.steps.some((step) => isLintRecord(step) &&
|
|
2759
|
+
step.kind === "guard" &&
|
|
2760
|
+
rejectsStaleServe(step.condition, bindings) &&
|
|
2761
|
+
isLintRecord(step.onFail) &&
|
|
2762
|
+
Array.isArray(step.onFail.attribute) &&
|
|
2763
|
+
step.onFail.attribute.some((entry) => isLintRecord(entry) &&
|
|
2764
|
+
entry.operationId === operationId &&
|
|
2765
|
+
entry.reasonCode === "expected_absence"));
|
|
2766
|
+
}
|
|
2743
2767
|
/** How many uncovered probes the stale-serve message names before eliding. */
|
|
2744
2768
|
const STALE_SERVE_MESSAGE_PROBE_LIMIT = 8;
|
|
2745
2769
|
/**
|
|
@@ -2773,6 +2797,7 @@ function lintHealthCheckMonitorability(provider) {
|
|
|
2773
2797
|
for (const [operationKey, operation] of Object.entries(provider.operations ?? {})) {
|
|
2774
2798
|
const cases = readHealthCheckCases(operation.healthCheck);
|
|
2775
2799
|
const unmonitored = [];
|
|
2800
|
+
const absenceAttributed = [];
|
|
2776
2801
|
for (const [caseIndex, healthCase] of cases.entries()) {
|
|
2777
2802
|
const caseLabel = typeof healthCase.name === "string" && healthCase.name.length > 0
|
|
2778
2803
|
? `"${healthCase.name}"`
|
|
@@ -2785,6 +2810,17 @@ function lintHealthCheckMonitorability(provider) {
|
|
|
2785
2810
|
uncovered.push(`${operationKey} ${caseLabel}`);
|
|
2786
2811
|
uncoveredByOperation.set(operationKey, uncovered);
|
|
2787
2812
|
}
|
|
2813
|
+
if (freshnessGuardAttributesExpectedAbsence(healthCase.scenario, operationKey)) {
|
|
2814
|
+
absenceAttributed.push(caseLabel);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
if (absenceAttributed.length > 0) {
|
|
2818
|
+
diagnostics.push({
|
|
2819
|
+
rule: "health-check-stale-serve-reason",
|
|
2820
|
+
level: "warn",
|
|
2821
|
+
field: `operations.${operationKey}.healthCheck.cases`,
|
|
2822
|
+
message: `${providerLabel} operation "${operationKey}" health-check ${absenceAttributed.length === 1 ? "case" : "cases"} ${absenceAttributed.join(", ")} guard ${SERVED_STALE_CACHE_OPERAND} but attribute reasonCode "expected_absence". The platform publishes expected_absence as a non-incident status (neither ok nor degraded, excluded from uptime and incidents), so an upstream outage this guard catches would read as "nothing to return" instead of degraded. Attribute reasonCode "served_stale_cache" instead; the reasonKey and its copy can stay.`,
|
|
2823
|
+
});
|
|
2788
2824
|
}
|
|
2789
2825
|
if (unmonitored.length > 0) {
|
|
2790
2826
|
diagnostics.push({
|
|
@@ -2840,7 +2876,7 @@ function lintHealthCheckMonitorability(provider) {
|
|
|
2840
2876
|
rule: "health-check-stale-serve-unguarded",
|
|
2841
2877
|
level: "warn",
|
|
2842
2878
|
field: "healthCheck",
|
|
2843
|
-
message: `${providerLabel} serves stale-if-error (staleIfErrorMs in ${[...sources].sort().join(", ")}) and these health-check cases never check ${SERVED_STALE_CACHE_OPERAND}: ${named}. During an upstream outage the cache answers HTTP 200 with a schema-valid body, so every clause over status_code and data still passes and those probes report ok for the whole stale window. Add one guard step per affected probe on { ref: { namespace: "steps", binding: "<operation step result>", path: ["${SERVED_STALE_CACHE_OPERAND}"] } } attributing status "degraded" with reasonCode "expected_absence", placed before any row or emptiness guard.${caveat}`,
|
|
2879
|
+
message: `${providerLabel} serves stale-if-error (staleIfErrorMs in ${[...sources].sort().join(", ")}) and these health-check cases never check ${SERVED_STALE_CACHE_OPERAND}: ${named}. During an upstream outage the cache answers HTTP 200 with a schema-valid body, so every clause over status_code and data still passes and those probes report ok for the whole stale window. Add one guard step per affected probe on { ref: { namespace: "steps", binding: "<operation step result>", path: ["${SERVED_STALE_CACHE_OPERAND}"] } } attributing status "degraded" with reasonCode "served_stale_cache" (a stale serve is an upstream fault; "expected_absence" is the non-incident status for an absence the provider declares in advance), placed before any row or emptiness guard.${caveat}`,
|
|
2844
2880
|
});
|
|
2845
2881
|
return diagnostics;
|
|
2846
2882
|
}
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
export { AuthAbortError, credentialsAuthChallenge, createAuthFlowHelpers, defineCredentialsAuth, } from "./auth.js";
|
|
2
1
|
export type { CredentialsAuthChallengeDefinition, CredentialsAuthChallengeRequest, CredentialsAuthCompleteResult, CredentialsAuthCredential, CredentialsAuthField, CredentialsAuthFields, CredentialsAuthFieldType, CredentialsAuthInput, CredentialsAuthLoginResult, DefineCredentialsAuthOptions, DefinedCredentialsAuth, } from "./auth.js";
|
|
2
|
+
export { AuthAbortError, createAuthFlowHelpers, credentialsAuthChallenge, defineCredentialsAuth, } from "./auth.js";
|
|
3
3
|
export { createFormCeremony } from "./ceremonies/index.js";
|
|
4
|
-
export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define.js";
|
|
5
|
-
export type { OperationDefinitionFor, ProviderBuilder, ProviderContextOf, ProviderDeclaration, ProviderDefinitionFor, } from "./define.js";
|
|
6
4
|
export type { JsonPrimitive, JsonValue } from "./contract-json.js";
|
|
7
|
-
export {
|
|
8
|
-
export
|
|
9
|
-
export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, isTransportError, ProviderEgressDeniedError, ProviderEngineAuthenticationError, ProviderEngineProtocolVersionError, ProviderEngineUnavailableError, ProviderError, type ProviderErrorObservability, SDKError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
|
|
10
|
-
export { createProviderEnvironment, createInProcessProviderEngine, ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RUNTIME_ENV_NAMES, ENGINE_OWNED_TELEMETRY_ENV_NAMES, isEngineOwnedEnvName, isEngineOwnedProxyCredentialName, isEngineOwnedResolverCredentialName, isEngineOwnedRuntimeEnvName, isEngineOwnedTelemetryEnvName, PROVIDER_CAPABILITY_KEYS, PROVIDER_ENGINE_MODE_ENV, PROVIDER_ENGINE_PROTOCOL_VERSION, readEngineProxyCredentials, } from "./engine.js";
|
|
5
|
+
export type { OperationDefinitionFor, ProviderBuilder, ProviderContextOf, ProviderDeclaration, ProviderDefinitionFor, } from "./define.js";
|
|
6
|
+
export { centered, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, delayed, every, } from "./define.js";
|
|
11
7
|
export type { ProviderCapabilityKey, ProviderEngine, ProviderEngineAttachmentInput, ProviderEngineBindingCandidates, ProviderEngineCapabilitySurface, ProviderEngineMode, ProviderEngineRequest, ProviderEngineResidentSurface, ProviderEngineSession, ProviderEngineTransport, } from "./engine.js";
|
|
12
|
-
export {
|
|
8
|
+
export { createInProcessProviderEngine, createProviderEnvironment, ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RUNTIME_ENV_NAMES, ENGINE_OWNED_TELEMETRY_ENV_NAMES, isEngineOwnedEnvName, isEngineOwnedProxyCredentialName, isEngineOwnedResolverCredentialName, isEngineOwnedRuntimeEnvName, isEngineOwnedTelemetryEnvName, PROVIDER_CAPABILITY_KEYS, PROVIDER_ENGINE_MODE_ENV, PROVIDER_ENGINE_PROTOCOL_VERSION, readEngineProxyCredentials, } from "./engine.js";
|
|
9
|
+
export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, isTransportError, ProviderEgressDeniedError, ProviderEngineAuthenticationError, ProviderEngineProtocolVersionError, ProviderEngineUnavailableError, ProviderError, type ProviderErrorObservability, SDKError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
|
|
13
10
|
export * from "./handle.js";
|
|
14
11
|
export { APIFUSE_HANDLE_META_KEY, HANDLE_KIND_NAME_PATTERN, handleFieldDescription, handleFieldNameFor, handleHasDirectionalFieldNames, isHandleFieldMeta, } from "./handle-meta.js";
|
|
12
|
+
export type { AssertionExpression, AssertionPredicate, AssertResult, AssertStep, AttemptReference, BoundedJsonPath, CandidateBlock, CandidatePolicy, CandidateReference, CredentialRefDeclaration, CredentialReference, EstablishedConnectionReference, ExtractResult, ExtractStep, FindFirst, GuardAttribution, GuardReasonCode, GuardResult, GuardStep, HealthScenario, HealthStep, JournalPolicy, JsonTemplate, ManualTriggerPolicy, NonEmpty, Operand, OperationResult, OperationStep, Quantifier, Reference, ReferenceNode, RelativeDateNode, RetryPolicy, SafeRegex, ScopedAssertionExpression, ScopedAssertionPredicate, ScopedItemReference, ScopedOperand, StepBase, StepReference, ValueType, } from "./health-scenario.js";
|
|
13
|
+
export { AssertionExpressionSchema, AssertionPredicateSchema, AssertStepSchema, BoundedJsonPathSchema, CandidateBlockSchema, CandidatePolicySchema, CredentialRefDeclarationSchema, defineHealthScenario, ExtractStepSchema, FindFirstSchema, GUARD_REASON_CODES, GuardStepSchema, HealthScenarioSchema, HealthStepSchema, JournalPolicySchema, JsonTemplateSchema, ManualTriggerPolicySchema, OperandSchema, OperationStepSchema, QuantifierSchema, ReferenceSchema, RelativeDateNodeSchema, RetryPolicySchema, SafeRegexSchema, ScopedAssertionExpressionSchema, ScopedAssertionPredicateSchema, ScopedItemReferenceSchema, ScopedOperandSchema, StepReferenceSchema, ValueTypeSchema, } from "./health-scenario.js";
|
|
14
|
+
export { getProviderLocalePath, type ProviderErrorMessageParams, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
|
|
15
15
|
export { type CreateHandleContextOptions, type CreateTestHandleContextOptions, createHandleContext, createTestHandleContext, type HandleNormalizationClass, type NormalizedHandle, normalizeHandle, } from "./runtime/handle.js";
|
|
16
|
+
export type { NativeGatewayProxy, NativeGatewayProxyResolutionInput, NativeGatewayProxySkipReason, NativeGatewayProxySynthesisInput, NativeGatewayProxySynthesisResult, NativeGatewayProxySynthesizer, NativeNetworkClientOptions, NativeNetworkErrorCode, VendorCredentialLookup, VendorCredentialResolver, } from "./runtime/native-network.js";
|
|
17
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
16
18
|
export { createMemoryProviderRuntimeState, createUnsupportedProviderRuntimeState, } from "./runtime/state.js";
|
|
17
19
|
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, untrustedContent, z, } from "./schema.js";
|
|
18
|
-
export type { AuthAbortData, AuthAbortRetry, AuthFlowTerminalContext, AuthMode, AuthSafeData, AuthSafeJson, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthScheduleRandomization, HttpAttemptContext, HttpHeadersFactory, HttpRedirectFailureReason, HttpRedirectPolicy, HttpRedirectPolicyMode, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, NativeContext, NativeNetworkClient, NativeNetworkCloseReason,
|
|
19
|
-
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
20
|
-
export type { NativeGatewayProxy, NativeGatewayProxyResolutionInput, NativeGatewayProxySkipReason, NativeGatewayProxySynthesizer, NativeGatewayProxySynthesisResult, NativeGatewayProxySynthesisInput, NativeNetworkClientOptions, NativeNetworkErrorCode, VendorCredentialLookup, VendorCredentialResolver, } from "./runtime/native-network.js";
|
|
20
|
+
export type { AuthAbortData, AuthAbortRetry, AuthFlowTerminalContext, AuthMode, AuthSafeData, AuthSafeJson, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthScheduleRandomization, HttpAttemptContext, HttpHeadersFactory, HttpRedirectFailureReason, HttpRedirectPolicy, HttpRedirectPolicyMode, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnectInput, NativeNetworkConnection, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationErrorCode, OperationExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationTransport, ProviderAccessVisibility, ProviderContext, ProviderContextFor, ProviderDefinition, ProviderDeploymentOverrides, ProviderErrorStatus, ProviderFileRef, ProviderFilesContext, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderProxyPolicy, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderResolvedFile, ProviderRuntimeState, ProviderRuntimeTarget, ProviderStateDurationString, ProviderStateNamespace, ProviderStealthConfig, ProviderSupportLevel, ProxiedOAuthConfig, RedirectRunReason, SchemaLike, SmsOtpMatcherDefinition, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateNamespaceScope, StateValue, StateWriteOptions, StealthChallengeClassification, } from "./types.js";
|
|
21
21
|
export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
|
package/dist/provider.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export { AuthAbortError,
|
|
1
|
+
export { AuthAbortError, createAuthFlowHelpers, credentialsAuthChallenge, defineCredentialsAuth, } from "./auth.js";
|
|
2
2
|
export { createFormCeremony } from "./ceremonies/index.js";
|
|
3
|
-
export { centered,
|
|
4
|
-
export {
|
|
3
|
+
export { centered, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, delayed, every, } from "./define.js";
|
|
4
|
+
export { createInProcessProviderEngine, createProviderEnvironment, ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RUNTIME_ENV_NAMES, ENGINE_OWNED_TELEMETRY_ENV_NAMES, isEngineOwnedEnvName, isEngineOwnedProxyCredentialName, isEngineOwnedResolverCredentialName, isEngineOwnedRuntimeEnvName, isEngineOwnedTelemetryEnvName, PROVIDER_CAPABILITY_KEYS, PROVIDER_ENGINE_MODE_ENV, PROVIDER_ENGINE_PROTOCOL_VERSION, readEngineProxyCredentials, } from "./engine.js";
|
|
5
5
|
export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, isTransportError, ProviderEgressDeniedError, ProviderEngineAuthenticationError, ProviderEngineProtocolVersionError, ProviderEngineUnavailableError, ProviderError, SDKError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
|
|
6
|
-
export { createProviderEnvironment, createInProcessProviderEngine, ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RUNTIME_ENV_NAMES, ENGINE_OWNED_TELEMETRY_ENV_NAMES, isEngineOwnedEnvName, isEngineOwnedProxyCredentialName, isEngineOwnedResolverCredentialName, isEngineOwnedRuntimeEnvName, isEngineOwnedTelemetryEnvName, PROVIDER_CAPABILITY_KEYS, PROVIDER_ENGINE_MODE_ENV, PROVIDER_ENGINE_PROTOCOL_VERSION, readEngineProxyCredentials, } from "./engine.js";
|
|
7
|
-
export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
|
|
8
6
|
export * from "./handle.js";
|
|
9
7
|
export { APIFUSE_HANDLE_META_KEY, HANDLE_KIND_NAME_PATTERN, handleFieldDescription, handleFieldNameFor, handleHasDirectionalFieldNames, isHandleFieldMeta, } from "./handle-meta.js";
|
|
8
|
+
export { AssertionExpressionSchema, AssertionPredicateSchema, AssertStepSchema, BoundedJsonPathSchema, CandidateBlockSchema, CandidatePolicySchema, CredentialRefDeclarationSchema, defineHealthScenario, ExtractStepSchema, FindFirstSchema, GUARD_REASON_CODES, GuardStepSchema, HealthScenarioSchema, HealthStepSchema, JournalPolicySchema, JsonTemplateSchema, ManualTriggerPolicySchema, OperandSchema, OperationStepSchema, QuantifierSchema, ReferenceSchema, RelativeDateNodeSchema, RetryPolicySchema, SafeRegexSchema, ScopedAssertionExpressionSchema, ScopedAssertionPredicateSchema, ScopedItemReferenceSchema, ScopedOperandSchema, StepReferenceSchema, ValueTypeSchema, } from "./health-scenario.js";
|
|
9
|
+
export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
|
|
10
10
|
export { createHandleContext, createTestHandleContext, normalizeHandle, } from "./runtime/handle.js";
|
|
11
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
11
12
|
export { createMemoryProviderRuntimeState, createUnsupportedProviderRuntimeState, } from "./runtime/state.js";
|
|
12
13
|
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, sensitive, untrustedContent, z, } from "./schema.js";
|
|
13
|
-
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
14
14
|
export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
|
package/dist/server/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type { ProviderErrorObservability } from "../errors.js";
|
|
|
17
17
|
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, type SelfTestAppOptions, type SelfTestAuthFlowInvoke, type SelfTestAuthFlowRoute, type SelfTestCaseResult, type SelfTestCaseStatus, type SelfTestOperationInvoke, type SelfTestRequest, SelfTestRequestSchema, type SelfTestResponse, } from "./self-test.js";
|
|
18
18
|
export { type InputDateTokenCalendar, resolveHealthCheckInputDateTokens, } from "./self-test-input-tokens.js";
|
|
19
19
|
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
20
|
+
export { type CollectRuntimeDiagnosticsInput, collectRuntimeDiagnostics, DEFAULT_PROCFS_SELF_ROOT, DEFAULT_RUNTIME_DIAGNOSTICS_WINDOW_MS, MAX_RUNTIME_DIAGNOSTICS_WINDOW_MS, MIN_RUNTIME_DIAGNOSTICS_WINDOW_MS, normalizeRuntimeDiagnosticsWindowMs, PROCFS_CLOCK_TICKS_PER_SECOND, resolveRuntimeDiagnosticsWindowMs, RUNTIME_DIAGNOSTICS_ROUTE, RUNTIME_DIAGNOSTICS_SCHEMA_VERSION, RUNTIME_DIAGNOSTICS_WINDOW_QUERY, type RuntimeDiagnosticsActiveResources, type RuntimeDiagnosticsClock, type RuntimeDiagnosticsCpu, type RuntimeDiagnosticsCpuTotals, type RuntimeDiagnosticsEventLoop, type RuntimeDiagnosticsEventLoopUtilization, type RuntimeDiagnosticsFdKind, type RuntimeDiagnosticsMemory, type RuntimeDiagnosticsProcfs, type RuntimeDiagnosticsReport, type RuntimeDiagnosticsThread, type RuntimeDiagnosticsThreadContextSwitches, type RuntimeDiagnosticsThreadCpuTicks, type RuntimeDiagnosticsThreadWindow, } from "./runtime-diagnostics.js";
|
|
20
21
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, type SelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
21
22
|
export type { AuthFlowRequest, AuthFlowResponse, AuthFlowSuccessResponse, ConnectionMode, OperationConnection, OperationErrorResponse, OperationRequest, OperationResponse, OperationSuccessResponse, } from "./types.js";
|
|
22
23
|
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
package/dist/server/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, serv
|
|
|
8
8
|
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test.js";
|
|
9
9
|
export { resolveHealthCheckInputDateTokens, } from "./self-test-input-tokens.js";
|
|
10
10
|
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
11
|
+
export { collectRuntimeDiagnostics, DEFAULT_PROCFS_SELF_ROOT, DEFAULT_RUNTIME_DIAGNOSTICS_WINDOW_MS, MAX_RUNTIME_DIAGNOSTICS_WINDOW_MS, MIN_RUNTIME_DIAGNOSTICS_WINDOW_MS, normalizeRuntimeDiagnosticsWindowMs, PROCFS_CLOCK_TICKS_PER_SECOND, resolveRuntimeDiagnosticsWindowMs, RUNTIME_DIAGNOSTICS_ROUTE, RUNTIME_DIAGNOSTICS_SCHEMA_VERSION, RUNTIME_DIAGNOSTICS_WINDOW_QUERY, } from "./runtime-diagnostics.js";
|
|
11
12
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
12
13
|
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
|
13
14
|
export { HttpTelemetryCollector, } from "../runtime/http-telemetry.js";
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal runtime diagnostics route on the provider's primary listener, next
|
|
3
|
+
* to `/health` and `/readyz`. It answers one JSON report that tells an idle
|
|
4
|
+
* process that still burns CPU apart from a busy one without `exec`: process
|
|
5
|
+
* CPU sampled over a short window, memory, the Node event-loop and
|
|
6
|
+
* active-resource APIs, and on Linux the per-thread CPU and file-descriptor
|
|
7
|
+
* picture from `/proc/self`.
|
|
8
|
+
*
|
|
9
|
+
* Read-only and secret-free. It shares the boundary of `/health` and `/readyz`:
|
|
10
|
+
* the generated provider NetworkPolicy admits only the gateway on this port and
|
|
11
|
+
* the gateway dials canonical operation paths only, so a tenant cannot reach
|
|
12
|
+
* it; operators use `kubectl port-forward`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RUNTIME_DIAGNOSTICS_ROUTE = "/__apifuse/diagnostics/runtime";
|
|
15
|
+
export declare const RUNTIME_DIAGNOSTICS_SCHEMA_VERSION: 1;
|
|
16
|
+
/** Query parameter naming the sampling window; clamped, never rejected. */
|
|
17
|
+
export declare const RUNTIME_DIAGNOSTICS_WINDOW_QUERY = "windowMs";
|
|
18
|
+
export declare const DEFAULT_RUNTIME_DIAGNOSTICS_WINDOW_MS = 250;
|
|
19
|
+
export declare const MIN_RUNTIME_DIAGNOSTICS_WINDOW_MS = 50;
|
|
20
|
+
export declare const MAX_RUNTIME_DIAGNOSTICS_WINDOW_MS = 5000;
|
|
21
|
+
/**
|
|
22
|
+
* Linux USER_HZ. The unit of `utime`/`stime` in `/proc` stat files is an ABI
|
|
23
|
+
* constant (100 Hz) independent of the kernel's CONFIG_HZ.
|
|
24
|
+
*/
|
|
25
|
+
export declare const PROCFS_CLOCK_TICKS_PER_SECOND = 100;
|
|
26
|
+
export declare const DEFAULT_PROCFS_SELF_ROOT = "/proc/self";
|
|
27
|
+
export interface RuntimeDiagnosticsCpuTotals {
|
|
28
|
+
readonly userMicros: number;
|
|
29
|
+
readonly systemMicros: number;
|
|
30
|
+
}
|
|
31
|
+
export interface RuntimeDiagnosticsCpu {
|
|
32
|
+
/** `process.cpuUsage()` since boot and its average in cores over `uptimeSeconds`. */
|
|
33
|
+
readonly lifetime: RuntimeDiagnosticsCpuTotals & {
|
|
34
|
+
readonly averageCores: number;
|
|
35
|
+
};
|
|
36
|
+
/** `process.cpuUsage()` delta over the sampling window, as cores (1 = one CPU fully busy). */
|
|
37
|
+
readonly window: RuntimeDiagnosticsCpuTotals & {
|
|
38
|
+
readonly userCores: number;
|
|
39
|
+
readonly systemCores: number;
|
|
40
|
+
readonly totalCores: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export interface RuntimeDiagnosticsEventLoopUtilization {
|
|
44
|
+
readonly idle: number;
|
|
45
|
+
readonly active: number;
|
|
46
|
+
readonly utilization: number;
|
|
47
|
+
}
|
|
48
|
+
export interface RuntimeDiagnosticsEventLoop {
|
|
49
|
+
/**
|
|
50
|
+
* false when the runtime returned only zeros for the whole process lifetime.
|
|
51
|
+
* Bun 1.2 and 1.3 stub `performance.eventLoopUtilization`; read
|
|
52
|
+
* `cpu.window` and `procfs.threads` instead.
|
|
53
|
+
*/
|
|
54
|
+
readonly reported: boolean;
|
|
55
|
+
readonly lifetime: RuntimeDiagnosticsEventLoopUtilization;
|
|
56
|
+
readonly window: RuntimeDiagnosticsEventLoopUtilization;
|
|
57
|
+
}
|
|
58
|
+
export interface RuntimeDiagnosticsActiveResources {
|
|
59
|
+
/**
|
|
60
|
+
* false when the runtime listed nothing, although at least the socket that
|
|
61
|
+
* answers this request is alive. Bun 1.2 and 1.3 stub
|
|
62
|
+
* `process.getActiveResourcesInfo`; read `procfs.fileDescriptors` instead.
|
|
63
|
+
*/
|
|
64
|
+
readonly reported: boolean;
|
|
65
|
+
readonly total: number;
|
|
66
|
+
readonly byType: Readonly<Record<string, number>>;
|
|
67
|
+
}
|
|
68
|
+
export interface RuntimeDiagnosticsMemory {
|
|
69
|
+
readonly rss: number;
|
|
70
|
+
readonly heapTotal: number;
|
|
71
|
+
readonly heapUsed: number;
|
|
72
|
+
readonly external: number;
|
|
73
|
+
readonly arrayBuffers: number;
|
|
74
|
+
}
|
|
75
|
+
export interface RuntimeDiagnosticsThreadCpuTicks {
|
|
76
|
+
readonly userTicks: number;
|
|
77
|
+
readonly systemTicks: number;
|
|
78
|
+
}
|
|
79
|
+
export interface RuntimeDiagnosticsThreadContextSwitches {
|
|
80
|
+
readonly voluntary: number;
|
|
81
|
+
readonly nonvoluntary: number;
|
|
82
|
+
}
|
|
83
|
+
export interface RuntimeDiagnosticsThreadWindow extends RuntimeDiagnosticsThreadCpuTicks {
|
|
84
|
+
/** CPU consumed by this thread over the window, in cores. */
|
|
85
|
+
readonly cores: number;
|
|
86
|
+
readonly contextSwitches: RuntimeDiagnosticsThreadContextSwitches;
|
|
87
|
+
}
|
|
88
|
+
export interface RuntimeDiagnosticsThread {
|
|
89
|
+
readonly tid: number;
|
|
90
|
+
/** Kernel thread name (`comm`, 15 bytes), e.g. `bun`, `HTTP Client`, `HeapHelper`. */
|
|
91
|
+
readonly name: string;
|
|
92
|
+
/** Scheduler state letter at the second sample (`R` running, `S` sleeping, ...). */
|
|
93
|
+
readonly state: string;
|
|
94
|
+
/** Kernel wait channel at the second sample (`0` while running); null when unreadable. */
|
|
95
|
+
readonly waitChannel: string | null;
|
|
96
|
+
readonly lifetime: RuntimeDiagnosticsThreadCpuTicks;
|
|
97
|
+
/** null for a thread that appeared after the first sample. */
|
|
98
|
+
readonly window: RuntimeDiagnosticsThreadWindow | null;
|
|
99
|
+
}
|
|
100
|
+
export type RuntimeDiagnosticsFdKind = "socket" | "eventpoll" | "timerfd" | "eventfd" | "pipe" | "file" | "other";
|
|
101
|
+
export interface RuntimeDiagnosticsProcfs {
|
|
102
|
+
readonly clockTicksPerSecond: number;
|
|
103
|
+
/**
|
|
104
|
+
* Elapsed time between the two /proc/self scans. Slightly longer than
|
|
105
|
+
* `window.observedMs` because it encloses the scans themselves; thread
|
|
106
|
+
* `window.cores` is computed over this interval.
|
|
107
|
+
*/
|
|
108
|
+
readonly observedMs: number;
|
|
109
|
+
readonly threads: {
|
|
110
|
+
readonly total: number;
|
|
111
|
+
readonly byName: Readonly<Record<string, number>>;
|
|
112
|
+
/** Sorted by window cores descending, so the hottest thread is first. */
|
|
113
|
+
readonly items: readonly RuntimeDiagnosticsThread[];
|
|
114
|
+
};
|
|
115
|
+
readonly fileDescriptors: {
|
|
116
|
+
readonly total: number;
|
|
117
|
+
readonly byKind: Readonly<Record<RuntimeDiagnosticsFdKind, number>>;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export interface RuntimeDiagnosticsReport {
|
|
121
|
+
readonly schemaVersion: typeof RUNTIME_DIAGNOSTICS_SCHEMA_VERSION;
|
|
122
|
+
readonly provider: {
|
|
123
|
+
readonly id: string;
|
|
124
|
+
readonly version: string;
|
|
125
|
+
};
|
|
126
|
+
readonly sdkVersion: string;
|
|
127
|
+
readonly runtime: {
|
|
128
|
+
readonly bunVersion: string | null;
|
|
129
|
+
readonly nodeCompatVersion: string;
|
|
130
|
+
readonly platform: string;
|
|
131
|
+
readonly arch: string;
|
|
132
|
+
readonly pid: number;
|
|
133
|
+
};
|
|
134
|
+
readonly sampledAt: string;
|
|
135
|
+
readonly uptimeSeconds: number;
|
|
136
|
+
readonly window: {
|
|
137
|
+
readonly requestedMs: number;
|
|
138
|
+
readonly observedMs: number;
|
|
139
|
+
};
|
|
140
|
+
readonly cpu: RuntimeDiagnosticsCpu;
|
|
141
|
+
readonly memory: RuntimeDiagnosticsMemory;
|
|
142
|
+
readonly eventLoop: RuntimeDiagnosticsEventLoop;
|
|
143
|
+
readonly activeResources: RuntimeDiagnosticsActiveResources;
|
|
144
|
+
/** null off Linux or when `/proc/self` is unreadable. */
|
|
145
|
+
readonly procfs: RuntimeDiagnosticsProcfs | null;
|
|
146
|
+
}
|
|
147
|
+
export interface RuntimeDiagnosticsClock {
|
|
148
|
+
now(): number;
|
|
149
|
+
sleep(ms: number): Promise<void>;
|
|
150
|
+
}
|
|
151
|
+
export interface CollectRuntimeDiagnosticsInput {
|
|
152
|
+
readonly provider: {
|
|
153
|
+
readonly id: string;
|
|
154
|
+
readonly version: string;
|
|
155
|
+
};
|
|
156
|
+
/** Sampling window; clamped to [MIN, MAX]. */
|
|
157
|
+
readonly windowMs?: number;
|
|
158
|
+
/** `/proc/self` substitute for tests. */
|
|
159
|
+
readonly procfsRoot?: string;
|
|
160
|
+
readonly clock?: RuntimeDiagnosticsClock;
|
|
161
|
+
}
|
|
162
|
+
export declare function normalizeRuntimeDiagnosticsWindowMs(value: number | undefined): number;
|
|
163
|
+
/** Parses the `windowMs` query value; anything unparsable falls back to the default. */
|
|
164
|
+
export declare function resolveRuntimeDiagnosticsWindowMs(raw: string | undefined | null): number;
|
|
165
|
+
export declare function collectRuntimeDiagnostics(input: CollectRuntimeDiagnosticsInput): Promise<RuntimeDiagnosticsReport>;
|