@ultimat3/core 22.0.0 → 22.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/core",
3
- "version": "22.0.0",
3
+ "version": "22.1.0",
4
4
  "description": "Ultimate's foundation: errors, context, env, config, clock, ids, logging, telemetry, lifecycle",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,6 +40,6 @@
40
40
  "test": "bun test"
41
41
  },
42
42
  "dependencies": {
43
- "@ultimat3/schema": "22.0.0"
43
+ "@ultimat3/schema": "22.1.0"
44
44
  }
45
45
  }
package/src/index.ts CHANGED
@@ -590,6 +590,11 @@ export { DEFAULT_ROLE, isRole, ROLE_INFO, ROLES, resolveRole } from './roles';
590
590
  export type { HydrateStrategy, OfflineStrategy, RenderMode } from './route-vocabulary';
591
591
  export { HYDRATE_STRATEGIES, OFFLINE_STRATEGIES, RENDER_MODES } from './route-vocabulary';
592
592
  export { safeUrl, URL_ATTRIBUTES } from './safe-url';
593
+ export {
594
+ type OriginEvidence,
595
+ type OriginVerdict,
596
+ proveSameOrigin,
597
+ } from './same-origin';
593
598
  export {
594
599
  defineService,
595
600
  installedServices,
package/src/metrics.ts CHANGED
@@ -391,11 +391,10 @@ export function counter(name: string, options?: InstrumentOptions): Counter {
391
391
  export function gauge(name: string, options?: GaugeOptions): Gauge {
392
392
  const instrument = declare(name, 'gauge', options ?? {});
393
393
  return {
394
- // The screen runs BEFORE the series is resolved, the order `counter.add` already had: a
395
- // refused value must cost nothing, and `seriesFor` is not a read — it MINTS a series, one of
396
- // a bounded number, keeps it for the life of the process and can trip the cardinality
397
- // ceiling. `a.b += finite(…)` evaluates the reference first, so the two cannot be folded
398
- // back into one expression.
394
+ // The screen runs BEFORE the series is resolved, as in `counter.add`: a refused value must
395
+ // cost nothing, and `seriesFor` MINTS a series — bounded in number, kept for the process's
396
+ // life, able to trip the cardinality ceiling. `a.b += finite(…)` evaluates the reference
397
+ // first, so the two cannot be folded into one expression.
399
398
  record(value, attributes = {}): void {
400
399
  if (!enabled) return;
401
400
  const observed = finite(name, value);
@@ -443,6 +442,10 @@ function pointsOf(instrument: Instrument): readonly MetricPoint[] {
443
442
  return [];
444
443
  }
445
444
  }
445
+ // Declared counter, no sample: 0, not absent (`rate()` needs a series) — until one exists.
446
+ const unsampled =
447
+ enabled && instrument.descriptor.kind === 'counter' && instrument.series.size === 0;
448
+ if (unsampled) return [{ attributes: {}, value: 0 }];
446
449
  return [...instrument.series.values()].map((series) =>
447
450
  instrument.descriptor.kind === 'histogram'
448
451
  ? {
@@ -0,0 +1,51 @@
1
+ // Single responsibility: the one rule for "did this request carrying an AMBIENT credential come
2
+ // from this app?" — `@ultimat3/http`'s CSRF check asks it of an unsafe write, and
3
+ // `@ultimat3/realtime`'s sync node of a websocket upgrade. One rule, so a sibling origin cannot be
4
+ // let in by one surface and refused by the other.
5
+
6
+ /** The complete `Sec-Fetch-Site` vocabulary. Anything else was written by a non-browser. */
7
+ const KNOWN_SITES = new Set(['same-origin', 'same-site', 'cross-site', 'none']);
8
+
9
+ export interface OriginEvidence {
10
+ /** The origins this app is reached on. More than one when the scheme is not knowable here. */
11
+ readonly selfOrigins: readonly string[];
12
+ readonly origin: string | null;
13
+ readonly secFetchSite: string | null;
14
+ /** An EXACT allowance for a sibling origin — never a wildcard, never a suffix match. */
15
+ readonly listed: (origin: string) => boolean;
16
+ /** Where the operator adds an origin, named in the refusal: `http.cors.origins`, `SYNC_ORIGINS`. */
17
+ readonly listName: string;
18
+ }
19
+
20
+ export type OriginVerdict =
21
+ | { readonly ok: true }
22
+ /** Why it was refused, in terms the caller can act on. Never echoes a header verbatim. */
23
+ | { readonly ok: false; readonly reason: string };
24
+
25
+ /**
26
+ * `sec-fetch-site` first because it is the browser's own answer and cannot be set by script;
27
+ * `Origin` second, so an app that lists a sibling origin keeps working. `same-site` is NOT proof:
28
+ * a sibling subdomain is same-site, and a `SameSite=Lax` cookie rides its requests. A request with
29
+ * neither header is refused — "we could not tell" is the case this exists for.
30
+ */
31
+ export function proveSameOrigin(evidence: OriginEvidence): OriginVerdict {
32
+ const site = evidence.secFetchSite;
33
+ if (site === 'same-origin' || site === 'none') return { ok: true };
34
+ const origin = evidence.origin;
35
+ if (origin !== null && evidence.selfOrigins.includes(origin)) return { ok: true };
36
+ if (origin !== null && evidence.listed(origin)) return { ok: true };
37
+ // Only the four values a browser can send are quoted back. Anything else is a client that
38
+ // wrote the header itself, and echoing what it wrote is how a rejected value reaches the log
39
+ // store and the response body.
40
+ if (site !== null) {
41
+ const known = KNOWN_SITES.has(site) ? site : 'a value no browser sends';
42
+ return { ok: false, reason: `the request reported sec-fetch-site: ${known}` };
43
+ }
44
+ return {
45
+ ok: false,
46
+ reason:
47
+ origin === null
48
+ ? 'the request carried neither sec-fetch-site nor origin, so it cannot be shown to be same-origin'
49
+ : `the origin it declares is not this app and is not listed in ${evidence.listName}`,
50
+ };
51
+ }