@alpacakit/channels 0.1.0-beta.19
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/LICENSE +21 -0
- package/README.md +772 -0
- package/dist/binding-compiler.d.ts +29 -0
- package/dist/binding-compiler.d.ts.map +1 -0
- package/dist/binding-compiler.js +40 -0
- package/dist/cli-coercion.d.ts +5 -0
- package/dist/cli-coercion.d.ts.map +1 -0
- package/dist/cli-coercion.js +51 -0
- package/dist/cli-compiler.d.ts +46 -0
- package/dist/cli-compiler.d.ts.map +1 -0
- package/dist/cli-compiler.js +213 -0
- package/dist/cli-executor.d.ts +25 -0
- package/dist/cli-executor.d.ts.map +1 -0
- package/dist/cli-executor.js +44 -0
- package/dist/cli-help-projection.d.ts +13 -0
- package/dist/cli-help-projection.d.ts.map +1 -0
- package/dist/cli-help-projection.js +159 -0
- package/dist/cli-model.d.ts +240 -0
- package/dist/cli-model.d.ts.map +1 -0
- package/dist/cli-model.js +89 -0
- package/dist/cli-presentation.d.ts +23 -0
- package/dist/cli-presentation.d.ts.map +1 -0
- package/dist/cli-presentation.js +265 -0
- package/dist/cli-schema.d.ts +4 -0
- package/dist/cli-schema.d.ts.map +1 -0
- package/dist/cli-schema.js +7 -0
- package/dist/cli-tree.d.ts +4 -0
- package/dist/cli-tree.d.ts.map +1 -0
- package/dist/cli-tree.js +421 -0
- package/dist/cli-values.d.ts +24 -0
- package/dist/cli-values.d.ts.map +1 -0
- package/dist/cli-values.js +40 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +5 -0
- package/dist/codecs.d.ts +25 -0
- package/dist/codecs.d.ts.map +1 -0
- package/dist/codecs.js +74 -0
- package/dist/contract.d.ts +12 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +28 -0
- package/dist/factory.d.ts +16 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +188 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/internal.d.ts +3 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +3 -0
- package/dist/introspection.d.ts +40 -0
- package/dist/introspection.d.ts.map +1 -0
- package/dist/introspection.js +56 -0
- package/dist/mcp.d.ts +26 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +84 -0
- package/dist/model.d.ts +166 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +22 -0
- package/dist/runtime.d.ts +47 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +140 -0
- package/dist/schema.d.ts +14 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +70 -0
- package/dist/tree-internal.d.ts +14 -0
- package/dist/tree-internal.d.ts.map +1 -0
- package/dist/tree-internal.js +20 -0
- package/dist/values.d.ts +32 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +30 -0
- package/package.json +47 -0
package/dist/model.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PARAMETER_REQUIREMENT_KIND, } from "./values.js";
|
|
2
|
+
export function defineParameter(parameter) {
|
|
3
|
+
return parameter;
|
|
4
|
+
}
|
|
5
|
+
export function defineEntry(entry) {
|
|
6
|
+
if (entry.output === undefined) {
|
|
7
|
+
return { ...entry, output: null };
|
|
8
|
+
}
|
|
9
|
+
return { ...entry, output: entry.output };
|
|
10
|
+
}
|
|
11
|
+
export function required() {
|
|
12
|
+
return { kind: PARAMETER_REQUIREMENT_KIND.required };
|
|
13
|
+
}
|
|
14
|
+
export function optional(input) {
|
|
15
|
+
if (input === undefined) {
|
|
16
|
+
return { kind: PARAMETER_REQUIREMENT_KIND.optional };
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
kind: PARAMETER_REQUIREMENT_KIND.optionalWithDefault,
|
|
20
|
+
defaultValue: input.default,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ErasedEntryDefinition, ErasedParameterDefinition, ParameterSet, ParameterValues, RawValueMap } from "./model.js";
|
|
2
|
+
import { ENTRY_DECODE_RESULT_KIND, ENTRY_INPUT_TARGET_KIND } from "./values.js";
|
|
3
|
+
export type EntryInputTarget = {
|
|
4
|
+
readonly kind: typeof ENTRY_INPUT_TARGET_KIND.entry;
|
|
5
|
+
} | {
|
|
6
|
+
readonly kind: typeof ENTRY_INPUT_TARGET_KIND.parameter;
|
|
7
|
+
readonly parameterName: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class EntryInputError extends Error {
|
|
10
|
+
readonly issues: readonly string[];
|
|
11
|
+
readonly target: EntryInputTarget;
|
|
12
|
+
constructor(issues: readonly string[], target?: EntryInputTarget);
|
|
13
|
+
}
|
|
14
|
+
export type EntryDecodeResult<Projection> = {
|
|
15
|
+
readonly kind: typeof ENTRY_DECODE_RESULT_KIND.resolved;
|
|
16
|
+
readonly projection: Projection;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: typeof ENTRY_DECODE_RESULT_KIND.invalidInput;
|
|
19
|
+
readonly issues: readonly string[];
|
|
20
|
+
} | InvalidParameterDecodeResult | {
|
|
21
|
+
readonly kind: typeof ENTRY_DECODE_RESULT_KIND.internalError;
|
|
22
|
+
readonly error: unknown;
|
|
23
|
+
};
|
|
24
|
+
type InvalidParameterDecodeResult = {
|
|
25
|
+
readonly kind: typeof ENTRY_DECODE_RESULT_KIND.invalidParameter;
|
|
26
|
+
readonly parameterName: string;
|
|
27
|
+
readonly issues: readonly string[];
|
|
28
|
+
};
|
|
29
|
+
export type ParameterDecodeResult<Parameters extends ParameterSet> = {
|
|
30
|
+
readonly kind: typeof ENTRY_DECODE_RESULT_KIND.resolved;
|
|
31
|
+
readonly values: ParameterValues<Parameters>;
|
|
32
|
+
} | InvalidParameterDecodeResult;
|
|
33
|
+
export type RawValueCoercer = (parameter: ErasedParameterDefinition, rawValue: unknown) => unknown;
|
|
34
|
+
export declare function decodeParameterValues<const Parameters extends ParameterSet>(input: {
|
|
35
|
+
readonly parameters: Parameters;
|
|
36
|
+
readonly parameterNames: readonly string[];
|
|
37
|
+
readonly raw: RawValueMap;
|
|
38
|
+
readonly coerce?: RawValueCoercer;
|
|
39
|
+
}): ParameterDecodeResult<Parameters>;
|
|
40
|
+
export declare function decodeEntryInput<const Entry extends ErasedEntryDefinition>(input: {
|
|
41
|
+
readonly entry: Entry;
|
|
42
|
+
readonly parameterNames: readonly string[];
|
|
43
|
+
readonly raw: RawValueMap;
|
|
44
|
+
readonly coerce?: RawValueCoercer;
|
|
45
|
+
}): EntryDecodeResult<ReturnType<Entry["project"]>>;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,qBAAqB,EACrB,yBAAyB,EACzB,YAAY,EACZ,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EAExB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,uBAAuB,CAAC,KAAK,CAAA;CAAE,GACvD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,uBAAuB,CAAC,SAAS,CAAC;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC,CAAC;AAMN,qBAAa,eAAgB,SAAQ,KAAK;IAEtC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE;IAClC,QAAQ,CAAC,MAAM,EAAE,gBAAgB;gBADxB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,MAAM,GAAE,gBAAqC;CAKzD;AAED,MAAM,MAAM,iBAAiB,CAAC,UAAU,IACpC;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,wBAAwB,CAAC,QAAQ,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,wBAAwB,CAAC,YAAY,CAAC;IAC5D,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,GACD,4BAA4B,GAC5B;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,wBAAwB,CAAC,aAAa,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;AAEN,KAAK,4BAA4B,GAAG;IAClC,QAAQ,CAAC,IAAI,EAAE,OAAO,wBAAwB,CAAC,gBAAgB,CAAC;IAChE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,UAAU,SAAS,YAAY,IAC7D;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,wBAAwB,CAAC,QAAQ,CAAC;IACxD,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;CAC9C,GACD,4BAA4B,CAAC;AAEjC,MAAM,MAAM,eAAe,GAAG,CAC5B,SAAS,EAAE,yBAAyB,EACpC,QAAQ,EAAE,OAAO,KACd,OAAO,CAAC;AAwBb,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,UAAU,SAAS,YAAY,EACrC,KAAK,EAAE;IACP,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;CACnC,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAgDpC;AAyBD,wBAAgB,gBAAgB,CAC9B,KAAK,CAAC,KAAK,SAAS,qBAAqB,EACzC,KAAK,EAAE;IACP,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;CACnC,GAAG,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CA8ClD"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { CODEC_DECODE_RESULT_KIND } from "@alpacakit/core";
|
|
2
|
+
import { findParameter } from "./internal.js";
|
|
3
|
+
import { ENTRY_DECODE_RESULT_KIND, ENTRY_INPUT_TARGET_KIND, PARAMETER_REQUIREMENT_KIND, } from "./values.js";
|
|
4
|
+
const ENTRY_INPUT_TARGET = {
|
|
5
|
+
kind: ENTRY_INPUT_TARGET_KIND.entry,
|
|
6
|
+
};
|
|
7
|
+
export class EntryInputError extends Error {
|
|
8
|
+
issues;
|
|
9
|
+
target;
|
|
10
|
+
constructor(issues, target = ENTRY_INPUT_TARGET) {
|
|
11
|
+
super(issues.join("; "));
|
|
12
|
+
this.issues = issues;
|
|
13
|
+
this.target = target;
|
|
14
|
+
this.name = EntryInputError.name;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const PARAMETER_CANDIDATE_KIND = {
|
|
18
|
+
omitted: "omitted",
|
|
19
|
+
raw: "raw",
|
|
20
|
+
default: "default",
|
|
21
|
+
invalid: "invalid",
|
|
22
|
+
};
|
|
23
|
+
export function decodeParameterValues(input) {
|
|
24
|
+
const output = new Map();
|
|
25
|
+
const boundParameterNames = new Set(input.parameterNames);
|
|
26
|
+
for (const parameterName of input.parameterNames) {
|
|
27
|
+
const parameter = findParameter(input.parameters, parameterName);
|
|
28
|
+
if (parameter === null) {
|
|
29
|
+
return invalidParameter(parameterName, [
|
|
30
|
+
`Unknown parameter binding: ${parameterName}`,
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const parameter of input.parameters) {
|
|
35
|
+
const candidate = resolveParameterCandidate(parameter, boundParameterNames.has(parameter.name)
|
|
36
|
+
? input.raw[parameter.name]
|
|
37
|
+
: undefined);
|
|
38
|
+
if (candidate.kind === PARAMETER_CANDIDATE_KIND.omitted) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (candidate.kind === PARAMETER_CANDIDATE_KIND.invalid) {
|
|
42
|
+
return invalidParameter(parameter.name, candidate.issues);
|
|
43
|
+
}
|
|
44
|
+
let value;
|
|
45
|
+
try {
|
|
46
|
+
value =
|
|
47
|
+
candidate.kind === PARAMETER_CANDIDATE_KIND.raw && input.coerce
|
|
48
|
+
? input.coerce(parameter, candidate.value)
|
|
49
|
+
: candidate.value;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return invalidParameter(parameter.name, [errorMessage(error)]);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const decoded = parameter.codec.decode(value);
|
|
56
|
+
if (decoded.kind === CODEC_DECODE_RESULT_KIND.invalid) {
|
|
57
|
+
return invalidParameter(parameter.name, decoded.issues);
|
|
58
|
+
}
|
|
59
|
+
output.set(parameter.name, decoded.value);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return invalidParameter(parameter.name, [errorMessage(error)]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
kind: ENTRY_DECODE_RESULT_KIND.resolved,
|
|
67
|
+
values: Object.fromEntries(output),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function resolveParameterCandidate(parameter, rawValue) {
|
|
71
|
+
if (rawValue !== undefined) {
|
|
72
|
+
return { kind: PARAMETER_CANDIDATE_KIND.raw, value: rawValue };
|
|
73
|
+
}
|
|
74
|
+
switch (parameter.requirement.kind) {
|
|
75
|
+
case PARAMETER_REQUIREMENT_KIND.required:
|
|
76
|
+
return {
|
|
77
|
+
kind: PARAMETER_CANDIDATE_KIND.invalid,
|
|
78
|
+
issues: [`Missing required parameter ${parameter.name}`],
|
|
79
|
+
};
|
|
80
|
+
case PARAMETER_REQUIREMENT_KIND.optional:
|
|
81
|
+
return { kind: PARAMETER_CANDIDATE_KIND.omitted };
|
|
82
|
+
case PARAMETER_REQUIREMENT_KIND.optionalWithDefault:
|
|
83
|
+
return {
|
|
84
|
+
kind: PARAMETER_CANDIDATE_KIND.default,
|
|
85
|
+
value: parameter.requirement.defaultValue,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export function decodeEntryInput(input) {
|
|
90
|
+
const decoded = decodeParameterValues({
|
|
91
|
+
parameters: input.entry.parameters,
|
|
92
|
+
parameterNames: input.parameterNames,
|
|
93
|
+
raw: input.raw,
|
|
94
|
+
...(input.coerce ? { coerce: input.coerce } : {}),
|
|
95
|
+
});
|
|
96
|
+
if (decoded.kind === ENTRY_DECODE_RESULT_KIND.invalidParameter) {
|
|
97
|
+
return decoded;
|
|
98
|
+
}
|
|
99
|
+
const project = input.entry.project;
|
|
100
|
+
try {
|
|
101
|
+
return {
|
|
102
|
+
kind: ENTRY_DECODE_RESULT_KIND.resolved,
|
|
103
|
+
projection: project({
|
|
104
|
+
values: decoded.values,
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (error instanceof EntryInputError) {
|
|
110
|
+
const target = error.target;
|
|
111
|
+
switch (target.kind) {
|
|
112
|
+
case ENTRY_INPUT_TARGET_KIND.entry:
|
|
113
|
+
return {
|
|
114
|
+
kind: ENTRY_DECODE_RESULT_KIND.invalidInput,
|
|
115
|
+
issues: error.issues,
|
|
116
|
+
};
|
|
117
|
+
case ENTRY_INPUT_TARGET_KIND.parameter:
|
|
118
|
+
if (!input.entry.parameters.some((parameter) => parameter.name === target.parameterName)) {
|
|
119
|
+
return { kind: ENTRY_DECODE_RESULT_KIND.internalError, error };
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
kind: ENTRY_DECODE_RESULT_KIND.invalidParameter,
|
|
123
|
+
parameterName: target.parameterName,
|
|
124
|
+
issues: error.issues,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { kind: ENTRY_DECODE_RESULT_KIND.internalError, error };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function invalidParameter(parameterName, issues) {
|
|
132
|
+
return {
|
|
133
|
+
kind: ENTRY_DECODE_RESULT_KIND.invalidParameter,
|
|
134
|
+
parameterName,
|
|
135
|
+
issues,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function errorMessage(error) {
|
|
139
|
+
return error instanceof Error ? error.message : String(error);
|
|
140
|
+
}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EntryChannelBinding, EntryTreeDefinition, EntryTreeEndpoint, EntryTreeNode } from "./model.js";
|
|
2
|
+
export declare class EntryTreeDefinitionError extends Error {
|
|
3
|
+
readonly issues: readonly string[];
|
|
4
|
+
constructor(issues: readonly string[]);
|
|
5
|
+
}
|
|
6
|
+
export interface EntryTreeVisitor {
|
|
7
|
+
visitNode(node: EntryTreeNode, path: readonly string[]): void;
|
|
8
|
+
visitEndpoint(endpoint: EntryTreeEndpoint, node: EntryTreeNode, path: readonly string[]): void;
|
|
9
|
+
}
|
|
10
|
+
export declare function visitEntryTree(tree: EntryTreeDefinition, visitor: EntryTreeVisitor): void;
|
|
11
|
+
export declare function validateEntryTreeStructure(tree: EntryTreeDefinition): readonly string[];
|
|
12
|
+
export declare function findChannelBinding(endpoint: EntryTreeEndpoint, channel: EntryChannelBinding["channel"]): EntryChannelBinding | null;
|
|
13
|
+
export declare function formatTreePath(path: readonly string[]): string;
|
|
14
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,qBAAa,wBAAyB,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE;gBAAzB,MAAM,EAAE,SAAS,MAAM,EAAE;CAI/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAC9D,aAAa,CACX,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,IAAI,CAAC;CACT;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAsBN;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,mBAAmB,GACxB,SAAS,MAAM,EAAE,CAyCnB;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,mBAAmB,CAAC,SAAS,CAAC,GACtC,mBAAmB,GAAG,IAAI,CAI5B;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE9D"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export class EntryTreeDefinitionError extends Error {
|
|
2
|
+
issues;
|
|
3
|
+
constructor(issues) {
|
|
4
|
+
super(`Invalid entry tree definition:\n${issues.join("\n")}`);
|
|
5
|
+
this.issues = issues;
|
|
6
|
+
this.name = EntryTreeDefinitionError.name;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function visitEntryTree(tree, visitor) {
|
|
10
|
+
const stack = [{ node: tree.root, path: [] }];
|
|
11
|
+
while (stack.length > 0) {
|
|
12
|
+
const current = stack.pop();
|
|
13
|
+
if (!current) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const path = [...current.path, current.node.name];
|
|
17
|
+
visitor.visitNode(current.node, path);
|
|
18
|
+
for (const endpoint of current.node.endpoints) {
|
|
19
|
+
visitor.visitEndpoint(endpoint, current.node, path);
|
|
20
|
+
}
|
|
21
|
+
for (let index = current.node.children.length - 1; index >= 0; index -= 1) {
|
|
22
|
+
const child = current.node.children[index];
|
|
23
|
+
if (child) {
|
|
24
|
+
stack.push({ node: child, path });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function validateEntryTreeStructure(tree) {
|
|
30
|
+
const issues = [];
|
|
31
|
+
visitEntryTree(tree, {
|
|
32
|
+
visitNode(node, path) {
|
|
33
|
+
const location = formatTreePath(path);
|
|
34
|
+
if (node.name.length === 0) {
|
|
35
|
+
issues.push(`${location}: node name must not be empty`);
|
|
36
|
+
}
|
|
37
|
+
const childNames = new Set();
|
|
38
|
+
for (const child of node.children) {
|
|
39
|
+
if (childNames.has(child.name)) {
|
|
40
|
+
issues.push(`${location}: duplicate child name ${JSON.stringify(child.name)}`);
|
|
41
|
+
}
|
|
42
|
+
childNames.add(child.name);
|
|
43
|
+
}
|
|
44
|
+
const overrideChannels = new Set();
|
|
45
|
+
for (const override of node.segments) {
|
|
46
|
+
if (overrideChannels.has(override.channel)) {
|
|
47
|
+
issues.push(`${location}: duplicate ${override.channel} segment override`);
|
|
48
|
+
}
|
|
49
|
+
overrideChannels.add(override.channel);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
visitEndpoint(endpoint, _node, path) {
|
|
53
|
+
const location = `${formatTreePath(path)}#${endpoint.entry.name}`;
|
|
54
|
+
const channels = new Set();
|
|
55
|
+
for (const channelBinding of endpoint.channels) {
|
|
56
|
+
if (channels.has(channelBinding.channel)) {
|
|
57
|
+
issues.push(`${location}: duplicate ${channelBinding.channel} channel binding`);
|
|
58
|
+
}
|
|
59
|
+
channels.add(channelBinding.channel);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
return issues;
|
|
64
|
+
}
|
|
65
|
+
export function findChannelBinding(endpoint, channel) {
|
|
66
|
+
return (endpoint.channels.find((candidate) => candidate.channel === channel) ?? null);
|
|
67
|
+
}
|
|
68
|
+
export function formatTreePath(path) {
|
|
69
|
+
return path.map((segment) => segment || "<empty>").join("/");
|
|
70
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ChannelSegmentOverride, EntryChannelBinding } from "./model.js";
|
|
2
|
+
import type { Channel } from "./values.js";
|
|
3
|
+
export declare const PAYLOAD_KIND: {
|
|
4
|
+
readonly cliBinding: "cli_binding";
|
|
5
|
+
readonly cliSegment: "cli_segment";
|
|
6
|
+
readonly mcpBinding: "mcp_binding";
|
|
7
|
+
};
|
|
8
|
+
type PayloadKind = (typeof PAYLOAD_KIND)[keyof typeof PAYLOAD_KIND];
|
|
9
|
+
export declare function registerChannelPayload(kind: PayloadKind, payload: object): void;
|
|
10
|
+
export declare function isChannelPayload(kind: PayloadKind, value: unknown): boolean;
|
|
11
|
+
export declare function createChannelSegmentOverride(channel: Channel, segment: unknown): ChannelSegmentOverride;
|
|
12
|
+
export declare function createEntryChannelBinding<const ChannelName extends Channel, const ParameterName extends string>(channel: ChannelName, binding: unknown): EntryChannelBinding<ChannelName, ParameterName>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=tree-internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-internal.d.ts","sourceRoot":"","sources":["../src/tree-internal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX,KAAK,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAIpE,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,MAAM,GACd,IAAI,CAEN;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAM3E;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GACf,sBAAsB,CAExB;AAED,wBAAgB,yBAAyB,CACvC,KAAK,CAAC,WAAW,SAAS,OAAO,EACjC,KAAK,CAAC,aAAa,SAAS,MAAM,EAElC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,OAAO,GACf,mBAAmB,CAAC,WAAW,EAAE,aAAa,CAAC,CAKjD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const PAYLOAD_KIND = {
|
|
2
|
+
cliBinding: "cli_binding",
|
|
3
|
+
cliSegment: "cli_segment",
|
|
4
|
+
mcpBinding: "mcp_binding",
|
|
5
|
+
};
|
|
6
|
+
const REGISTERED_PAYLOADS = new WeakMap();
|
|
7
|
+
export function registerChannelPayload(kind, payload) {
|
|
8
|
+
REGISTERED_PAYLOADS.set(payload, kind);
|
|
9
|
+
}
|
|
10
|
+
export function isChannelPayload(kind, value) {
|
|
11
|
+
return (typeof value === "object" &&
|
|
12
|
+
value !== null &&
|
|
13
|
+
REGISTERED_PAYLOADS.get(value) === kind);
|
|
14
|
+
}
|
|
15
|
+
export function createChannelSegmentOverride(channel, segment) {
|
|
16
|
+
return { channel, segment };
|
|
17
|
+
}
|
|
18
|
+
export function createEntryChannelBinding(channel, binding) {
|
|
19
|
+
return { channel, binding };
|
|
20
|
+
}
|
package/dist/values.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const CHANNEL: {
|
|
2
|
+
readonly cli: "cli";
|
|
3
|
+
readonly mcp: "mcp";
|
|
4
|
+
};
|
|
5
|
+
export type Channel = (typeof CHANNEL)[keyof typeof CHANNEL];
|
|
6
|
+
export declare const PARAMETER_REQUIREMENT_KIND: {
|
|
7
|
+
readonly required: "required";
|
|
8
|
+
readonly optional: "optional";
|
|
9
|
+
readonly optionalWithDefault: "optional_with_default";
|
|
10
|
+
};
|
|
11
|
+
export declare const VALUE_SHAPE_KIND: {
|
|
12
|
+
readonly string: "string";
|
|
13
|
+
readonly boolean: "boolean";
|
|
14
|
+
readonly positiveInteger: "positive_integer";
|
|
15
|
+
readonly stringEnum: "string_enum";
|
|
16
|
+
readonly array: "array";
|
|
17
|
+
};
|
|
18
|
+
export declare const ENTRY_DECODE_RESULT_KIND: {
|
|
19
|
+
readonly resolved: "resolved";
|
|
20
|
+
readonly invalidInput: "invalid_input";
|
|
21
|
+
readonly invalidParameter: "invalid_parameter";
|
|
22
|
+
readonly internalError: "internal_error";
|
|
23
|
+
};
|
|
24
|
+
export declare const ENTRY_INPUT_TARGET_KIND: {
|
|
25
|
+
readonly entry: "entry";
|
|
26
|
+
readonly parameter: "parameter";
|
|
27
|
+
};
|
|
28
|
+
export declare const ENTRY_OUTPUT_DESCRIPTION_KIND: {
|
|
29
|
+
readonly typed: "typed";
|
|
30
|
+
readonly none: "none";
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../src/values.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO;;;CAGV,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE7D,eAAO,MAAM,0BAA0B;;;;CAI7B,CAAC;AAEX,eAAO,MAAM,gBAAgB;;;;;;CAMnB,CAAC;AAEX,eAAO,MAAM,wBAAwB;;;;;CAK3B,CAAC;AAEX,eAAO,MAAM,uBAAuB;;;CAG1B,CAAC;AAEX,eAAO,MAAM,6BAA6B;;;CAGhC,CAAC"}
|
package/dist/values.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const CHANNEL = {
|
|
2
|
+
cli: "cli",
|
|
3
|
+
mcp: "mcp",
|
|
4
|
+
};
|
|
5
|
+
export const PARAMETER_REQUIREMENT_KIND = {
|
|
6
|
+
required: "required",
|
|
7
|
+
optional: "optional",
|
|
8
|
+
optionalWithDefault: "optional_with_default",
|
|
9
|
+
};
|
|
10
|
+
export const VALUE_SHAPE_KIND = {
|
|
11
|
+
string: "string",
|
|
12
|
+
boolean: "boolean",
|
|
13
|
+
positiveInteger: "positive_integer",
|
|
14
|
+
stringEnum: "string_enum",
|
|
15
|
+
array: "array",
|
|
16
|
+
};
|
|
17
|
+
export const ENTRY_DECODE_RESULT_KIND = {
|
|
18
|
+
resolved: "resolved",
|
|
19
|
+
invalidInput: "invalid_input",
|
|
20
|
+
invalidParameter: "invalid_parameter",
|
|
21
|
+
internalError: "internal_error",
|
|
22
|
+
};
|
|
23
|
+
export const ENTRY_INPUT_TARGET_KIND = {
|
|
24
|
+
entry: "entry",
|
|
25
|
+
parameter: "parameter",
|
|
26
|
+
};
|
|
27
|
+
export const ENTRY_OUTPUT_DESCRIPTION_KIND = {
|
|
28
|
+
typed: "typed",
|
|
29
|
+
none: "none",
|
|
30
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alpacakit/channels",
|
|
3
|
+
"version": "0.1.0-beta.19",
|
|
4
|
+
"description": "Neutral multi-channel entry definitions with CLI and MCP binding adapters.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public",
|
|
8
|
+
"registry": "https://registry.npmjs.org/"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./cli": {
|
|
17
|
+
"types": "./dist/cli.d.ts",
|
|
18
|
+
"import": "./dist/cli.js"
|
|
19
|
+
},
|
|
20
|
+
"./mcp": {
|
|
21
|
+
"types": "./dist/mcp.d.ts",
|
|
22
|
+
"import": "./dist/mcp.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README*.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@alpacakit/core": "0.1.0-beta.19"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"zod": "^4.3.6"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.9.3",
|
|
39
|
+
"vitest": "^4.0.18",
|
|
40
|
+
"zod": "4.3.6"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc -p tsconfig.build.json",
|
|
44
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
45
|
+
"test": "vitest run"
|
|
46
|
+
}
|
|
47
|
+
}
|