@konneal/engine 0.2.22 → 0.2.24
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/ask-OO6UUIFF.js +12 -0
- package/dist/{chunk-RESCBSX6.js → chunk-434NRPSS.js} +1 -1
- package/dist/{chunk-BV7IKH3N.js → chunk-FYGJDJPN.js} +2 -2
- package/dist/chunk-HXWDVAVN.js +24441 -0
- package/dist/{chunk-YTWPZE5O.js → chunk-HYI32HMI.js} +0 -32
- package/dist/{chunk-M24JWPVN.js → chunk-IM5KMIL6.js} +9 -9
- package/dist/{chunk-COKARI7O.js → chunk-IOZAZA7Y.js} +2 -2
- package/dist/{chunk-IROEVHEV.js → chunk-PZLYPUYJ.js} +4 -4
- package/dist/{chunk-FNJ457SE.js → chunk-RZ3UZVRR.js} +1 -1
- package/dist/livedata.d.ts +3 -4
- package/dist/oidc-refresh.d.ts +19 -0
- package/dist/oidc.d.ts +1 -0
- package/dist/refresh-core.d.ts +28 -0
- package/dist/search-OJ776DMH.js +12 -0
- package/dist/worker_mcp/src/index.js +3 -3
- package/dist/worker_public/src/config.js +2 -2
- package/dist/worker_public/src/index.js +9 -9
- package/dist/worker_public/src/profile.js +1 -1
- package/dist/worker_public/src/refusal.js +2 -2
- package/dist/worker_public/src/requestScope.js +3 -3
- package/package.json +2 -3
- package/workers/worker_public/src/aggregation.ts +1 -1
- package/workers/worker_public/src/auth.ts +45 -10
- package/workers/worker_public/src/codecs.ts +33 -32
- package/workers/worker_public/src/conditions.ts +2 -2
- package/workers/worker_public/src/livedata.ts +35 -0
- package/workers/worker_public/src/oidc-refresh.ts +76 -0
- package/workers/worker_public/src/oidc.ts +1 -0
- package/workers/worker_public/src/refresh-core.ts +67 -0
- package/dist/ask-HLELROYT.js +0 -12
- package/dist/chunk-4XBU4J6B.js +0 -4149
- package/dist/search-GVDELP3N.js +0 -12
|
@@ -1,33 +1,3 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
-
try {
|
|
9
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
-
} catch (e) {
|
|
11
|
-
throw mod = 0, e;
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
var __copyProps = (to, from, except, desc) => {
|
|
15
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
-
for (let key of __getOwnPropNames(from))
|
|
17
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
-
}
|
|
20
|
-
return to;
|
|
21
|
-
};
|
|
22
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
-
mod
|
|
29
|
-
));
|
|
30
|
-
|
|
31
1
|
// workers/worker_public/src/profile.gen.ts
|
|
32
2
|
var PROFILE = {
|
|
33
3
|
"publisher": {
|
|
@@ -176,8 +146,6 @@ function P() {
|
|
|
176
146
|
}
|
|
177
147
|
|
|
178
148
|
export {
|
|
179
|
-
__commonJS,
|
|
180
|
-
__toESM,
|
|
181
149
|
setProfile,
|
|
182
150
|
P
|
|
183
151
|
};
|
|
@@ -27,23 +27,23 @@ import {
|
|
|
27
27
|
syntheticUnderstanding,
|
|
28
28
|
telemetry,
|
|
29
29
|
understandQuery
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-HXWDVAVN.js";
|
|
31
31
|
import {
|
|
32
32
|
corsHeaders,
|
|
33
33
|
err,
|
|
34
34
|
json,
|
|
35
35
|
readJson,
|
|
36
36
|
validateQuery
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-FYGJDJPN.js";
|
|
38
38
|
import {
|
|
39
39
|
canonicalRefusal,
|
|
40
40
|
refusalAnswer
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-RZ3UZVRR.js";
|
|
42
42
|
import {
|
|
43
43
|
entitlementScope,
|
|
44
44
|
requestSalt,
|
|
45
45
|
resolveRequestScope
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-IOZAZA7Y.js";
|
|
47
47
|
import {
|
|
48
48
|
LIMITS,
|
|
49
49
|
MODELS,
|
|
@@ -53,10 +53,10 @@ import {
|
|
|
53
53
|
requestEffort,
|
|
54
54
|
roleModel,
|
|
55
55
|
sha256Hex
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-434NRPSS.js";
|
|
57
57
|
import {
|
|
58
58
|
P
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-HYI32HMI.js";
|
|
60
60
|
|
|
61
61
|
// workers/worker_public/src/internal_gateway.ts
|
|
62
62
|
async function retrieveInternal(service, auth, query) {
|
|
@@ -827,7 +827,7 @@ function evaluateConditionSets(nodes, query) {
|
|
|
827
827
|
verdict: "pass",
|
|
828
828
|
matched: matched.map((m) => m.node_id),
|
|
829
829
|
checks: matched[0].checks,
|
|
830
|
-
note: `VERDICT: PASS \u2014 the stated combination (${kinds.join(", ")}) matches severity set(
|
|
830
|
+
note: `VERDICT: PASS \u2014 the stated combination (${kinds.join(", ")}) matches a severity set (${matched[0].checks.map((c) => c.band).join("; ")}). Present this verdict and cite the set's clause. The machine set identifier rides the verdict block as data \u2014 never write it in your prose.`
|
|
831
831
|
};
|
|
832
832
|
}
|
|
833
833
|
const nearest = scored[0];
|
|
@@ -836,7 +836,7 @@ function evaluateConditionSets(nodes, query) {
|
|
|
836
836
|
matched: [],
|
|
837
837
|
nearest: { node_id: nearest.node_id, distance: Number(nearest.distance.toFixed(2)), bands: nearest.checks.map((c) => c.band) },
|
|
838
838
|
checks: nearest.checks,
|
|
839
|
-
note: `VERDICT: FAIL \u2014 no severity set admits the stated combination. The nearest set
|
|
839
|
+
note: `VERDICT: FAIL \u2014 no severity set admits the stated combination. The nearest set (bands: ${nearest.checks.map((c) => c.band).join("; ")}) is the closest match. Say the combination is outside the menu and describe the nearest set's bands; never soften it. The machine set identifier rides the verdict block as data \u2014 never write it in your prose.`
|
|
840
840
|
};
|
|
841
841
|
}
|
|
842
842
|
|
|
@@ -985,7 +985,7 @@ function evaluateAggregation(nodes, query) {
|
|
|
985
985
|
const rawTitle = String(content.name ?? content.definition ?? node.node_id.replace("/table/", ""));
|
|
986
986
|
const cut = rawTitle.indexOf(" (");
|
|
987
987
|
const tableTitle = cut > 0 ? rawTitle.slice(0, cut) : rawTitle.slice(0, 120);
|
|
988
|
-
const cite = (what) => `COMPUTED (${operation}) \u2014 ${what}, read from the typed table "${tableTitle}"
|
|
988
|
+
const cite = (what) => `COMPUTED (${operation}) \u2014 ${what}, read from the typed table "${tableTitle}". Present this result and cite the table's clause; the value is machine-computed from the table payload, do not recompute or round it differently. The machine table identifier rides the verdict block as data \u2014 never write it in your prose.`;
|
|
989
989
|
if (operation === "count") {
|
|
990
990
|
const cc2 = classColumn(cols);
|
|
991
991
|
if (cc2 && /\bclasses?\b/.test(qLower) && tokens(cc2.name).some((t) => t.length >= 3 && qLower.includes(t))) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DATASETS,
|
|
3
3
|
datasetAllowed
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-434NRPSS.js";
|
|
5
5
|
import {
|
|
6
6
|
P
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HYI32HMI.js";
|
|
8
8
|
|
|
9
9
|
// workers/worker_public/src/requestScope.ts
|
|
10
10
|
function licenseDeclared() {
|
|
@@ -7,24 +7,24 @@ import {
|
|
|
7
7
|
sessionFrom,
|
|
8
8
|
telemetry,
|
|
9
9
|
understandQuery
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-HXWDVAVN.js";
|
|
11
11
|
import {
|
|
12
12
|
corsHeaders,
|
|
13
13
|
err,
|
|
14
14
|
json,
|
|
15
15
|
readJson,
|
|
16
16
|
validateQuery
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-FYGJDJPN.js";
|
|
18
18
|
import {
|
|
19
19
|
entitlementScope,
|
|
20
20
|
standardKeysFrom
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-IOZAZA7Y.js";
|
|
22
22
|
import {
|
|
23
23
|
LIMITS,
|
|
24
24
|
MODELS,
|
|
25
25
|
num,
|
|
26
26
|
sha256Hex
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-434NRPSS.js";
|
|
28
28
|
|
|
29
29
|
// workers/worker_public/src/search.ts
|
|
30
30
|
async function handleSearch(env, ctx, req, tier, key) {
|
package/dist/livedata.d.ts
CHANGED
|
@@ -12,10 +12,9 @@ export interface LiveDataConfig {
|
|
|
12
12
|
clientSecret?: string;
|
|
13
13
|
}
|
|
14
14
|
export declare function liveDataConfig(env: any): LiveDataConfig | null;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* the window. */
|
|
15
|
+
export declare function retainRefreshToken(env: any, sessionRaw: string, refreshToken: string): Promise<void>;
|
|
16
|
+
export declare function readRefreshToken(env: any, sessionRaw: string): Promise<string | null>;
|
|
17
|
+
export declare function dropRefreshToken(env: any, sessionRaw: string): Promise<void>;
|
|
19
18
|
export declare function retainOpAccessToken(env: any, sessionRaw: string, opAccessToken: string, expiresInSec: number): Promise<void>;
|
|
20
19
|
/** Drop the retained subject + the cached exchanged token (the sign-out
|
|
21
20
|
* closes the window deliberately, never by expiry alone). */
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SessionClaims } from "./session";
|
|
2
|
+
export interface RenewedSession {
|
|
3
|
+
claims: Omit<SessionClaims, "iat" | "exp">;
|
|
4
|
+
refreshToken: string;
|
|
5
|
+
}
|
|
6
|
+
export type RenewOutcome = {
|
|
7
|
+
kind: "ok";
|
|
8
|
+
renewed: RenewedSession;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "revoked";
|
|
11
|
+
} | {
|
|
12
|
+
kind: "unavailable";
|
|
13
|
+
};
|
|
14
|
+
export declare function renewSessionClaims(env: any, cfg: {
|
|
15
|
+
issuer: string;
|
|
16
|
+
clientId: string;
|
|
17
|
+
clientSecret?: string;
|
|
18
|
+
sessionSecret: string;
|
|
19
|
+
}, session: SessionClaims, sessionRaw: string): Promise<RenewOutcome>;
|
package/dist/oidc.d.ts
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { OidcIdTokenClaims, OidcTokenResponse } from "./oidc.ts";
|
|
2
|
+
import type { SessionClaims } from "./session";
|
|
3
|
+
export interface OidcMetadata {
|
|
4
|
+
token_endpoint: string;
|
|
5
|
+
jwks_uri: string;
|
|
6
|
+
}
|
|
7
|
+
export type RefreshResult = {
|
|
8
|
+
kind: "ok";
|
|
9
|
+
token: OidcTokenResponse;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "refused";
|
|
12
|
+
} | {
|
|
13
|
+
kind: "unavailable";
|
|
14
|
+
};
|
|
15
|
+
/** The refresh grant's backchannel: the same shape as the code
|
|
16
|
+
* exchange's POST (the OP's WAF wants the issuer's own origin), with
|
|
17
|
+
* the three outcomes the renewal policy needs — a 400 is the OP
|
|
18
|
+
* REFUSING (revocation, expiry: dead), a network throw is
|
|
19
|
+
* unavailability (keep the session, retry next load). */
|
|
20
|
+
export declare function refreshGrant(meta: OidcMetadata, cfg: {
|
|
21
|
+
clientId: string;
|
|
22
|
+
clientSecret?: string;
|
|
23
|
+
}, refreshToken: string): Promise<RefreshResult>;
|
|
24
|
+
/** The fresh session claims from the refresh grant's ID token. The sub
|
|
25
|
+
* MUST match (a different account is a provisioning error, never an
|
|
26
|
+
* update); every profile field falls back to the standing session's so
|
|
27
|
+
* a claim the OP omits never erases what the user already had. */
|
|
28
|
+
export declare function renewedSessionClaims(session: SessionClaims, claims: OidcIdTokenClaims): Omit<SessionClaims, "iat" | "exp"> | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleSearch
|
|
3
|
+
} from "./chunk-PZLYPUYJ.js";
|
|
4
|
+
import "./chunk-HXWDVAVN.js";
|
|
5
|
+
import "./chunk-FYGJDJPN.js";
|
|
6
|
+
import "./chunk-RZ3UZVRR.js";
|
|
7
|
+
import "./chunk-IOZAZA7Y.js";
|
|
8
|
+
import "./chunk-434NRPSS.js";
|
|
9
|
+
import "./chunk-HYI32HMI.js";
|
|
10
|
+
export {
|
|
11
|
+
handleSearch
|
|
12
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authenticate
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-FYGJDJPN.js";
|
|
4
|
+
import "../../chunk-434NRPSS.js";
|
|
5
5
|
import {
|
|
6
6
|
P,
|
|
7
7
|
setProfile
|
|
8
|
-
} from "../../chunk-
|
|
8
|
+
} from "../../chunk-HYI32HMI.js";
|
|
9
9
|
|
|
10
10
|
// workers/worker_mcp/src/index.ts
|
|
11
11
|
var PROTOCOL_VERSION = "2025-06-18";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleSearch
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-PZLYPUYJ.js";
|
|
4
4
|
import {
|
|
5
5
|
checkQuoteAnchors,
|
|
6
6
|
handleAsk,
|
|
7
7
|
handleMemories,
|
|
8
8
|
scoreJudge,
|
|
9
9
|
standardForDocNumber
|
|
10
|
-
} from "../../chunk-
|
|
10
|
+
} from "../../chunk-IM5KMIL6.js";
|
|
11
11
|
import {
|
|
12
12
|
buildMessages,
|
|
13
13
|
citations,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
sessionFrom,
|
|
30
30
|
telemetry,
|
|
31
31
|
understandQuery
|
|
32
|
-
} from "../../chunk-
|
|
32
|
+
} from "../../chunk-HXWDVAVN.js";
|
|
33
33
|
import {
|
|
34
34
|
authenticate,
|
|
35
35
|
corsHeaders,
|
|
@@ -38,14 +38,14 @@ import {
|
|
|
38
38
|
readJson,
|
|
39
39
|
validateQuery,
|
|
40
40
|
withCors
|
|
41
|
-
} from "../../chunk-
|
|
41
|
+
} from "../../chunk-FYGJDJPN.js";
|
|
42
42
|
import {
|
|
43
43
|
canonicalRefusal
|
|
44
|
-
} from "../../chunk-
|
|
44
|
+
} from "../../chunk-RZ3UZVRR.js";
|
|
45
45
|
import {
|
|
46
46
|
entitlementScope,
|
|
47
47
|
standardKeysFrom
|
|
48
|
-
} from "../../chunk-
|
|
48
|
+
} from "../../chunk-IOZAZA7Y.js";
|
|
49
49
|
import {
|
|
50
50
|
LIMITS,
|
|
51
51
|
MODELS,
|
|
@@ -56,11 +56,11 @@ import {
|
|
|
56
56
|
roleModel,
|
|
57
57
|
sha256Hex,
|
|
58
58
|
today
|
|
59
|
-
} from "../../chunk-
|
|
59
|
+
} from "../../chunk-434NRPSS.js";
|
|
60
60
|
import {
|
|
61
61
|
P,
|
|
62
62
|
setProfile
|
|
63
|
-
} from "../../chunk-
|
|
63
|
+
} from "../../chunk-HYI32HMI.js";
|
|
64
64
|
|
|
65
65
|
// workers/worker_public/src/conversations.ts
|
|
66
66
|
var ID_RE = /^[a-zA-Z0-9_-]{8,64}$/;
|
|
@@ -979,7 +979,7 @@ async function handleMcp(env, ctx, req, tier, key) {
|
|
|
979
979
|
// stream:false forces the JSON lane (anon defaults to SSE)
|
|
980
980
|
body: JSON.stringify({ ...args, stream: false })
|
|
981
981
|
});
|
|
982
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
982
|
+
const res = name === "ask" ? await (await import("../../ask-OO6UUIFF.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-OJ776DMH.js")).handleSearch(env, ctx, inner, tier, key);
|
|
983
983
|
return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
984
984
|
});
|
|
985
985
|
if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
requestSalt,
|
|
5
5
|
resolveRequestScope,
|
|
6
6
|
standardKeysFrom
|
|
7
|
-
} from "../../chunk-
|
|
8
|
-
import "../../chunk-
|
|
9
|
-
import "../../chunk-
|
|
7
|
+
} from "../../chunk-IOZAZA7Y.js";
|
|
8
|
+
import "../../chunk-434NRPSS.js";
|
|
9
|
+
import "../../chunk-HYI32HMI.js";
|
|
10
10
|
export {
|
|
11
11
|
entitlementScope,
|
|
12
12
|
licenseDeclared,
|
package/package.json
CHANGED
|
@@ -20,15 +20,14 @@
|
|
|
20
20
|
"@astrojs/mdx": "^4.3.14",
|
|
21
21
|
"@cloudflare/workers-types": "^5.20260911.1",
|
|
22
22
|
"@konneal/client": "^0.2.1",
|
|
23
|
-
"@
|
|
24
|
-
"@pubid/pubid": "^0.1.4",
|
|
23
|
+
"@pubid/pubid": "^0.1.5",
|
|
25
24
|
"esbuild": "^0.28.2",
|
|
26
25
|
"jsdom": "^29.1.1",
|
|
27
26
|
"openapi-typescript": "^7.13.0",
|
|
28
27
|
"playwright": "^1.62.1",
|
|
29
28
|
"yaml": "^2.9.1"
|
|
30
29
|
},
|
|
31
|
-
"version": "0.2.
|
|
30
|
+
"version": "0.2.24",
|
|
32
31
|
"description": "The Konneal engine: the publisher-agnostic build pipeline and API plane for standards intelligence (retrieval, answer contract, verdicts, evaluation).",
|
|
33
32
|
"license": "BSD-3-Clause",
|
|
34
33
|
"type": "module",
|
|
@@ -222,7 +222,7 @@ export function evaluateAggregation(
|
|
|
222
222
|
const tableTitle = cut > 0 ? rawTitle.slice(0, cut) : rawTitle.slice(0, 120);
|
|
223
223
|
|
|
224
224
|
const cite = (what: string) =>
|
|
225
|
-
`COMPUTED (${operation}) — ${what}, read from the typed table "${tableTitle}"
|
|
225
|
+
`COMPUTED (${operation}) — ${what}, read from the typed table "${tableTitle}". Present this result and cite the table's clause; the value is machine-computed from the table payload, do not recompute or round it differently. The machine table identifier rides the verdict block as data — never write it in your prose.`;
|
|
226
226
|
|
|
227
227
|
if (operation === "count") {
|
|
228
228
|
const cc = classColumn(cols);
|
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
OidcError,
|
|
15
15
|
} from "./oidc";
|
|
16
16
|
import { clearSessionCookie, mintSessionCookie, mintSessionToken, rawSessionToken, readSession, sessionCookieFromToken, SessionClaims } from "./session";
|
|
17
|
+
import { renewSessionClaims } from "./oidc-refresh";
|
|
18
|
+
import { retainRefreshToken } from "./livedata";
|
|
17
19
|
import { bubbleConfirmPage, isAllowedBubbleOrigin } from "./bubble";
|
|
18
20
|
import { dropOpAccessToken, retainOpAccessToken } from "./livedata";
|
|
19
21
|
|
|
@@ -47,6 +49,9 @@ export interface AuthConfig {
|
|
|
47
49
|
sessionSecret: string;
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
// how long a session serves before renewal re-judges it against the OP
|
|
53
|
+
const RENEW_AFTER_MS = 60 * 60 * 1000;
|
|
54
|
+
|
|
50
55
|
function authConfig(env: any): AuthConfig | null {
|
|
51
56
|
const issuer = (env.OIDC_ISSUER ?? "").trim().replace(/\/$/, "");
|
|
52
57
|
const clientId = env.OIDC_CLIENT_ID;
|
|
@@ -89,7 +94,7 @@ export async function handleLogin(env: any, req: Request): Promise<Response> {
|
|
|
89
94
|
const url = buildAuthorizationUrl(meta, {
|
|
90
95
|
clientId: cfg.clientId,
|
|
91
96
|
redirectUri: cfg.redirectUri,
|
|
92
|
-
scopes: "openid profile email roles",
|
|
97
|
+
scopes: "openid profile email roles offline_access",
|
|
93
98
|
state,
|
|
94
99
|
nonce,
|
|
95
100
|
codeChallenge: pkce.challenge,
|
|
@@ -181,6 +186,11 @@ export async function handleCallback(env: any, req: Request): Promise<Response>
|
|
|
181
186
|
if (typeof token.access_token === "string" && typeof token.expires_in === "number") {
|
|
182
187
|
await retainOpAccessToken(env, session.token, token.access_token, token.expires_in);
|
|
183
188
|
}
|
|
189
|
+
// the session's lifeline (oidc-refresh.ts): the OP's refresh token
|
|
190
|
+
// is what makes renewal a RE-JUDGMENT instead of a re-stamp
|
|
191
|
+
if (typeof token.refresh_token === "string" && token.refresh_token) {
|
|
192
|
+
await retainRefreshToken(env, session.token, token.refresh_token);
|
|
193
|
+
}
|
|
184
194
|
// Bubble bridge: hand the session to the embedded panel as a Bearer
|
|
185
195
|
// token via the confirm page — postMessage to the validated origin
|
|
186
196
|
// ONLY, and only on the user's explicit click (bubble.ts). The
|
|
@@ -211,9 +221,34 @@ export async function handleMe(env: any, req: Request): Promise<Response> {
|
|
|
211
221
|
const cfg = authConfig(env);
|
|
212
222
|
const session = cfg ? await readSession(req, cfg.sessionSecret) : null;
|
|
213
223
|
const headers: Record<string, string> = { "content-type": "application/json" };
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
224
|
+
// Renewal is a RE-JUDGMENT, not a re-stamp (oidc-refresh.ts): a
|
|
225
|
+
// session older than the threshold presents the OP's refresh token,
|
|
226
|
+
// whose grant re-judges the live standing — a deactivated account's
|
|
227
|
+
// grant family is dead, the OP refuses, and the session ENDS here
|
|
228
|
+
// instead of silently serving stale claims for a week. A session with
|
|
229
|
+
// no stored refresh token (pre-offline_access logins) falls back to
|
|
230
|
+
// the legacy re-stamp; a network refusal keeps the session and
|
|
231
|
+
// retries on the next load.
|
|
232
|
+
let effective: SessionClaims | null = session;
|
|
233
|
+
if (session && cfg && Date.now() - session.iat > RENEW_AFTER_MS) {
|
|
234
|
+
const raw = rawSessionToken(req);
|
|
235
|
+
if (raw) {
|
|
236
|
+
const renewed = await renewSessionClaims(env, { issuer: cfg.issuer, clientId: cfg.clientId, clientSecret: env.OIDC_CLIENT_SECRET, sessionSecret: cfg.sessionSecret }, session, raw);
|
|
237
|
+
if (renewed.kind === "ok") {
|
|
238
|
+
const freshClaims = renewed.renewed.claims;
|
|
239
|
+
const minted = await mintSessionToken(cfg.sessionSecret, freshClaims);
|
|
240
|
+
effective = { ...freshClaims, iat: Date.now(), exp: minted.expiresAt };
|
|
241
|
+
headers["set-cookie"] = sessionCookieFromToken(minted.token);
|
|
242
|
+
} else if (renewed.kind === "revoked") {
|
|
243
|
+
effective = null;
|
|
244
|
+
headers["set-cookie"] = clearSessionCookie();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (effective && cfg && session && effective === session && Date.now() - session.iat > 24 * 3600 * 1000) {
|
|
249
|
+
// the legacy re-stamp: no refresh token available (pre-offline_access
|
|
250
|
+
// sessions) — the claims are what they were, but the 7-day wall still
|
|
251
|
+
// slides for active users
|
|
217
252
|
headers["set-cookie"] = await mintSessionCookie(cfg.sessionSecret, {
|
|
218
253
|
sub: session.sub,
|
|
219
254
|
name: session.name,
|
|
@@ -224,12 +259,12 @@ export async function handleMe(env: any, req: Request): Promise<Response> {
|
|
|
224
259
|
}
|
|
225
260
|
return new Response(
|
|
226
261
|
JSON.stringify({
|
|
227
|
-
authenticated: !!
|
|
228
|
-
name:
|
|
229
|
-
email:
|
|
230
|
-
picture:
|
|
231
|
-
roles:
|
|
232
|
-
tier:
|
|
262
|
+
authenticated: !!effective,
|
|
263
|
+
name: effective?.name ?? null,
|
|
264
|
+
email: effective?.email ?? null,
|
|
265
|
+
picture: effective?.picture ?? null,
|
|
266
|
+
roles: effective?.roles ?? [],
|
|
267
|
+
tier: effective ? "member" : "anon",
|
|
233
268
|
sign_in_available: !!cfg,
|
|
234
269
|
}),
|
|
235
270
|
{ headers },
|
|
@@ -24,18 +24,15 @@ export interface RefCodec {
|
|
|
24
24
|
familyOf(docidentifier: string): string | null;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
// The OIML grammar is @
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
// bundle carries only the OIML grammar), and the retrieval spine of a
|
|
37
|
-
// dual is its OIML side, whichever side prints first.
|
|
38
|
-
import { parseOimlPubid } from "@oimlsmart/oiml-pubid";
|
|
27
|
+
// The OIML grammar is the unified pubid grammar (@pubid/pubid's oiml
|
|
28
|
+
// flavor — single-flavor import so the worker bundle carries the OIML
|
|
29
|
+
// grammar and nothing else). This codec's job is the ADAPTATION: the
|
|
30
|
+
// grammar takes the prefixed form and returns null for everything
|
|
31
|
+
// else; our callers also send bare forms ("R 60-1:2021"), the URN
|
|
32
|
+
// provenance shape, and the dual-published print ("ISO
|
|
33
|
+
// 4064-1:2024|OIML R 49-1:2024") whose retrieval spine is its OIML
|
|
34
|
+
// side, whichever side prints first. The estate's former grammar
|
|
35
|
+
// (@oimlsmart/oiml-pubid) retired into this one (pubid/pubid-ts#63).
|
|
39
36
|
import { oimlGrammarImplementation } from "@pubid/pubid/dist/flavors/oiml/implementation.js";
|
|
40
37
|
|
|
41
38
|
const oimlParser = oimlGrammarImplementation();
|
|
@@ -55,12 +52,13 @@ interface PubidHash {
|
|
|
55
52
|
edition?: string;
|
|
56
53
|
}
|
|
57
54
|
|
|
58
|
-
/** The
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
|
|
55
|
+
/** The spine of a printed identifier through the unified grammar: the
|
|
56
|
+
* type letter, the normalized number, the part and the edition year.
|
|
57
|
+
* A dual-published print resolves to its OIML member (the caller picks
|
|
58
|
+
* the side); unknown type kinds refuse — never a fabricated letter. */
|
|
59
|
+
function parseOimlSpine(display: string): { doc_number: string; edition?: string; label: string } | null {
|
|
62
60
|
try {
|
|
63
|
-
const h = oimlParser.parse(
|
|
61
|
+
const h = oimlParser.parse(display.trim()).toHash() as PubidHash;
|
|
64
62
|
if (h.number === undefined) return null;
|
|
65
63
|
const kind = String(h._type ?? "").split(":").pop() ?? "";
|
|
66
64
|
const letter = TYPE_LETTER[kind] ?? "";
|
|
@@ -89,8 +87,15 @@ const urnToDisplay = (u: string) => {
|
|
|
89
87
|
};
|
|
90
88
|
|
|
91
89
|
const parsePubid = (doc: string) => {
|
|
90
|
+
// a dual-published print: the OIML side is the spine, whichever side
|
|
91
|
+
// prints first — pick it before the bare-form normalization, which
|
|
92
|
+
// would mis-prefix the co-publisher's side
|
|
93
|
+
if (!/^urn:/i.test(doc) && doc.includes("|")) {
|
|
94
|
+
const side = doc.split("|").map((s) => s.trim()).find((s) => /^(?:OIML|oiml)\b/i.test(s));
|
|
95
|
+
return side ? parseOimlSpine(side) : null;
|
|
96
|
+
}
|
|
92
97
|
const src = /^urn:/i.test(doc) ? urnToDisplay(doc) : /^(?:OIML|oiml)\b/i.test(doc) ? doc : `OIML ${doc}`;
|
|
93
|
-
return src ?
|
|
98
|
+
return src ? parseOimlSpine(src) : null;
|
|
94
99
|
};
|
|
95
100
|
|
|
96
101
|
/** OIML's grammar (delegated): type letter + 1–3 digits, optional part,
|
|
@@ -98,20 +103,13 @@ const parsePubid = (doc: string) => {
|
|
|
98
103
|
* edition is never part of the number. */
|
|
99
104
|
export const oimlPubid: RefCodec = {
|
|
100
105
|
parse(doc, edition) {
|
|
101
|
-
// the dual-published print: the OIML side is the spine, whichever
|
|
102
|
-
// side prints first — resolved before the strict grammar, whose
|
|
103
|
-
// null would otherwise be the whole answer
|
|
104
|
-
if (!/^urn:/i.test(doc) && doc.includes("|")) {
|
|
105
|
-
const side = doc.split("|").map((s) => s.trim()).find((s) => /^(?:OIML|oiml)\b/i.test(s));
|
|
106
|
-
const dual = side ? dualOimlSpine(side) : null;
|
|
107
|
-
if (dual) return dual;
|
|
108
|
-
}
|
|
109
106
|
const p = parsePubid(doc);
|
|
110
|
-
if (!p
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
if (!p) return null;
|
|
108
|
+
// the caller's edition is bibdata's truth — it wins over the print's
|
|
109
|
+
if (edition && p.edition !== edition) {
|
|
110
|
+
return { ...p, edition, label: p.label.split(":")[0] + `:${edition}` };
|
|
111
|
+
}
|
|
112
|
+
return p;
|
|
115
113
|
},
|
|
116
114
|
scanQuestion(query) {
|
|
117
115
|
const re = /\b(OIML\s+)?([RDBGE])(\s*)0*(\d{1,3})(?:\s*[-–]\s*\d+)?(?:\s*:\s*(\d{4}))?/gi;
|
|
@@ -131,7 +129,10 @@ export const oimlPubid: RefCodec = {
|
|
|
131
129
|
},
|
|
132
130
|
familyOf(di) {
|
|
133
131
|
const p = parsePubid(di);
|
|
134
|
-
if (p
|
|
132
|
+
if (p) {
|
|
133
|
+
const m = /^OIML ([A-Z]+) (\d{1,3})/.exec(p.label);
|
|
134
|
+
return m ? `${m[1]}-${m[2]}` : null;
|
|
135
|
+
}
|
|
135
136
|
const m = /^(?:OIML\s+)?([A-Z])\s?(\d{1,3})(?:[-–]([0-9A-Za-z]+))?/.exec(di);
|
|
136
137
|
return m ? `${m[1]}-${m[2]}` : null;
|
|
137
138
|
},
|
|
@@ -118,7 +118,7 @@ export function evaluateConditionSets(
|
|
|
118
118
|
verdict: "pass",
|
|
119
119
|
matched: matched.map((m) => m.node_id),
|
|
120
120
|
checks: matched[0]!.checks,
|
|
121
|
-
note: `VERDICT: PASS — the stated combination (${kinds.join(", ")}) matches severity set(
|
|
121
|
+
note: `VERDICT: PASS — the stated combination (${kinds.join(", ")}) matches a severity set (${matched[0]!.checks.map((c) => c.band).join("; ")}). Present this verdict and cite the set's clause. The machine set identifier rides the verdict block as data — never write it in your prose.`,
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
const nearest = scored[0]!;
|
|
@@ -127,6 +127,6 @@ export function evaluateConditionSets(
|
|
|
127
127
|
matched: [],
|
|
128
128
|
nearest: { node_id: nearest.node_id, distance: Number(nearest.distance.toFixed(2)), bands: nearest.checks.map((c) => c.band) },
|
|
129
129
|
checks: nearest.checks,
|
|
130
|
-
note: `VERDICT: FAIL — no severity set admits the stated combination. The nearest set
|
|
130
|
+
note: `VERDICT: FAIL — no severity set admits the stated combination. The nearest set (bands: ${nearest.checks.map((c) => c.band).join("; ")}) is the closest match. Say the combination is outside the menu and describe the nearest set's bands; never soften it. The machine set identifier rides the verdict block as data — never write it in your prose.`,
|
|
131
131
|
};
|
|
132
132
|
}
|