@vibe-agent-toolkit/utils 0.2.0-rc.3 → 0.2.0-rc.4

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.
Files changed (74) hide show
  1. package/README.md +21 -13
  2. package/dist/crawl-timing.d.ts +43 -66
  3. package/dist/crawl-timing.d.ts.map +1 -1
  4. package/dist/crawl-timing.js +35 -79
  5. package/dist/crawl-timing.js.map +1 -1
  6. package/dist/crawl.d.ts +2 -4
  7. package/dist/crawl.d.ts.map +1 -1
  8. package/dist/crawl.js +2 -4
  9. package/dist/crawl.js.map +1 -1
  10. package/dist/git.d.ts +11 -4
  11. package/dist/git.d.ts.map +1 -1
  12. package/dist/git.js +11 -4
  13. package/dist/git.js.map +1 -1
  14. package/dist/index.d.ts +19 -20
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +19 -41
  17. package/dist/index.js.map +1 -1
  18. package/dist/project.d.ts +7 -5
  19. package/dist/project.d.ts.map +1 -1
  20. package/dist/project.js +7 -5
  21. package/dist/project.js.map +1 -1
  22. package/dist/testing.d.ts +73 -3
  23. package/dist/testing.d.ts.map +1 -1
  24. package/dist/testing.js +93 -3
  25. package/dist/testing.js.map +1 -1
  26. package/dist/timing-dump.d.ts +22 -5
  27. package/dist/timing-dump.d.ts.map +1 -1
  28. package/dist/timing-dump.js +89 -23
  29. package/dist/timing-dump.js.map +1 -1
  30. package/eslint/index.cjs +9 -0
  31. package/eslint/index.d.cts +14 -7
  32. package/eslint/rules/no-process-exit-in-phase.cjs +117 -0
  33. package/package.json +5 -7
  34. package/dist/link-auth/build-headers.d.ts +0 -34
  35. package/dist/link-auth/build-headers.d.ts.map +0 -1
  36. package/dist/link-auth/build-headers.js +0 -58
  37. package/dist/link-auth/build-headers.js.map +0 -1
  38. package/dist/link-auth/expand-macro.d.ts +0 -38
  39. package/dist/link-auth/expand-macro.d.ts.map +0 -1
  40. package/dist/link-auth/expand-macro.js +0 -139
  41. package/dist/link-auth/expand-macro.js.map +0 -1
  42. package/dist/link-auth/macros.yaml +0 -50
  43. package/dist/link-auth/resolve-token.d.ts +0 -83
  44. package/dist/link-auth/resolve-token.d.ts.map +0 -1
  45. package/dist/link-auth/resolve-token.js +0 -115
  46. package/dist/link-auth/resolve-token.js.map +0 -1
  47. package/dist/link-auth/resolve.d.ts +0 -102
  48. package/dist/link-auth/resolve.d.ts.map +0 -1
  49. package/dist/link-auth/resolve.js +0 -66
  50. package/dist/link-auth/resolve.js.map +0 -1
  51. package/dist/link-auth/rewrite.d.ts +0 -52
  52. package/dist/link-auth/rewrite.d.ts.map +0 -1
  53. package/dist/link-auth/rewrite.js +0 -102
  54. package/dist/link-auth/rewrite.js.map +0 -1
  55. package/dist/link-auth/select-provider.d.ts +0 -30
  56. package/dist/link-auth/select-provider.d.ts.map +0 -1
  57. package/dist/link-auth/select-provider.js +0 -55
  58. package/dist/link-auth/select-provider.js.map +0 -1
  59. package/dist/link-auth/template.d.ts +0 -40
  60. package/dist/link-auth/template.d.ts.map +0 -1
  61. package/dist/link-auth/template.js +0 -89
  62. package/dist/link-auth/template.js.map +0 -1
  63. package/dist/link-auth/transforms.d.ts +0 -46
  64. package/dist/link-auth/transforms.d.ts.map +0 -1
  65. package/dist/link-auth/transforms.js +0 -52
  66. package/dist/link-auth/transforms.js.map +0 -1
  67. package/dist/template-entry.d.ts +0 -10
  68. package/dist/template-entry.d.ts.map +0 -1
  69. package/dist/template-entry.js +0 -10
  70. package/dist/template-entry.js.map +0 -1
  71. package/dist/template.d.ts +0 -7
  72. package/dist/template.d.ts.map +0 -1
  73. package/dist/template.js +0 -18
  74. package/dist/template.js.map +0 -1
