@xema/omni-protocol 0.1.47 → 0.1.49

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/dist/testing.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { browserSessionKey, effectiveLevels, sameCapabilities, } from "./index.js";
2
- import { assertNoViolations, validateAuthenticationState, validateEventEnvelope, validateHostGuarantees, validateHostReport, validateManifest, validateResult, validateSnapshot, validateTimeZone, validatePhone, isTimeZone, } from "./validation.js";
2
+ import { assertNoViolations, validateAuthenticationState, validateEventEnvelope, validateHostGuarantees, validateHostReport, validateManifest, validateResult, validateSnapshot, validateTimeZone, validatePhone, isTimeZone, sameTimeZone, } from "./validation.js";
3
3
  export { ProtocolConformanceError, assertNoViolations } from "./validation.js";
4
4
  /**
5
5
  * A part of the contract a run may never reach: state nothing obliges an adapter to publish, so
@@ -342,7 +342,9 @@ export async function exerciseAdapter(adapter, context, options = {}) {
342
342
  // The provider republishes the agent's day: once connected, the identity carries the zone the
343
343
  // host sent. That proves the round trip, not the store -- an echo passes it -- and the name
344
344
  // says only what it tests; storage is proved by a colleague's zone arriving from describeUsers().
345
- if (isTimeZone(context.timeZone) && current().identity.timeZone !== context.timeZone) {
345
+ // A zone is judged by what it denotes: Asia/Kolkata and Asia/Calcutta are one zone, and a
346
+ // provider that keeps the canonical name has kept the zone.
347
+ if (isTimeZone(context.timeZone) && !sameTimeZone(current().identity.timeZone, context.timeZone)) {
346
348
  violations.push({
347
349
  rule: "authentication.identity.timeZone.republished",
348
350
  path: "authentication.identity.timeZone",
@@ -74,6 +74,8 @@ export type ResultMethod = "execute" | "dial" | "setCapacity" | "requestBreak" |
74
74
  export declare function validateResult(result: unknown, method: ResultMethod, path?: string, dialId?: string): ProtocolViolation[];
75
75
  /** An IANA zone name the runtime knows: `Asia/Kolkata` is one, an offset or a made-up name is not. */
76
76
  export declare function isTimeZone(value: unknown): value is string;
77
+ /** Whether two zone names denote one zone: `Asia/Kolkata` and `Asia/Calcutta` do, and a name is judged by what it denotes. */
78
+ export declare function sameTimeZone(a: unknown, b: unknown): boolean;
77
79
  /** The zone a host sends at connect: required, and an IANA name. */
78
80
  export declare function validateTimeZone(value: unknown, path?: string): ProtocolViolation[];
79
81
  /** What a login is validated against beyond its own shape. */
@@ -1788,6 +1788,13 @@ export function isTimeZone(value) {
1788
1788
  return false;
1789
1789
  }
1790
1790
  }
1791
+ /** Whether two zone names denote one zone: `Asia/Kolkata` and `Asia/Calcutta` do, and a name is judged by what it denotes. */
1792
+ export function sameTimeZone(a, b) {
1793
+ if (!isTimeZone(a) || !isTimeZone(b))
1794
+ return false;
1795
+ const canonical = (zone) => new Intl.DateTimeFormat("en", { timeZone: zone }).resolvedOptions().timeZone;
1796
+ return a === b || canonical(a) === canonical(b);
1797
+ }
1791
1798
  /** The zone a host sends at connect: required, and an IANA name. */
1792
1799
  export function validateTimeZone(value, path = "context.timeZone") {
1793
1800
  const into = new Collector();
package/guide.md CHANGED
@@ -1939,7 +1939,9 @@ field to fill in later: an identity without one is refused (`authentication.iden
1939
1939
  so is a zone that is not an IANA name, wherever it appears. Nothing is ever assumed in its place --
1940
1940
  not the viewer's browser, which gives a different answer per reader for the same record, and not the
1941
1941
  provider's clock. The harness holds a provider to the round trip: the identity carries the zone the
1942
- host stated (`authentication.identity.timeZone.republished`). **The round trip is not the store.**
1942
+ host stated (`authentication.identity.timeZone.republished`), judged by what the name denotes:
1943
+ `Asia/Kolkata` and `Asia/Calcutta` are one zone, and a provider that keeps the canonical name has
1944
+ kept the zone. **The round trip is not the store.**
1943
1945
  An adapter that echoes the stated zone back onto the identity passes that check with nothing kept,
1944
1946
  and a lead reading a colleague's day would still get the wrong one. What proves the store is a zone
1945
1947
  the run never sent: a colleague's `User` from `describeUsers()` carrying theirs. A provider's own
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xema/omni-protocol",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
4
4
  "description": "The Omni protocol: the contract every provider adapter implements",
5
5
  "type": "module",
6
6
  "license": "MIT",