@yaklabs-ai/plugin-sdk 0.13.5 → 0.13.6
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 +4 -2
- package/THIRD-PARTY-INVENTORY.json +8 -1
- package/dist/disclosure.d.ts +5 -7
- package/dist/kay-agent-testing.d.ts +30 -7
- package/dist/kay-agent-testing.js +37 -0
- package/dist/kay-agent.d.ts +19 -8
- package/dist/kay-agent.js +197 -2
- package/dist/kay-app.d.ts +60 -55
- package/dist/kay-app.js +66 -50
- package/dist/time.d.ts +157 -0
- package/dist/time.js +37 -0
- package/dist/transcript.d.ts +109 -0
- package/dist/transcript.js +83 -1
- package/package.json +7 -2
- package/skills/directory-plugin-authoring/SKILL.md +7 -7
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ it under the name your plugin code actually imports:
|
|
|
13
13
|
```json
|
|
14
14
|
{
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.13.
|
|
16
|
+
"@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.13.6"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
```
|
|
@@ -62,7 +62,7 @@ Every tool the entrypoint registers is declared in the manifest too:
|
|
|
62
62
|
"description": "Greets people by name.",
|
|
63
63
|
"version": "0.1.0",
|
|
64
64
|
"namespace": "widgets",
|
|
65
|
-
"compatibility": { "sdk": "^0.13.
|
|
65
|
+
"compatibility": { "sdk": "^0.13.6" },
|
|
66
66
|
"targets": {
|
|
67
67
|
"kay": {
|
|
68
68
|
"agent": {
|
|
@@ -122,6 +122,8 @@ naming both versions, instead of loading it and finding no `activate`.
|
|
|
122
122
|
| `@bonsai/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
|
|
123
123
|
| `@bonsai/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
|
|
124
124
|
| `@bonsai/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
|
|
125
|
+
| `@bonsai/plugin-sdk/time` | `Temporal` (Bonsai's own instance) and the time-zone helpers, from 0.13.6 |
|
|
126
|
+
| `@bonsai/plugin-sdk/transcript` | The active-branch walk, the turn walk and the run records of a session log |
|
|
125
127
|
|
|
126
128
|
`kay-agent/host` is intentionally not published; it is Bonsai's own loading
|
|
127
129
|
machinery, not an authoring API.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "@yaklabs-ai/plugin-sdk",
|
|
4
|
-
"version": "0.13.
|
|
4
|
+
"version": "0.13.6",
|
|
5
5
|
"target": "npm",
|
|
6
6
|
"firstPartyLicense": "MIT",
|
|
7
7
|
"bundled": [
|
|
@@ -50,6 +50,13 @@
|
|
|
50
50
|
"source": "https://github.com/eemeli/yaml",
|
|
51
51
|
"note": "Installed as a consumer dependency; it is not bundled into the staged artifacts.",
|
|
52
52
|
"versionRange": "^2.9.0"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "@js-temporal/polyfill",
|
|
56
|
+
"license": "ISC",
|
|
57
|
+
"source": "https://github.com/js-temporal/temporal-polyfill",
|
|
58
|
+
"note": "Installed as a consumer dependency; it is not bundled into the staged artifacts.",
|
|
59
|
+
"versionRange": "0.5.1"
|
|
53
60
|
}
|
|
54
61
|
]
|
|
55
62
|
}
|
package/dist/disclosure.d.ts
CHANGED
|
@@ -2109,11 +2109,9 @@ declare interface KayAppTimeSnapshot {
|
|
|
2109
2109
|
/**
|
|
2110
2110
|
* The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
|
|
2111
2111
|
* One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
|
|
2112
|
-
* never compare zone ids with
|
|
2113
|
-
*
|
|
2114
|
-
*
|
|
2115
|
-
* results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
|
|
2116
|
-
* time for the user.
|
|
2112
|
+
* never compare zone ids with `===`: compare with `sameZone` from `@bonsai/plugin-sdk/time`. Pass
|
|
2113
|
+
* `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a time for the
|
|
2114
|
+
* user.
|
|
2117
2115
|
*
|
|
2118
2116
|
* When `zoneSource` is `utc-fallback` the zone is unknown, and this value is `UTC` only because a
|
|
2119
2117
|
* value is required.
|
|
@@ -3696,8 +3694,8 @@ declare function ReturnTypeDeferred<Type extends TSchema>(type: Type, options?:
|
|
|
3696
3694
|
* owns:
|
|
3697
3695
|
* - {@link RunFailureReason}.
|
|
3698
3696
|
* does_not_own:
|
|
3699
|
-
* - Classifying a failure into a reason (
|
|
3700
|
-
*
|
|
3697
|
+
* - Classifying a failure into a reason (`./run-failure-classifier.ts`), or the engine's
|
|
3698
|
+
* run-error mapping and recovery policy (`@herd/herd-agent`).
|
|
3701
3699
|
* ---
|
|
3702
3700
|
*/
|
|
3703
3701
|
/** Provider-neutral factual category for a failed model run. */
|
|
@@ -481,6 +481,19 @@ declare interface ConvertedArtifact {
|
|
|
481
481
|
*/
|
|
482
482
|
declare function Create(hidden: ObjectLike_2, enumerable: ObjectLike_2, options?: ObjectLike_2): ObjectLike_2;
|
|
483
483
|
|
|
484
|
+
/**
|
|
485
|
+
* A {@link TestClock} starting at `startMs`. Without a `zone` it answers the zone as unknown, like
|
|
486
|
+
* {@link fauxKayAgentCapabilities}; with one it answers that zone as the user's. Use it as
|
|
487
|
+
* `{ ...fauxKayAgentCapabilities(), time: createTestClock(0) }`.
|
|
488
|
+
*
|
|
489
|
+
* Throws `RangeError` for a non-finite time, and for a `zone` the host could never answer: the
|
|
490
|
+
* host answers an IANA id in the spelling ICU resolves (`Asia/Calcutta`, not `Asia/Kolkata`), so
|
|
491
|
+
* an alias, an abbreviation such as `EST` or a typo would make a test pass that production fails.
|
|
492
|
+
*/
|
|
493
|
+
export declare function createTestClock(startMs: number, options?: {
|
|
494
|
+
readonly zone?: string;
|
|
495
|
+
}): TestClock;
|
|
496
|
+
|
|
484
497
|
/** Creates a Cyclic type. */
|
|
485
498
|
declare function Cyclic<Defs extends TProperties, Ref extends string>($defs: Defs, $ref: Ref, options?: TSchemaOptions): TCyclic<Defs, Ref>;
|
|
486
499
|
|
|
@@ -2010,11 +2023,9 @@ declare interface KayAppTimeSnapshot {
|
|
|
2010
2023
|
/**
|
|
2011
2024
|
* The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
|
|
2012
2025
|
* One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
|
|
2013
|
-
* never compare zone ids with
|
|
2014
|
-
*
|
|
2015
|
-
*
|
|
2016
|
-
* results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
|
|
2017
|
-
* time for the user.
|
|
2026
|
+
* never compare zone ids with `===`: compare with `sameZone` from `@bonsai/plugin-sdk/time`. Pass
|
|
2027
|
+
* `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a time for the
|
|
2028
|
+
* user.
|
|
2018
2029
|
*
|
|
2019
2030
|
* When `zoneSource` is `utc-fallback` the zone is unknown, and this value is `UTC` only because a
|
|
2020
2031
|
* value is required.
|
|
@@ -3594,8 +3605,8 @@ declare function ReturnTypeDeferred<Type extends TSchema>(type: Type, options?:
|
|
|
3594
3605
|
* owns:
|
|
3595
3606
|
* - {@link RunFailureReason}.
|
|
3596
3607
|
* does_not_own:
|
|
3597
|
-
* - Classifying a failure into a reason (
|
|
3598
|
-
*
|
|
3608
|
+
* - Classifying a failure into a reason (`./run-failure-classifier.ts`), or the engine's
|
|
3609
|
+
* run-error mapping and recovery policy (`@herd/herd-agent`).
|
|
3599
3610
|
* ---
|
|
3600
3611
|
*/
|
|
3601
3612
|
/** Provider-neutral factual category for a failed model run. */
|
|
@@ -5077,6 +5088,18 @@ declare type TEscape0<Index extends string> = Index extends `${infer Left}~0${in
|
|
|
5077
5088
|
|
|
5078
5089
|
declare type TEscape1<Index extends string> = Index extends `${infer Left}~1${infer Right}` ? `${Left}/${TEscape<Right>}` : Index;
|
|
5079
5090
|
|
|
5091
|
+
/**
|
|
5092
|
+
* A time door (`api.time` / `app.time`) whose clock moves only when the test moves it. It also
|
|
5093
|
+
* answers `nowMs()`, so it replaces `createTestClock` from `@bonsai/time/testing` unchanged.
|
|
5094
|
+
*/
|
|
5095
|
+
export declare interface TestClock extends KayAppTime {
|
|
5096
|
+
nowMs(): number;
|
|
5097
|
+
/** Moves the clock forward (or backward, for a negative value) by `ms`. */
|
|
5098
|
+
advance(ms: number): void;
|
|
5099
|
+
/** Jumps the clock to an absolute epoch-millisecond value. */
|
|
5100
|
+
set(ms: number): void;
|
|
5101
|
+
}
|
|
5102
|
+
|
|
5080
5103
|
/** Applies an Evaluate action to a type. */
|
|
5081
5104
|
declare type TEvaluate<Type extends TSchema> = (TEvaluateAction<Type>);
|
|
5082
5105
|
|
|
@@ -193,6 +193,42 @@ function fauxKayAgentCapabilities() {
|
|
|
193
193
|
familyFolder: { path: async () => void 0 }
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
|
+
function createTestClock(startMs, options = {}) {
|
|
197
|
+
let nowMs = finiteMs(startMs, "startMs");
|
|
198
|
+
const { zone } = options;
|
|
199
|
+
if (zone !== void 0)
|
|
200
|
+
requireResolvedZone(zone);
|
|
201
|
+
return {
|
|
202
|
+
nowMs: () => nowMs,
|
|
203
|
+
snapshot: () => zone === void 0 ? { nowMs, zone: "UTC", zoneSource: "utc-fallback" } : { nowMs, zone, zoneSource: "host" },
|
|
204
|
+
advance(ms) {
|
|
205
|
+
nowMs += finiteMs(ms, "ms");
|
|
206
|
+
},
|
|
207
|
+
set(ms) {
|
|
208
|
+
nowMs = finiteMs(ms, "ms");
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function requireResolvedZone(zone) {
|
|
213
|
+
let resolved;
|
|
214
|
+
try {
|
|
215
|
+
resolved = new Intl.DateTimeFormat("en-US", {
|
|
216
|
+
timeZone: zone
|
|
217
|
+
}).resolvedOptions().timeZone;
|
|
218
|
+
} catch {
|
|
219
|
+
resolved = void 0;
|
|
220
|
+
}
|
|
221
|
+
const ianaShaped = zone.includes("/") || zone === "UTC";
|
|
222
|
+
if (!ianaShaped || resolved !== zone) {
|
|
223
|
+
throw new RangeError(`createTestClock: zone ${JSON.stringify(zone)} is not a zone the host answers` + (resolved !== void 0 && ianaShaped ? `; the host spells it ${JSON.stringify(resolved)}` : ""));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function finiteMs(value, name) {
|
|
227
|
+
if (!Number.isFinite(value)) {
|
|
228
|
+
throw new RangeError(`createTestClock: ${name} must be a finite number, got ${String(value)}`);
|
|
229
|
+
}
|
|
230
|
+
return value;
|
|
231
|
+
}
|
|
196
232
|
function defaultTestToolContext() {
|
|
197
233
|
return { cwd: "/tmp", model: void 0 };
|
|
198
234
|
}
|
|
@@ -209,6 +245,7 @@ function producedResourcesForTest(result) {
|
|
|
209
245
|
return read;
|
|
210
246
|
}
|
|
211
247
|
export {
|
|
248
|
+
createTestClock,
|
|
212
249
|
fauxAuthContext,
|
|
213
250
|
fauxKayAgentCapabilities,
|
|
214
251
|
invokeToolForTest,
|
package/dist/kay-agent.d.ts
CHANGED
|
@@ -551,6 +551,8 @@ declare const CompareResultLeftInside = 2;
|
|
|
551
551
|
|
|
552
552
|
declare const CompareResultRightInside = 3;
|
|
553
553
|
|
|
554
|
+
export declare function compileUriClaim(claim: UriClaim): UriCompiledClaim;
|
|
555
|
+
|
|
554
556
|
/** Applies a Conditional action to the given types. */
|
|
555
557
|
declare function Conditional<Left extends TSchema, Right extends TSchema, True extends TSchema, False extends TSchema>(left: Left, right: Right, true_: True, false_: False, options?: TSchemaOptions): TConditional<Left, Right, True, False>;
|
|
556
558
|
|
|
@@ -2478,11 +2480,9 @@ declare interface KayAppTimeSnapshot {
|
|
|
2478
2480
|
/**
|
|
2479
2481
|
* The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
|
|
2480
2482
|
* One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
|
|
2481
|
-
* never compare zone ids with
|
|
2482
|
-
*
|
|
2483
|
-
*
|
|
2484
|
-
* results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
|
|
2485
|
-
* time for the user.
|
|
2483
|
+
* never compare zone ids with `===`: compare with `sameZone` from `@bonsai/plugin-sdk/time`. Pass
|
|
2484
|
+
* `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a time for the
|
|
2485
|
+
* user.
|
|
2486
2486
|
*
|
|
2487
2487
|
* When `zoneSource` is `utc-fallback` the zone is unknown, and this value is `UTC` only because a
|
|
2488
2488
|
* value is required.
|
|
@@ -5518,8 +5518,8 @@ declare function ReturnTypeDeferred<Type extends TSchema>(type: Type, options?:
|
|
|
5518
5518
|
* owns:
|
|
5519
5519
|
* - {@link RunFailureReason}.
|
|
5520
5520
|
* does_not_own:
|
|
5521
|
-
* - Classifying a failure into a reason (
|
|
5522
|
-
*
|
|
5521
|
+
* - Classifying a failure into a reason (`./run-failure-classifier.ts`), or the engine's
|
|
5522
|
+
* run-error mapping and recovery policy (`@herd/herd-agent`).
|
|
5523
5523
|
* ---
|
|
5524
5524
|
*/
|
|
5525
5525
|
/** Provider-neutral factual category for a failed model run. */
|
|
@@ -10114,7 +10114,7 @@ export declare interface UriCapabilitySpec {
|
|
|
10114
10114
|
readonly returns?: UriPayloadContract;
|
|
10115
10115
|
}
|
|
10116
10116
|
|
|
10117
|
-
declare type UriClaim = UriSchemeClaim | UriPatternClaim | UrlPatternClaim;
|
|
10117
|
+
export declare type UriClaim = UriSchemeClaim | UriPatternClaim | UrlPatternClaim;
|
|
10118
10118
|
|
|
10119
10119
|
declare interface UriCommonFlow {
|
|
10120
10120
|
readonly label: string;
|
|
@@ -10122,6 +10122,17 @@ declare interface UriCommonFlow {
|
|
|
10122
10122
|
readonly example: string;
|
|
10123
10123
|
}
|
|
10124
10124
|
|
|
10125
|
+
export declare interface UriCompiledClaim {
|
|
10126
|
+
readonly claim: UriClaim;
|
|
10127
|
+
match(input: string): UriCompiledClaimMatch | undefined;
|
|
10128
|
+
}
|
|
10129
|
+
|
|
10130
|
+
export declare interface UriCompiledClaimMatch {
|
|
10131
|
+
readonly claimKind: UriClaim["kind"];
|
|
10132
|
+
readonly captures?: Record<string, string>;
|
|
10133
|
+
readonly normalizedUri?: string;
|
|
10134
|
+
}
|
|
10135
|
+
|
|
10125
10136
|
/**
|
|
10126
10137
|
* A source changed (or was never witnessed) before a mediated mutation. Thrown by a
|
|
10127
10138
|
* module or by the host tool; the host renders it as a normal "not applied" tool
|
package/dist/kay-agent.js
CHANGED
|
@@ -1,3 +1,197 @@
|
|
|
1
|
+
// packages/herd-uri/dist/claims.js
|
|
2
|
+
var SCHEME_RE = /^([a-z][a-z0-9+.-]*):\/\//i;
|
|
3
|
+
var CAPTURE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
4
|
+
var REST_CAPTURE_RE = /^:([A-Za-z_][A-Za-z0-9_]*)\*$/;
|
|
5
|
+
var CONSTRAINED_CAPTURE_RE = /^([A-Za-z_][A-Za-z0-9_]*)(?:\((.*)\))?$/;
|
|
6
|
+
var MAX_CAPTURE_CONSTRAINT_LENGTH = 64;
|
|
7
|
+
function compileUriClaim(claim) {
|
|
8
|
+
if (claim.kind === "scheme") {
|
|
9
|
+
const scheme = normalizeProtocol(claim.scheme);
|
|
10
|
+
return {
|
|
11
|
+
claim,
|
|
12
|
+
match(input) {
|
|
13
|
+
const actual = SCHEME_RE.exec(input.trim())?.[1]?.toLowerCase();
|
|
14
|
+
if (actual !== scheme)
|
|
15
|
+
return void 0;
|
|
16
|
+
return { claimKind: claim.kind };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const pattern = compileRoutePattern(claim.pattern);
|
|
21
|
+
return {
|
|
22
|
+
claim,
|
|
23
|
+
match(input) {
|
|
24
|
+
const parsed = parsePatternInput(input);
|
|
25
|
+
if (parsed === void 0)
|
|
26
|
+
return void 0;
|
|
27
|
+
const captures = matchRoute(pattern, parsed);
|
|
28
|
+
if (captures === void 0)
|
|
29
|
+
return void 0;
|
|
30
|
+
return {
|
|
31
|
+
claimKind: claim.kind,
|
|
32
|
+
...Object.keys(captures).length > 0 ? { captures } : {},
|
|
33
|
+
...claim.normalizeTo !== void 0 ? {
|
|
34
|
+
normalizedUri: withInputSearch(claim, pattern, parsed, interpolateNormalizeTo(claim.normalizeTo, captures, pattern.restCaptures ?? []))
|
|
35
|
+
} : {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function normalizeProtocol(value) {
|
|
41
|
+
return value.replace(/:$/, "").toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
function parsePatternInput(input) {
|
|
44
|
+
try {
|
|
45
|
+
const url = new URL(input.trim());
|
|
46
|
+
return {
|
|
47
|
+
protocol: normalizeProtocol(url.protocol),
|
|
48
|
+
hostname: url.hostname.toLowerCase(),
|
|
49
|
+
pathname: url.pathname,
|
|
50
|
+
search: url.search.startsWith("?") ? url.search.slice(1) : url.search
|
|
51
|
+
};
|
|
52
|
+
} catch {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function compileRoutePattern(pattern) {
|
|
57
|
+
const pathname = pattern.pathname !== void 0 ? compileParts(pattern.pathname, "/", { allowRest: true }) : void 0;
|
|
58
|
+
return {
|
|
59
|
+
...pattern.protocol !== void 0 ? { protocol: normalizeProtocol(pattern.protocol) } : {},
|
|
60
|
+
...pattern.hostname !== void 0 ? { hostname: compileParts(pattern.hostname.toLowerCase(), ".") } : {},
|
|
61
|
+
...pathname !== void 0 ? { pathname } : {},
|
|
62
|
+
...pathname !== void 0 ? {
|
|
63
|
+
restCaptures: pathname.filter((part) => part.rest === true).map((part) => part.capture)
|
|
64
|
+
} : {},
|
|
65
|
+
...pattern.search !== void 0 ? { search: compileParts(pattern.search.replace(/^\?/, ""), "&") } : {}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function compileParts(value, separator, options = {}) {
|
|
69
|
+
if (value === "")
|
|
70
|
+
return [];
|
|
71
|
+
const parts = value.split(separator);
|
|
72
|
+
return parts.map((part, index) => {
|
|
73
|
+
const restMatch = REST_CAPTURE_RE.exec(part);
|
|
74
|
+
if (restMatch !== null) {
|
|
75
|
+
if (options.allowRest !== true || index !== parts.length - 1) {
|
|
76
|
+
throw new Error("URI claim rest captures must be final pathname segments.");
|
|
77
|
+
}
|
|
78
|
+
return { capture: restMatch[1], rest: true };
|
|
79
|
+
}
|
|
80
|
+
if (part.startsWith(":")) {
|
|
81
|
+
const rawCapture = part.slice(1);
|
|
82
|
+
const match = CONSTRAINED_CAPTURE_RE.exec(rawCapture);
|
|
83
|
+
if (match === null) {
|
|
84
|
+
throw new Error(`Invalid URI claim capture ':${rawCapture}'.`);
|
|
85
|
+
}
|
|
86
|
+
const capture = match[1];
|
|
87
|
+
if (!CAPTURE_RE.test(capture)) {
|
|
88
|
+
throw new Error(`Invalid URI claim capture ':${rawCapture}'.`);
|
|
89
|
+
}
|
|
90
|
+
const constraint = match[2];
|
|
91
|
+
if (constraint !== void 0)
|
|
92
|
+
assertSupportedConstraint(constraint);
|
|
93
|
+
return {
|
|
94
|
+
capture,
|
|
95
|
+
...constraint !== void 0 ? { constraint: new RegExp(`^(?:${constraint})$`) } : {}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return { literal: part };
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function assertSupportedConstraint(constraint) {
|
|
102
|
+
if (constraint.length > MAX_CAPTURE_CONSTRAINT_LENGTH || /[()|]/.test(constraint)) {
|
|
103
|
+
throw new Error("URI claim capture constraints must be short segment regexes without grouping or alternation.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function matchRoute(pattern, input) {
|
|
107
|
+
if (pattern.protocol !== void 0 && pattern.protocol !== input.protocol) {
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
const captures = {};
|
|
111
|
+
if (pattern.hostname !== void 0 && !matchParts(pattern.hostname, input.hostname, ".", captures)) {
|
|
112
|
+
return void 0;
|
|
113
|
+
}
|
|
114
|
+
if (pattern.pathname !== void 0 && !matchParts(pattern.pathname, input.pathname, "/", captures)) {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
if (pattern.search !== void 0 && !matchParts(pattern.search, input.search, "&", captures)) {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
return captures;
|
|
121
|
+
}
|
|
122
|
+
function matchParts(pattern, value, separator, captures) {
|
|
123
|
+
const parts = value.split(separator);
|
|
124
|
+
let partIndex = 0;
|
|
125
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
126
|
+
const expected = pattern[i];
|
|
127
|
+
if (expected.rest === true) {
|
|
128
|
+
const remaining = parts.slice(partIndex);
|
|
129
|
+
if (remaining.every((part) => part === ""))
|
|
130
|
+
return false;
|
|
131
|
+
captures[expected.capture] = remaining.join(separator);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
if (partIndex >= parts.length)
|
|
135
|
+
return false;
|
|
136
|
+
const actual = parts[partIndex];
|
|
137
|
+
if (expected.capture !== void 0) {
|
|
138
|
+
const decoded = safeDecode(actual);
|
|
139
|
+
if (expected.constraint !== void 0 && !expected.constraint.test(decoded)) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
captures[expected.capture] = decoded;
|
|
143
|
+
partIndex += 1;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (expected.literal !== actual)
|
|
147
|
+
return false;
|
|
148
|
+
partIndex += 1;
|
|
149
|
+
}
|
|
150
|
+
return partIndex === parts.length;
|
|
151
|
+
}
|
|
152
|
+
function safeDecode(value) {
|
|
153
|
+
try {
|
|
154
|
+
return decodeURIComponent(value);
|
|
155
|
+
} catch {
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function withInputSearch(claim, pattern, input, normalized) {
|
|
160
|
+
if (claim.kind !== "uriPattern" || claim.normalizeTo === void 0 || pattern.search !== void 0 || input.search.length === 0 || claim.normalizeTo.includes("?") || templateProtocol(claim.normalizeTo) !== input.protocol) {
|
|
161
|
+
return normalized;
|
|
162
|
+
}
|
|
163
|
+
return `${normalized}?${input.search}`;
|
|
164
|
+
}
|
|
165
|
+
function templateProtocol(template) {
|
|
166
|
+
return SCHEME_RE.exec(template)?.[1]?.toLowerCase();
|
|
167
|
+
}
|
|
168
|
+
function interpolateNormalizeTo(template, captures, restCaptures) {
|
|
169
|
+
return template.replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, (full, name, offset) => {
|
|
170
|
+
const value = captures[name];
|
|
171
|
+
if (value === void 0)
|
|
172
|
+
return full;
|
|
173
|
+
return encodeCaptureValue({
|
|
174
|
+
template,
|
|
175
|
+
offset,
|
|
176
|
+
value,
|
|
177
|
+
rest: restCaptures.includes(name)
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function encodeCaptureValue({ template, offset, value, rest }) {
|
|
182
|
+
const normalized = isAuthorityCapture(template, offset) ? value.toLowerCase() : value;
|
|
183
|
+
if (!rest)
|
|
184
|
+
return encodeURIComponent(normalized);
|
|
185
|
+
return normalized.split("/").join("/");
|
|
186
|
+
}
|
|
187
|
+
function isAuthorityCapture(template, offset) {
|
|
188
|
+
const prefix = template.slice(0, offset);
|
|
189
|
+
const schemeIndex = prefix.lastIndexOf("://");
|
|
190
|
+
if (schemeIndex === -1)
|
|
191
|
+
return false;
|
|
192
|
+
return !/[/?#]/.test(prefix.slice(schemeIndex + 3));
|
|
193
|
+
}
|
|
194
|
+
|
|
1
195
|
// packages/herd-uri/dist/errors.js
|
|
2
196
|
var UriError = class extends Error {
|
|
3
197
|
};
|
|
@@ -142,10 +336,10 @@ function isProducedResourceDeclaration(value) {
|
|
|
142
336
|
// packages/herd-uri/dist/template-route.js
|
|
143
337
|
var PLACEHOLDER_RE = /<([^<>]+)>/g;
|
|
144
338
|
var REST_SUFFIX = "...";
|
|
145
|
-
var
|
|
339
|
+
var SCHEME_RE2 = /^([a-zA-Z][a-zA-Z0-9+.-]*):(?:\/\/)?(.*)$/s;
|
|
146
340
|
function parseRoute(address) {
|
|
147
341
|
const trimmed = address.trim();
|
|
148
|
-
const match =
|
|
342
|
+
const match = SCHEME_RE2.exec(trimmed);
|
|
149
343
|
const scheme = match?.[1]?.toLowerCase() ?? "";
|
|
150
344
|
const rest = match?.[2] ?? trimmed;
|
|
151
345
|
const [rawPath = "", rawQuery] = splitQuery(rest);
|
|
@@ -1577,6 +1771,7 @@ export {
|
|
|
1577
1771
|
bytesToBase64,
|
|
1578
1772
|
capability,
|
|
1579
1773
|
collectKayAgentAdvertisement,
|
|
1774
|
+
compileUriClaim,
|
|
1580
1775
|
contentDigest,
|
|
1581
1776
|
contentResult,
|
|
1582
1777
|
createFallbackOnlyWithJev,
|