@@ -1,102 +0,0 @@
1
- /**
2
- * Rewrite pipeline: ordered when → vars → to.
3
- *
4
- * Each provider declares one or more rewrite rules. For an input URL the
5
- * pipeline strips `?query` and `#fragment`, finds the first rule whose
6
- * `when` regex matches, computes `vars` (templates over captures), and
7
- * renders the `to` template against captures + vars merged. The merged
8
- * context flows out so downstream header templates can interpolate the
9
- * same variables.
10
- *
11
- * Per design issue #113 §4 (vocabulary) and §5.2 (fragment/query
12
- * stripping must precede a greedy `(?<path>.+)` capture).
13
- */
14
- import { renderTemplate } from './template.js';
15
- /**
16
- * Thrown when a rule's `when` field is not a compilable regex.
17
- */
18
- export class InvalidRewriteRuleError extends Error {
19
- constructor(pattern, cause) {
20
- const reason = cause instanceof Error ? cause.message : String(cause);
21
- super(`Invalid rewrite rule "when" regex: ${pattern}. ${reason}`);
22
- this.name = 'InvalidRewriteRuleError';
23
- }
24
- }
25
- /**
26
- * Thrown when a `vars` key collides with a named capture in `when`.
27
- * Adopter must rename one — vars cannot shadow captures (the design's
28
- * intent is captures + vars in a single namespace).
29
- */
30
- export class VarCaptureCollisionError extends Error {
31
- constructor(name) {
32
- super(`Rewrite var "${name}" collides with a regex capture of the same name. Rename one.`);
33
- this.name = 'VarCaptureCollisionError';
34
- }
35
- }
36
- /**
37
- * Apply an ordered list of rewrite rules to a URL.
38
- *
39
- * @returns `{ matched: true, rewrittenUrl, context }` for the first matching
40
- * rule, or `{ matched: false }` if no rule claims the URL.
41
- * @throws {InvalidRewriteRuleError} if a `when` field does not compile
42
- * @throws {VarCaptureCollisionError} if a vars name shadows a capture name
43
- * @throws {TemplateMissingVarError} from a template referencing an unknown name
44
- * @throws {TemplateSyntaxError} from a malformed template expression
45
- * @throws {UnknownTransformError} from a template calling an unknown transform
46
- */
47
- export function rewriteUrl(url, rules) {
48
- const stripped = stripFragmentAndQuery(url);
49
- for (const rule of rules) {
50
- const regex = compileWhen(rule.when);
51
- const match = regex.exec(stripped);
52
- if (match === null)
53
- continue;
54
- const captures = collectCaptures(match);
55
- const context = computeContext(captures, rule.vars);
56
- const rewrittenUrl = renderTemplate(rule.to, context);
57
- return { matched: true, rewrittenUrl, context };
58
- }
59
- return { matched: false };
60
- }
61
- function stripFragmentAndQuery(url) {
62
- const idx = url.search(/[?#]/);
63
- return idx === -1 ? url : url.slice(0, idx);
64
- }
65
- function compileWhen(pattern) {
66
- try {
67
- // Rule patterns originate in trusted config (see design §8); runtime
68
- // compilation is intentional, not user-input regex injection.
69
- // eslint-disable-next-line security/detect-non-literal-regexp
70
- return new RegExp(pattern);
71
- }
72
- catch (e) {
73
- throw new InvalidRewriteRuleError(pattern, e);
74
- }
75
- }
76
- function collectCaptures(match) {
77
- const captures = Object.create(null);
78
- // The lib typedef for RegExpMatchArray.groups says values are `string`, but
79
- // optional named groups that did not match show up at runtime as `undefined`.
80
- // Cast to reflect runtime reality so the filter below is type-meaningful.
81
- const groups = (match.groups ?? {});
82
- for (const [key, value] of Object.entries(groups)) {
83
- if (value !== undefined) {
84
- captures[key] = value;
85
- }
86
- }
87
- return captures;
88
- }
89
- function computeContext(captures, vars) {
90
- const context = Object.create(null);
91
- Object.assign(context, captures);
92
- if (vars === undefined)
93
- return context;
94
- for (const [name, template] of Object.entries(vars)) {
95
- if (Object.hasOwn(captures, name)) {
96
- throw new VarCaptureCollisionError(name);
97
- }
98
- context[name] = renderTemplate(template, captures);
99
- }
100
- return context;
101
- }
102
- //# sourceMappingURL=rewrite.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rewrite.js","sourceRoot":"","sources":["../../src/link-auth/rewrite.ts"],"names":[],"mappings":"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"}
@@ -1,30 +0,0 @@
1
- /**
2
- * Provider selection by URL host.
3
- *
4
- * Iterates the configured providers in order; the first one whose `match.host`
5
- * glob matches the URL hostname (and no `match.excludeHost` glob excludes it)
6
- * claims the URL. Returns `undefined` if no provider claims it — the caller
7
- * then falls back to anonymous link-checking.
8
- *
9
- * Hostname matching is case-insensitive per RFC 3986. Pattern syntax follows
10
- * `picomatch` (already a utils dep): `*` matches any character, `**` matches
11
- * across `/`. For hostnames (no slashes) the practical effect is that `*`
12
- * happily matches dots — e.g. `*.sharepoint.com` claims both
13
- * `contoso.sharepoint.com` and `foo.bar.sharepoint.com`.
14
- *
15
- * Per design issue #113 §4 (vocabulary item 1: match.host + excludeHost).
16
- */
17
- export interface ProviderMatch {
18
- readonly host: string;
19
- readonly excludeHost?: readonly string[];
20
- }
21
- /**
22
- * Find the first provider whose `match` claims the given URL.
23
- *
24
- * @returns the matching provider, or `undefined` if none claim the URL (no
25
- * pattern matched, all candidates were excluded, or the URL is malformed).
26
- */
27
- export declare function selectProvider<P extends {
28
- readonly match: ProviderMatch;
29
- }>(url: string, providers: readonly P[]): P | undefined;
30
- //# sourceMappingURL=select-provider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"select-provider.d.ts","sourceRoot":"","sources":["../../src/link-auth/select-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,EACxE,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,CAAC,EAAE,GACtB,CAAC,GAAG,SAAS,CAUf"}
@@ -1,55 +0,0 @@
1
- /**
2
- * Provider selection by URL host.
3
- *
4
- * Iterates the configured providers in order; the first one whose `match.host`
5
- * glob matches the URL hostname (and no `match.excludeHost` glob excludes it)
6
- * claims the URL. Returns `undefined` if no provider claims it — the caller
7
- * then falls back to anonymous link-checking.
8
- *
9
- * Hostname matching is case-insensitive per RFC 3986. Pattern syntax follows
10
- * `picomatch` (already a utils dep): `*` matches any character, `**` matches
11
- * across `/`. For hostnames (no slashes) the practical effect is that `*`
12
- * happily matches dots — e.g. `*.sharepoint.com` claims both
13
- * `contoso.sharepoint.com` and `foo.bar.sharepoint.com`.
14
- *
15
- * Per design issue #113 §4 (vocabulary item 1: match.host + excludeHost).
16
- */
17
- import picomatch from 'picomatch';
18
- /**
19
- * Find the first provider whose `match` claims the given URL.
20
- *
21
- * @returns the matching provider, or `undefined` if none claim the URL (no
22
- * pattern matched, all candidates were excluded, or the URL is malformed).
23
- */
24
- export function selectProvider(url, providers) {
25
- const host = extractHostname(url);
26
- if (host === undefined)
27
- return undefined;
28
- for (const provider of providers) {
29
- if (matches(host, provider.match)) {
30
- return provider;
31
- }
32
- }
33
- return undefined;
34
- }
35
- function extractHostname(url) {
36
- try {
37
- return new URL(url).hostname;
38
- }
39
- catch {
40
- return undefined;
41
- }
42
- }
43
- function matches(host, match) {
44
- const lowerHost = host.toLowerCase();
45
- if (!picomatch.isMatch(lowerHost, match.host.toLowerCase()))
46
- return false;
47
- if (match.excludeHost !== undefined) {
48
- for (const pattern of match.excludeHost) {
49
- if (picomatch.isMatch(lowerHost, pattern.toLowerCase()))
50
- return false;
51
- }
52
- }
53
- return true;
54
- }
55
- //# sourceMappingURL=select-provider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"select-provider.js","sourceRoot":"","sources":["../../src/link-auth/select-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,SAAS,MAAM,WAAW,CAAC;AAOlC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,SAAuB;IAEvB,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEzC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,KAAoB;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAE1E,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACpC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;gBAAE,OAAO,KAAK,CAAC;QACxE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,40 +0,0 @@
1
- /**
2
- * Tiny template renderer for linkAuth rewrite + header templates.
3
- *
4
- * Syntax (strict, no escapes, no nesting):
5
- * - `${name}` → context[name]
6
- * - `${transform(name)}` → applyTransform(transform, context[name])
7
- *
8
- * Anything else inside `${...}` throws `TemplateSyntaxError`. Missing context
9
- * keys throw `TemplateMissingVarError`. Unknown transform names propagate
10
- * `UnknownTransformError` from the transforms allowlist.
11
- *
12
- * This is NOT the project's general-purpose Handlebars renderer
13
- * (`utils/template.ts`) — that one is `{{...}}` and consumed widely. linkAuth
14
- * needs different syntax and a closed transform set; the two coexist by
15
- * namespace (`link-auth/template.ts`).
16
- */
17
- /**
18
- * Thrown when a template references a variable not present in the context.
19
- * Message names the missing variable and includes the full template for
20
- * caller-side debugging.
21
- */
22
- export declare class TemplateMissingVarError extends Error {
23
- constructor(varName: string, template: string);
24
- }
25
- /**
26
- * Thrown when a template contains syntactically invalid content inside `${...}`
27
- * (empty expression, whitespace, unrecognized form) or an unterminated `${`.
28
- */
29
- export declare class TemplateSyntaxError extends Error {
30
- constructor(detail: string, template: string);
31
- }
32
- /**
33
- * Render a template by substituting `${...}` expressions from a context map.
34
- *
35
- * @throws {TemplateMissingVarError} if a referenced variable is absent
36
- * @throws {TemplateSyntaxError} for invalid expressions or unterminated `${`
37
- * @throws {UnknownTransformError} from a `${transform(name)}` call
38
- */
39
- export declare function renderTemplate(template: string, context: Record<string, string>): string;
40
- //# sourceMappingURL=template.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/link-auth/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAI9C;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAI7C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAUxF"}
@@ -1,89 +0,0 @@
1
- /**
2
- * Tiny template renderer for linkAuth rewrite + header templates.
3
- *
4
- * Syntax (strict, no escapes, no nesting):
5
- * - `${name}` → context[name]
6
- * - `${transform(name)}` → applyTransform(transform, context[name])
7
- *
8
- * Anything else inside `${...}` throws `TemplateSyntaxError`. Missing context
9
- * keys throw `TemplateMissingVarError`. Unknown transform names propagate
10
- * `UnknownTransformError` from the transforms allowlist.
11
- *
12
- * This is NOT the project's general-purpose Handlebars renderer
13
- * (`utils/template.ts`) — that one is `{{...}}` and consumed widely. linkAuth
14
- * needs different syntax and a closed transform set; the two coexist by
15
- * namespace (`link-auth/template.ts`).
16
- */
17
- import { applyTransform } from './transforms.js';
18
- const IDENTIFIER = /^[a-zA-Z_]\w*$/;
19
- const TRANSFORM_CALL = /^(?<fn>[a-zA-Z_]\w*)\((?<arg>[a-zA-Z_]\w*)\)$/;
20
- /**
21
- * Thrown when a template references a variable not present in the context.
22
- * Message names the missing variable and includes the full template for
23
- * caller-side debugging.
24
- */
25
- export class TemplateMissingVarError extends Error {
26
- constructor(varName, template) {
27
- super(`Template variable "${varName}" not in context. Template: ${template}`);
28
- this.name = 'TemplateMissingVarError';
29
- }
30
- }
31
- /**
32
- * Thrown when a template contains syntactically invalid content inside `${...}`
33
- * (empty expression, whitespace, unrecognized form) or an unterminated `${`.
34
- */
35
- export class TemplateSyntaxError extends Error {
36
- constructor(detail, template) {
37
- super(`Invalid template syntax — ${detail}. Template: ${template}`);
38
- this.name = 'TemplateSyntaxError';
39
- }
40
- }
41
- /**
42
- * Render a template by substituting `${...}` expressions from a context map.
43
- *
44
- * @throws {TemplateMissingVarError} if a referenced variable is absent
45
- * @throws {TemplateSyntaxError} for invalid expressions or unterminated `${`
46
- * @throws {UnknownTransformError} from a `${transform(name)}` call
47
- */
48
- export function renderTemplate(template, context) {
49
- const rendered = template.replaceAll(/\$\{([^}]*)\}/g, (_match, body) => resolveExpression(body, template, context));
50
- if (rendered.includes('${')) {
51
- throw new TemplateSyntaxError('unterminated "${" with no matching "}"', template);
52
- }
53
- return rendered;
54
- }
55
- function resolveExpression(body, template, context) {
56
- if (body !== body.trim()) {
57
- throw new TemplateSyntaxError(`whitespace in "${body}"`, template);
58
- }
59
- if (IDENTIFIER.test(body)) {
60
- return lookupContextVar(context, body, template);
61
- }
62
- const callMatch = TRANSFORM_CALL.exec(body);
63
- if (callMatch?.groups !== undefined) {
64
- const { fn, arg } = callMatch.groups;
65
- if (fn === undefined || arg === undefined) {
66
- throw new TemplateSyntaxError(`unexpected regex result for "${body}"`, template);
67
- }
68
- return applyTransform(fn, lookupContextVar(context, arg, template));
69
- }
70
- throw new TemplateSyntaxError(`unrecognized expression "${body}"`, template);
71
- }
72
- /**
73
- * Fetch a variable from the context map, blocking prototype-chain bypass.
74
- *
75
- * Without `Object.hasOwn`, `context["__proto__"]` would return `Object.prototype`
76
- * (a non-undefined object) and the renderer would substitute `[object Object]`
77
- * into the output. Mirrors the closed-allowlist discipline in `transforms.ts`.
78
- */
79
- function lookupContextVar(context, key, template) {
80
- if (!Object.hasOwn(context, key)) {
81
- throw new TemplateMissingVarError(key, template);
82
- }
83
- const value = context[key];
84
- if (value === undefined) {
85
- throw new TemplateMissingVarError(key, template);
86
- }
87
- return value;
88
- }
89
- //# sourceMappingURL=template.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/link-auth/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,UAAU,GAAG,gBAAgB,CAAC;AACpC,MAAM,cAAc,GAAG,+CAA+C,CAAC;AAEvE;;;;GAIG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD,YAAY,OAAe,EAAE,QAAgB;QAC3C,KAAK,CAAC,sBAAsB,OAAO,+BAA+B,QAAQ,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,MAAc,EAAE,QAAgB;QAC1C,KAAK,CAAC,6BAA6B,MAAM,eAAe,QAAQ,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,OAA+B;IAC9E,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE,CAC9E,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAC3C,CAAC;IAEF,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,mBAAmB,CAAC,wCAAwC,EAAE,QAAQ,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,iBAAiB,CACxB,IAAY,EACZ,QAAgB,EAChB,OAA+B;IAE/B,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,IAAI,GAAG,EAAE,QAAQ,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,OAAO,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,SAAS,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QACpC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC;QACrC,IAAI,EAAE,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC1C,MAAM,IAAI,mBAAmB,CAAC,gCAAgC,IAAI,GAAG,EAAE,QAAQ,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,cAAc,CAAC,EAAE,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,IAAI,mBAAmB,CAAC,4BAA4B,IAAI,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CACvB,OAA+B,EAC/B,GAAW,EACX,QAAgB;IAEhB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,uBAAuB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,uBAAuB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1,46 +0,0 @@
1
- /**
2
- * Transform allowlist for linkAuth rewrite templates.
3
- *
4
- * Rewrite `to:` templates may call transforms over named regex captures —
5
- * e.g. `${base64url(u)}` for Microsoft Graph share-ids. The allowed set is
6
- * frozen in this file: adding a transform requires a VAT PR (see issue #113
7
- * design §4.1). There is no arbitrary-evaluation path.
8
- *
9
- * v1 inputs are assumed to be ASCII URL host/path captures. Non-ASCII edge
10
- * cases (lone surrogates) are pinned by tests so future regressions surface.
11
- */
12
- declare const TRANSFORMS: {
13
- readonly base64url: (s: string) => string;
14
- readonly urlencode: (s: string) => string;
15
- readonly lower: (s: string) => string;
16
- };
17
- export type TransformName = keyof typeof TRANSFORMS;
18
- /**
19
- * The closed allowlist of transform names. Callers parsing rewrite templates
20
- * can validate transform calls (e.g. `${base64url(u)}`) against this list at
21
- * config-load time, surfacing typos before any URL is rewritten.
22
- */
23
- export declare const ALLOWED_TRANSFORMS: readonly TransformName[];
24
- /**
25
- * Thrown by `applyTransform` when called with a name not in the closed
26
- * allowlist. The message names the bad transform and the full allowlist so
27
- * a misconfigured macro surfaces a clear error at load time.
28
- */
29
- export declare class UnknownTransformError extends Error {
30
- constructor(name: string);
31
- }
32
- /**
33
- * Dispatch a transform by name on a string input.
34
- *
35
- * Security claim: only the names in `ALLOWED_TRANSFORMS` resolve; any other
36
- * input throws `UnknownTransformError`. Lookup uses `Object.hasOwn` to block
37
- * prototype-chain keys (`toString`, `__proto__`, `constructor`, …) that a
38
- * `name in TRANSFORMS` check would let through.
39
- *
40
- * @throws {UnknownTransformError} if `name` is not in the allowlist
41
- * @throws {URIError} from `urlencode` on lone-surrogate inputs — deliberate;
42
- * v1 callers pass URL-derived captures that cannot legally contain these
43
- */
44
- export declare function applyTransform(name: string, input: string): string;
45
- export {};
46
- //# sourceMappingURL=transforms.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transforms.d.ts","sourceRoot":"","sources":["../../src/link-auth/transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,QAAA,MAAM,UAAU;4BACC,MAAM;4BACN,MAAM;wBACV,MAAM;CAC6B,CAAC;AAEjD,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,UAAU,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,aAAa,EAEtD,CAAC;AAEF;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlE"}
@@ -1,52 +0,0 @@
1
- /**
2
- * Transform allowlist for linkAuth rewrite templates.
3
- *
4
- * Rewrite `to:` templates may call transforms over named regex captures —
5
- * e.g. `${base64url(u)}` for Microsoft Graph share-ids. The allowed set is
6
- * frozen in this file: adding a transform requires a VAT PR (see issue #113
7
- * design §4.1). There is no arbitrary-evaluation path.
8
- *
9
- * v1 inputs are assumed to be ASCII URL host/path captures. Non-ASCII edge
10
- * cases (lone surrogates) are pinned by tests so future regressions surface.
11
- */
12
- const TRANSFORMS = {
13
- base64url: (s) => Buffer.from(s, 'utf8').toString('base64url'),
14
- urlencode: (s) => encodeURIComponent(s),
15
- lower: (s) => s.toLowerCase(),
16
- };
17
- /**
18
- * The closed allowlist of transform names. Callers parsing rewrite templates
19
- * can validate transform calls (e.g. `${base64url(u)}`) against this list at
20
- * config-load time, surfacing typos before any URL is rewritten.
21
- */
22
- export const ALLOWED_TRANSFORMS = Object.freeze(Object.keys(TRANSFORMS));
23
- /**
24
- * Thrown by `applyTransform` when called with a name not in the closed
25
- * allowlist. The message names the bad transform and the full allowlist so
26
- * a misconfigured macro surfaces a clear error at load time.
27
- */
28
- export class UnknownTransformError extends Error {
29
- constructor(name) {
30
- super(`Unknown transform "${name}". Allowed: ${ALLOWED_TRANSFORMS.join(', ')}.`);
31
- this.name = 'UnknownTransformError';
32
- }
33
- }
34
- /**
35
- * Dispatch a transform by name on a string input.
36
- *
37
- * Security claim: only the names in `ALLOWED_TRANSFORMS` resolve; any other
38
- * input throws `UnknownTransformError`. Lookup uses `Object.hasOwn` to block
39
- * prototype-chain keys (`toString`, `__proto__`, `constructor`, …) that a
40
- * `name in TRANSFORMS` check would let through.
41
- *
42
- * @throws {UnknownTransformError} if `name` is not in the allowlist
43
- * @throws {URIError} from `urlencode` on lone-surrogate inputs — deliberate;
44
- * v1 callers pass URL-derived captures that cannot legally contain these
45
- */
46
- export function applyTransform(name, input) {
47
- if (!Object.hasOwn(TRANSFORMS, name)) {
48
- throw new UnknownTransformError(name);
49
- }
50
- return TRANSFORMS[name](input);
51
- }
52
- //# sourceMappingURL=transforms.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transforms.js","sourceRoot":"","sources":["../../src/link-auth/transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,UAAU,GAAG;IACjB,SAAS,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;IACtE,SAAS,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE;CACS,CAAC;AAIjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA6B,MAAM,CAAC,MAAM,CACvE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAoB,CAC3C,CAAC;AAEF;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,IAAY;QACtB,KAAK,CAAC,sBAAsB,IAAI,eAAe,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,KAAa;IACxD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,UAAU,CAAC,IAAqB,CAAC,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC"}
@@ -1,10 +0,0 @@
1
- /**
2
- * @vibe-agent-toolkit/utils/template
3
- *
4
- * Cached Handlebars rendering with HTML escaping disabled. Pure with respect
5
- * to Node builtins, but it pulls in `handlebars` (and transitively
6
- * `source-map`) — roughly 239KB bundled. Quarantined behind its own subpath
7
- * so importing a path helper never pays for it.
8
- */
9
- export * from './template.js';
10
- //# sourceMappingURL=template-entry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"template-entry.d.ts","sourceRoot":"","sources":["../src/template-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,eAAe,CAAC"}
@@ -1,10 +0,0 @@
1
- /**
2
- * @vibe-agent-toolkit/utils/template
3
- *
4
- * Cached Handlebars rendering with HTML escaping disabled. Pure with respect
5
- * to Node builtins, but it pulls in `handlebars` (and transitively
6
- * `source-map`) — roughly 239KB bundled. Quarantined behind its own subpath
7
- * so importing a path helper never pays for it.
8
- */
9
- export * from './template.js';
10
- //# sourceMappingURL=template-entry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"template-entry.js","sourceRoot":"","sources":["../src/template-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,eAAe,CAAC"}
@@ -1,7 +0,0 @@
1
- /**
2
- * Render a Handlebars template with the given context.
3
- * Uses noEscape since this is for markdown content, not HTML.
4
- * Compiled templates are cached by template string.
5
- */
6
- export declare function renderTemplate(template: string, context: Record<string, unknown>): string;
7
- //# sourceMappingURL=template.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CASzF"}
package/dist/template.js DELETED
@@ -1,18 +0,0 @@
1
- import Handlebars from 'handlebars';
2
- const templateCache = new Map();
3
- /**
4
- * Render a Handlebars template with the given context.
5
- * Uses noEscape since this is for markdown content, not HTML.
6
- * Compiled templates are cached by template string.
7
- */
8
- export function renderTemplate(template, context) {
9
- let compiled = templateCache.get(template);
10
- if (!compiled) {
11
- // Safe: templates render markdown/plaintext, not HTML. No XSS risk.
12
- // eslint-disable-next-line sonarjs/disabled-auto-escaping
13
- compiled = Handlebars.compile(template, { noEscape: true });
14
- templateCache.set(template, compiled);
15
- }
16
- return compiled(context);
17
- }
18
- //# sourceMappingURL=template.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AAEpC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAsC,CAAC;AAEpE;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,OAAgC;IAC/E,IAAI,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,oEAAoE;QACpE,0DAA0D;QAC1D,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC"}