create-relkit 0.0.0
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 +5 -0
- package/dist/generate-files.d.ts +16 -0
- package/dist/generate-files.d.ts.map +1 -0
- package/dist/generate-files.js +108 -0
- package/dist/generate-files.js.map +1 -0
- package/dist/generate-output.d.ts +20 -0
- package/dist/generate-output.d.ts.map +1 -0
- package/dist/generate-output.js +67 -0
- package/dist/generate-output.js.map +1 -0
- package/dist/generate-process.d.ts +9 -0
- package/dist/generate-process.d.ts.map +1 -0
- package/dist/generate-process.js +76 -0
- package/dist/generate-process.js.map +1 -0
- package/dist/generate.d.ts +42 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +103 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/options.d.ts +38 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +113 -0
- package/dist/options.js.map +1 -0
- package/dist/templates/default/README.md +13 -0
- package/dist/templates/default/v1/agent/.env.example +3 -0
- package/dist/templates/default/v1/agent/README.md +23 -0
- package/dist/templates/default/v1/agent/gitignore +10 -0
- package/dist/templates/default/v1/agent/package.json +29 -0
- package/dist/templates/default/v1/agent/relkit.config.ts +23 -0
- package/dist/templates/default/v1/agent/src/agents/assistant.agent.ts +13 -0
- package/dist/templates/default/v1/agent/src/env.ts +7 -0
- package/dist/templates/default/v1/agent/src/functions/hello.function.ts +21 -0
- package/dist/templates/default/v1/agent/src/routes/hello/route.ts +7 -0
- package/dist/templates/default/v1/agent/tests/integration/hello.route.test.ts +13 -0
- package/dist/templates/default/v1/agent/tests/unit/assistant.agent.test.ts +29 -0
- package/dist/templates/default/v1/agent/tests/unit/hello.function.test.ts +9 -0
- package/dist/templates/default/v1/agent/tsconfig.json +23 -0
- package/dist/templates/default/v1/api/.env.example +4 -0
- package/dist/templates/default/v1/api/README.md +25 -0
- package/dist/templates/default/v1/api/gitignore +10 -0
- package/dist/templates/default/v1/api/package.json +30 -0
- package/dist/templates/default/v1/api/relkit.config.ts +19 -0
- package/dist/templates/default/v1/api/src/env.ts +8 -0
- package/dist/templates/default/v1/api/src/events/order-audit.event.ts +15 -0
- package/dist/templates/default/v1/api/src/events/order-confirmation.event.ts +11 -0
- package/dist/templates/default/v1/api/src/events/order-created.event.ts +15 -0
- package/dist/templates/default/v1/api/src/functions/echo.function.ts +10 -0
- package/dist/templates/default/v1/api/src/functions/hello.function.ts +13 -0
- package/dist/templates/default/v1/api/src/functions/orders/create-order.function.ts +29 -0
- package/dist/templates/default/v1/api/src/functions/orders/price-order.function.ts +10 -0
- package/dist/templates/default/v1/api/src/routes/echo/route.ts +6 -0
- package/dist/templates/default/v1/api/src/routes/hello/route.ts +6 -0
- package/dist/templates/default/v1/api/src/routes/orders/route.ts +9 -0
- package/dist/templates/default/v1/api/src/services/orders.service.ts +7 -0
- package/dist/templates/default/v1/api/tests/integration/echo.route.test.ts +17 -0
- package/dist/templates/default/v1/api/tests/integration/hello.route.test.ts +13 -0
- package/dist/templates/default/v1/api/tests/integration/order-events.test.ts +71 -0
- package/dist/templates/default/v1/api/tests/integration/orders.route.test.ts +24 -0
- package/dist/templates/default/v1/api/tests/unit/echo.function.test.ts +9 -0
- package/dist/templates/default/v1/api/tests/unit/hello.function.test.ts +9 -0
- package/dist/templates/default/v1/api/tests/unit/orders.function.test.ts +26 -0
- package/dist/templates/default/v1/api/tsconfig.json +23 -0
- package/dist/templates/default/v1/minimal/.env.example +1 -0
- package/dist/templates/default/v1/minimal/README.md +19 -0
- package/dist/templates/default/v1/minimal/gitignore +10 -0
- package/dist/templates/default/v1/minimal/package.json +29 -0
- package/dist/templates/default/v1/minimal/relkit.config.ts +10 -0
- package/dist/templates/default/v1/minimal/src/env.ts +5 -0
- package/dist/templates/default/v1/minimal/src/functions/hello.function.ts +14 -0
- package/dist/templates/default/v1/minimal/src/routes/hello/route.ts +7 -0
- package/dist/templates/default/v1/minimal/tests/integration/hello.route.test.ts +13 -0
- package/dist/templates/default/v1/minimal/tests/unit/hello.function.test.ts +9 -0
- package/dist/templates/default/v1/minimal/tsconfig.json +23 -0
- package/dist/validate.d.ts +23 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +156 -0
- package/dist/validate.js.map +1 -0
- package/package.json +39 -0
package/dist/options.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export const CREATE_TEMPLATES = ["minimal", "api", "agent"];
|
|
2
|
+
export const CREATE_CLOUDS = ["aws", "none"];
|
|
3
|
+
export const CREATE_DEPLOYMENTS = ["pulumi", "none"];
|
|
4
|
+
export const CREATE_OPTION_DEFAULTS = Object.freeze({
|
|
5
|
+
template: "minimal",
|
|
6
|
+
cloud: "aws",
|
|
7
|
+
deploy: "pulumi",
|
|
8
|
+
install: true,
|
|
9
|
+
git: true,
|
|
10
|
+
examples: true,
|
|
11
|
+
forceEmptyDirectory: false,
|
|
12
|
+
json: false,
|
|
13
|
+
});
|
|
14
|
+
export class CreateOptionsError extends Error {
|
|
15
|
+
code = "RELKIT_CREATE_USAGE";
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "CreateOptionsError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Parses the non-interactive create flags and applies the v3 defaults. */
|
|
22
|
+
export function normalizeCreateOptions(args, context = {}) {
|
|
23
|
+
let name;
|
|
24
|
+
let directory;
|
|
25
|
+
let template = CREATE_OPTION_DEFAULTS.template;
|
|
26
|
+
let cloud = CREATE_OPTION_DEFAULTS.cloud;
|
|
27
|
+
let deploy = CREATE_OPTION_DEFAULTS.deploy;
|
|
28
|
+
let install = CREATE_OPTION_DEFAULTS.install;
|
|
29
|
+
let git = CREATE_OPTION_DEFAULTS.git;
|
|
30
|
+
let examples = CREATE_OPTION_DEFAULTS.examples;
|
|
31
|
+
let forceEmptyDirectory = CREATE_OPTION_DEFAULTS.forceEmptyDirectory;
|
|
32
|
+
let json = CREATE_OPTION_DEFAULTS.json || context.json === true;
|
|
33
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
34
|
+
const argument = args[index];
|
|
35
|
+
if (argument === "--json")
|
|
36
|
+
json = true;
|
|
37
|
+
else if (argument === "--force-empty-directory")
|
|
38
|
+
forceEmptyDirectory = true;
|
|
39
|
+
else if (argument === "--install")
|
|
40
|
+
install = true;
|
|
41
|
+
else if (argument === "--no-install")
|
|
42
|
+
install = false;
|
|
43
|
+
else if (argument === "--git")
|
|
44
|
+
git = true;
|
|
45
|
+
else if (argument === "--no-git")
|
|
46
|
+
git = false;
|
|
47
|
+
else if (argument === "--examples")
|
|
48
|
+
examples = true;
|
|
49
|
+
else if (argument === "--no-examples")
|
|
50
|
+
examples = false;
|
|
51
|
+
else if (argument === "--template" || argument.startsWith("--template=")) {
|
|
52
|
+
const option = readValue(args, index, argument, "--template");
|
|
53
|
+
index = option.index;
|
|
54
|
+
template = choice(option.value, "--template", CREATE_TEMPLATES);
|
|
55
|
+
}
|
|
56
|
+
else if (argument === "--cloud" || argument.startsWith("--cloud=")) {
|
|
57
|
+
const option = readValue(args, index, argument, "--cloud");
|
|
58
|
+
index = option.index;
|
|
59
|
+
cloud = choice(option.value, "--cloud", CREATE_CLOUDS);
|
|
60
|
+
}
|
|
61
|
+
else if (argument === "--deploy" || argument.startsWith("--deploy=")) {
|
|
62
|
+
const option = readValue(args, index, argument, "--deploy");
|
|
63
|
+
index = option.index;
|
|
64
|
+
deploy = choice(option.value, "--deploy", CREATE_DEPLOYMENTS);
|
|
65
|
+
}
|
|
66
|
+
else if (argument === "--directory" || argument.startsWith("--directory=")) {
|
|
67
|
+
const option = readValue(args, index, argument, "--directory");
|
|
68
|
+
index = option.index;
|
|
69
|
+
directory = option.value;
|
|
70
|
+
}
|
|
71
|
+
else if (argument.startsWith("-")) {
|
|
72
|
+
throw new CreateOptionsError(`Unknown create option: ${argument}`);
|
|
73
|
+
}
|
|
74
|
+
else if (name === undefined)
|
|
75
|
+
name = argument;
|
|
76
|
+
else
|
|
77
|
+
throw new CreateOptionsError("Only one project name is allowed.");
|
|
78
|
+
}
|
|
79
|
+
if (name === undefined)
|
|
80
|
+
throw new CreateOptionsError("Usage: create-relkit <name> [options]");
|
|
81
|
+
return Object.freeze({
|
|
82
|
+
name,
|
|
83
|
+
template,
|
|
84
|
+
cloud,
|
|
85
|
+
deploy,
|
|
86
|
+
install,
|
|
87
|
+
git,
|
|
88
|
+
examples,
|
|
89
|
+
...(directory === undefined ? {} : { directory }),
|
|
90
|
+
forceEmptyDirectory,
|
|
91
|
+
json,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function readValue(args, index, argument, option) {
|
|
95
|
+
const prefix = `${option}=`;
|
|
96
|
+
if (argument.startsWith(prefix)) {
|
|
97
|
+
const value = argument.slice(prefix.length);
|
|
98
|
+
if (value.length > 0)
|
|
99
|
+
return { value, index };
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const value = args[index + 1];
|
|
103
|
+
if (value !== undefined && !value.startsWith("-"))
|
|
104
|
+
return { value, index: index + 1 };
|
|
105
|
+
}
|
|
106
|
+
throw new CreateOptionsError(`${option} requires a value.`);
|
|
107
|
+
}
|
|
108
|
+
function choice(value, option, allowed) {
|
|
109
|
+
if (allowed.includes(value))
|
|
110
|
+
return value;
|
|
111
|
+
throw new CreateOptionsError(`${option} must be one of: ${allowed.join("|")}.`);
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAU,CAAC;AAGrE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,CAAU,CAAC;AAGtD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAU,CAAC;AAG9D,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,QAAQ,EAAE,SAA2B;IACrC,KAAK,EAAE,KAAoB;IAC3B,MAAM,EAAE,QAA4B;IACpC,OAAO,EAAE,IAAe;IACxB,GAAG,EAAE,IAAe;IACpB,QAAQ,EAAE,IAAe;IACzB,mBAAmB,EAAE,KAAgB;IACrC,IAAI,EAAE,KAAgB;CACvB,CAAC,CAAC;AAmBH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,GAAG,qBAA8B,CAAC;IAE/C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,2EAA2E;AAC3E,MAAM,UAAU,sBAAsB,CACpC,IAAuB,EACvB,UAAgC,EAAE;IAElC,IAAI,IAAwB,CAAC;IAC7B,IAAI,SAA6B,CAAC;IAClC,IAAI,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC;IAC/C,IAAI,KAAK,GAAG,sBAAsB,CAAC,KAAK,CAAC;IACzC,IAAI,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC;IAC3C,IAAI,OAAO,GAAG,sBAAsB,CAAC,OAAO,CAAC;IAC7C,IAAI,GAAG,GAAG,sBAAsB,CAAC,GAAG,CAAC;IACrC,IAAI,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC;IAC/C,IAAI,mBAAmB,GAAG,sBAAsB,CAAC,mBAAmB,CAAC;IACrE,IAAI,IAAI,GAAG,sBAAsB,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC;IAEhE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAE,CAAC;QAC9B,IAAI,QAAQ,KAAK,QAAQ;YAAE,IAAI,GAAG,IAAI,CAAC;aAClC,IAAI,QAAQ,KAAK,yBAAyB;YAAE,mBAAmB,GAAG,IAAI,CAAC;aACvE,IAAI,QAAQ,KAAK,WAAW;YAAE,OAAO,GAAG,IAAI,CAAC;aAC7C,IAAI,QAAQ,KAAK,cAAc;YAAE,OAAO,GAAG,KAAK,CAAC;aACjD,IAAI,QAAQ,KAAK,OAAO;YAAE,GAAG,GAAG,IAAI,CAAC;aACrC,IAAI,QAAQ,KAAK,UAAU;YAAE,GAAG,GAAG,KAAK,CAAC;aACzC,IAAI,QAAQ,KAAK,YAAY;YAAE,QAAQ,GAAG,IAAI,CAAC;aAC/C,IAAI,QAAQ,KAAK,eAAe;YAAE,QAAQ,GAAG,KAAK,CAAC;aACnD,IAAI,QAAQ,KAAK,YAAY,IAAI,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACzE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;YAC9D,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YACrB,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC;QAClE,CAAC;aAAM,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACrE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;YAC3D,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YACrB,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;QACzD,CAAC;aAAM,IAAI,QAAQ,KAAK,UAAU,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACvE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC5D,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YACrB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAC;QAChE,CAAC;aAAM,IAAI,QAAQ,KAAK,aAAa,IAAI,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YAC7E,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;YAC/D,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YACrB,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;QAC3B,CAAC;aAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,kBAAkB,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QACrE,CAAC;aAAM,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,GAAG,QAAQ,CAAC;;YAC1C,MAAM,IAAI,kBAAkB,CAAC,mCAAmC,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,IAAI,kBAAkB,CAAC,uCAAuC,CAAC,CAAC;IAC9F,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI;QACJ,QAAQ;QACR,KAAK;QACL,MAAM;QACN,OAAO;QACP,GAAG;QACH,QAAQ;QACR,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;QACjD,mBAAmB;QACnB,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAChB,IAAuB,EACvB,KAAa,EACb,QAAgB,EAChB,MAAc;IAEd,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC;IAC5B,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC;IACxF,CAAC;IACD,MAAM,IAAI,kBAAkB,CAAC,GAAG,MAAM,oBAAoB,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,MAAM,CAAmB,KAAa,EAAE,MAAc,EAAE,OAAqB;IACpF,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAU,CAAC;QAAE,OAAO,KAAU,CAAC;IACpD,MAAM,IAAI,kBAAkB,CAAC,GAAG,MAAM,oBAAoB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Default RelKit templates
|
|
2
|
+
|
|
3
|
+
The `v1` directory contains the bundled project templates used by the
|
|
4
|
+
scaffolder:
|
|
5
|
+
|
|
6
|
+
- `minimal` — one function and a `GET /hello` route;
|
|
7
|
+
- `api` — the minimal example plus a JSON `POST /echo` route;
|
|
8
|
+
- `agent` — the minimal example plus a read-only tool and agent descriptor.
|
|
9
|
+
|
|
10
|
+
Each variant is self-contained and can be copied as a project root. It uses
|
|
11
|
+
the current checked-in RelKit package version (`0.0.0`), Bun `1.3.10`, and
|
|
12
|
+
TypeScript `5.9.2`. The generator owns project-name substitution and later
|
|
13
|
+
installation/Git behavior.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# my-app
|
|
2
|
+
|
|
3
|
+
A RelKit TypeScript/Bun project with the minimal HTTP example and a bounded
|
|
4
|
+
agent backed by a function-derived read-only tool. Tests use deterministic AI
|
|
5
|
+
SDK test models, while production uses the configured AWS provider set.
|
|
6
|
+
|
|
7
|
+
The agent may omit `model` to use the configured `defaultProvider` and
|
|
8
|
+
`defaultModel`; production keeps OpenAI and Anthropic credentials as
|
|
9
|
+
environment references in `modelProviders`.
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
bun install
|
|
15
|
+
bun run dev
|
|
16
|
+
bun run test
|
|
17
|
+
bun run check
|
|
18
|
+
bun run typecheck
|
|
19
|
+
bun run build
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The example route is `GET /hello?name=RelKit`. Agent prompt and result content
|
|
23
|
+
are not captured by default.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"packageManager": "bun@1.3.10",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "relkit dev",
|
|
8
|
+
"check": "relkit check",
|
|
9
|
+
"typecheck": "tsc --noEmit",
|
|
10
|
+
"test": "bun test",
|
|
11
|
+
"test:unit": "bun test tests/unit",
|
|
12
|
+
"test:integration": "bun test tests/integration",
|
|
13
|
+
"build": "relkit build",
|
|
14
|
+
"start": "relkit start",
|
|
15
|
+
"graph": "relkit graph print",
|
|
16
|
+
"deploy:preview": "relkit deploy preview",
|
|
17
|
+
"deploy": "relkit deploy up"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@relkit/app": "0.0.0",
|
|
21
|
+
"@relkit/providers-standard": "0.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/bun": "1.3.10",
|
|
25
|
+
"@relkit/cli": "0.0.0",
|
|
26
|
+
"@relkit/testing": "0.0.0",
|
|
27
|
+
"typescript": "5.9.2"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { aiSdk, defineConfig, external } from "@relkit/app/config";
|
|
2
|
+
import env from "@app/env.js";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
env,
|
|
6
|
+
models: {
|
|
7
|
+
default: external(
|
|
8
|
+
aiSdk({
|
|
9
|
+
defaultProvider: "openai",
|
|
10
|
+
defaultModel: "gpt-5-mini",
|
|
11
|
+
openai: { apiKey: env.OPENAI_API_KEY },
|
|
12
|
+
anthropic: {
|
|
13
|
+
defaultModel: "claude-sonnet-4-5",
|
|
14
|
+
apiKey: env.ANTHROPIC_API_KEY,
|
|
15
|
+
},
|
|
16
|
+
}),
|
|
17
|
+
),
|
|
18
|
+
},
|
|
19
|
+
telemetry: { bodyCapture: { mode: "off" } },
|
|
20
|
+
server: { port: 3000, maxBodyBytes: 1_048_576 },
|
|
21
|
+
inspector: { port: 3210 },
|
|
22
|
+
deployment: { target: "aws", adapter: "pulumi" },
|
|
23
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineAgent } from "@relkit/app/agents";
|
|
2
|
+
import { z } from "@relkit/app/schema";
|
|
3
|
+
import { lookup } from "@app/functions/hello.function.js";
|
|
4
|
+
|
|
5
|
+
export default defineAgent({
|
|
6
|
+
id: "assistant",
|
|
7
|
+
input: z.object({ question: z.string().min(1) }),
|
|
8
|
+
output: z.object({ answer: z.string() }),
|
|
9
|
+
model: "openai:gpt-5-mini",
|
|
10
|
+
instructions: "Answer greeting questions with the read-only lookup tool.",
|
|
11
|
+
tools: [lookup],
|
|
12
|
+
limits: { maxSteps: 4, maxToolCalls: 4, timeoutMs: 10_000 },
|
|
13
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineEnv, env } from "@relkit/app/config";
|
|
2
|
+
|
|
3
|
+
export default defineEnv({
|
|
4
|
+
LOG_LEVEL: env.literal("trace", "debug", "info", "warn", "error").default("info"),
|
|
5
|
+
OPENAI_API_KEY: env.secret().requiredIn("production"),
|
|
6
|
+
ANTHROPIC_API_KEY: env.secret().requiredIn("production"),
|
|
7
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineFunction } from "@relkit/app/functions";
|
|
2
|
+
import { z } from "@relkit/app/schema";
|
|
3
|
+
|
|
4
|
+
const hello = defineFunction({
|
|
5
|
+
id: "hello",
|
|
6
|
+
input: z.object({ name: z.string().min(1).default("world") }),
|
|
7
|
+
output: z.object({ message: z.string() }),
|
|
8
|
+
handler: async ({ name }, context) => {
|
|
9
|
+
context.log.info("hello invoked", { name });
|
|
10
|
+
return { message: `Hello, ${name}!` };
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const lookup = hello.asTool({
|
|
15
|
+
id: "hello.lookup",
|
|
16
|
+
description: "Read a greeting for a supplied name",
|
|
17
|
+
sideEffect: "read",
|
|
18
|
+
approval: "never",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export default hello;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { afterAll, expect, test } from "bun:test";
|
|
2
|
+
import { createTestApplication } from "@relkit/testing";
|
|
3
|
+
import config from "../../relkit.config.js";
|
|
4
|
+
|
|
5
|
+
const testApp = await createTestApplication(config);
|
|
6
|
+
|
|
7
|
+
test("GET /hello", async () => {
|
|
8
|
+
const response = await testApp.http.request("/hello?name=Mustafa");
|
|
9
|
+
expect(response.status).toBe(200);
|
|
10
|
+
expect(await response.json()).toEqual({ message: "Hello, Mustafa!" });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterAll(() => testApp.close());
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { createTestAgent, invokeFunction } from "@relkit/testing";
|
|
3
|
+
import assistant from "@app/agents/assistant.agent.js";
|
|
4
|
+
import hello, { lookup } from "@app/functions/hello.function.js";
|
|
5
|
+
|
|
6
|
+
test("assistant uses a function-derived tool with an offline AI SDK model", async () => {
|
|
7
|
+
expect(assistant.model).toBe("openai:gpt-5-mini");
|
|
8
|
+
expect(assistant.tools.map((tool) => tool.ref.id)).toEqual(["hello.lookup"]);
|
|
9
|
+
expect(assistant.limits).toEqual({ maxSteps: 4, maxToolCalls: 4, timeoutMs: 10_000 });
|
|
10
|
+
|
|
11
|
+
const agent = createTestAgent({
|
|
12
|
+
agent: assistant,
|
|
13
|
+
tools: [lookup],
|
|
14
|
+
engine: {
|
|
15
|
+
invoke: (request) =>
|
|
16
|
+
invokeFunction(hello, request.input as Parameters<typeof hello.invoke>[0]),
|
|
17
|
+
},
|
|
18
|
+
model: { provider: "openai", modelId: "gpt-5-mini" },
|
|
19
|
+
script: [
|
|
20
|
+
{ type: "tool-call", callId: "call-1", toolId: "hello.lookup", input: { name: "Ada" } },
|
|
21
|
+
{ type: "final", output: { answer: "Hello, Ada!" } },
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
await expect(agent.invoke({ question: "greet Ada" })).resolves.toEqual({
|
|
26
|
+
answer: "Hello, Ada!",
|
|
27
|
+
});
|
|
28
|
+
expect(agent.model.calls).toHaveLength(2);
|
|
29
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { invokeFunction } from "@relkit/testing";
|
|
3
|
+
import hello from "@app/functions/hello.function.js";
|
|
4
|
+
|
|
5
|
+
test("hello returns a greeting", async () => {
|
|
6
|
+
await expect(invokeFunction(hello, { name: "Mustafa" })).resolves.toEqual({
|
|
7
|
+
message: "Hello, Mustafa!",
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"baseUrl": ".",
|
|
8
|
+
"paths": { "@app/*": ["src/*"] },
|
|
9
|
+
"lib": ["ES2022"],
|
|
10
|
+
"types": ["bun"],
|
|
11
|
+
"strict": true,
|
|
12
|
+
"noUncheckedIndexedAccess": true,
|
|
13
|
+
"exactOptionalPropertyTypes": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true
|
|
19
|
+
},
|
|
20
|
+
"files": [".relkit/generated/event-registry.d.ts"],
|
|
21
|
+
"include": ["src/**/*.ts", "tests/**/*.ts", "relkit.config.ts"],
|
|
22
|
+
"exclude": ["node_modules", ".relkit"]
|
|
23
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# my-app
|
|
2
|
+
|
|
3
|
+
A RelKit TypeScript/Bun API project with greeting, echo, and order routes.
|
|
4
|
+
Functions own the application handlers; routes describe transport mapping and
|
|
5
|
+
responses. Source-scoped IDs are inferred where safe, the order route targets a
|
|
6
|
+
small service, and nested calls use descriptor `invoke`.
|
|
7
|
+
|
|
8
|
+
## Commands
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
bun install
|
|
12
|
+
bun run dev
|
|
13
|
+
bun run test
|
|
14
|
+
bun run check
|
|
15
|
+
bun run typecheck
|
|
16
|
+
bun run build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The example routes are `GET /hello?name=RelKit`, `POST /echo` with a JSON
|
|
20
|
+
`message` field, and `POST /orders` with `{ orderId, sku, quantity }`.
|
|
21
|
+
|
|
22
|
+
Creating an order publishes `orders.created`. Its confirmation and audit
|
|
23
|
+
listeners are independent durable, at-least-once deliveries: one listener can
|
|
24
|
+
fail without rolling back the other, and delivery is not a transaction or a
|
|
25
|
+
promise of simultaneous execution.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"packageManager": "bun@1.3.10",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "relkit dev",
|
|
8
|
+
"check": "relkit check",
|
|
9
|
+
"typecheck": "tsc --noEmit",
|
|
10
|
+
"test": "bun test",
|
|
11
|
+
"test:unit": "bun test tests/unit",
|
|
12
|
+
"test:integration": "bun test tests/integration",
|
|
13
|
+
"build": "relkit build",
|
|
14
|
+
"start": "relkit start",
|
|
15
|
+
"graph": "relkit graph print",
|
|
16
|
+
"deploy:preview": "relkit deploy preview",
|
|
17
|
+
"deploy": "relkit deploy up"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@relkit/app": "0.0.0",
|
|
21
|
+
"@relkit/providers-standard": "0.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/bun": "1.3.10",
|
|
25
|
+
"@relkit/cli": "0.0.0",
|
|
26
|
+
"@relkit/events": "0.0.0",
|
|
27
|
+
"@relkit/testing": "0.0.0",
|
|
28
|
+
"typescript": "5.9.2"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig, eventBridge, managed } from "@relkit/app/config";
|
|
2
|
+
import env from "@app/env.js";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
env,
|
|
6
|
+
events: {
|
|
7
|
+
default: managed(
|
|
8
|
+
eventBridge({
|
|
9
|
+
region: env.EVENT_REGION,
|
|
10
|
+
endpoint: env.EVENT_ENDPOINT,
|
|
11
|
+
busName: env.EVENT_BUS_NAME,
|
|
12
|
+
}),
|
|
13
|
+
),
|
|
14
|
+
},
|
|
15
|
+
telemetry: { bodyCapture: { mode: "off" } },
|
|
16
|
+
server: { port: 3000, maxBodyBytes: 1_048_576 },
|
|
17
|
+
inspector: { port: 3210 },
|
|
18
|
+
deployment: { target: "aws", adapter: "pulumi" },
|
|
19
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { defineEnv, env } from "@relkit/app/config";
|
|
2
|
+
|
|
3
|
+
export default defineEnv({
|
|
4
|
+
LOG_LEVEL: env.literal("trace", "debug", "info", "warn", "error").default("info"),
|
|
5
|
+
EVENT_REGION: env.string().default("us-east-1"),
|
|
6
|
+
EVENT_ENDPOINT: env.url().requiredIn("development", "production"),
|
|
7
|
+
EVENT_BUS_NAME: env.string().requiredIn("development", "production"),
|
|
8
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { onEvent } from "@relkit/app/events";
|
|
2
|
+
|
|
3
|
+
const orderAudit = onEvent(
|
|
4
|
+
"orders.created",
|
|
5
|
+
async (payload, context) => {
|
|
6
|
+
context.log.info("order.audit.recorded", {
|
|
7
|
+
orderId: payload.orderId,
|
|
8
|
+
sku: payload.sku,
|
|
9
|
+
totalCents: payload.totalCents,
|
|
10
|
+
});
|
|
11
|
+
},
|
|
12
|
+
{ id: "orders.audit" },
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export default orderAudit;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { onEvent } from "@relkit/app/events";
|
|
2
|
+
|
|
3
|
+
const orderConfirmation = onEvent(
|
|
4
|
+
"orders.created",
|
|
5
|
+
async (payload, context) => {
|
|
6
|
+
context.log.info("order.confirmation.requested", { orderId: payload.orderId });
|
|
7
|
+
},
|
|
8
|
+
{ id: "orders.confirmation" },
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export default orderConfirmation;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineEvent } from "@relkit/app/events";
|
|
2
|
+
import { z } from "@relkit/app/schema";
|
|
3
|
+
|
|
4
|
+
const orderCreated = defineEvent({
|
|
5
|
+
id: "orders.created",
|
|
6
|
+
version: 1,
|
|
7
|
+
payload: z.object({
|
|
8
|
+
orderId: z.string().min(1),
|
|
9
|
+
sku: z.string().min(1),
|
|
10
|
+
totalCents: z.number().int().nonnegative(),
|
|
11
|
+
}),
|
|
12
|
+
title: "Order created",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default orderCreated;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineFunction } from "@relkit/app/functions";
|
|
2
|
+
import { z } from "@relkit/app/schema";
|
|
3
|
+
|
|
4
|
+
const echo = defineFunction({
|
|
5
|
+
input: z.object({ message: z.string().min(1) }),
|
|
6
|
+
output: z.object({ message: z.string() }),
|
|
7
|
+
handler: async ({ message }) => ({ message }),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default echo;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineFunction } from "@relkit/app/functions";
|
|
2
|
+
import { z } from "@relkit/app/schema";
|
|
3
|
+
|
|
4
|
+
const hello = defineFunction({
|
|
5
|
+
input: z.object({ name: z.string().min(1).default("world") }),
|
|
6
|
+
output: z.object({ message: z.string() }),
|
|
7
|
+
handler: async ({ name }, context) => {
|
|
8
|
+
context.log.info("hello invoked", { name });
|
|
9
|
+
return { message: `Hello, ${name}!` };
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export default hello;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineFunction } from "@relkit/app/functions";
|
|
2
|
+
import { z } from "@relkit/app/schema";
|
|
3
|
+
import orderCreated from "@app/events/order-created.event.js";
|
|
4
|
+
import priceOrder from "@app/functions/orders/price-order.function.js";
|
|
5
|
+
|
|
6
|
+
const orderInput = z.object({
|
|
7
|
+
orderId: z.string().min(1),
|
|
8
|
+
sku: z.string().min(1),
|
|
9
|
+
quantity: z.number().int().positive(),
|
|
10
|
+
});
|
|
11
|
+
const orderOutput = z.object({
|
|
12
|
+
orderId: z.string(),
|
|
13
|
+
sku: z.string(),
|
|
14
|
+
totalCents: z.number().int().nonnegative(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const createOrder = defineFunction({
|
|
18
|
+
input: orderInput,
|
|
19
|
+
output: orderOutput,
|
|
20
|
+
dependencies: { events: { orderCreated } },
|
|
21
|
+
handler: async (input, context) => {
|
|
22
|
+
const { totalCents } = await priceOrder.invoke({ quantity: input.quantity });
|
|
23
|
+
const order = { orderId: input.orderId, sku: input.sku, totalCents };
|
|
24
|
+
await context.events.orderCreated.publish(order);
|
|
25
|
+
return order;
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default createOrder;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineFunction } from "@relkit/app/functions";
|
|
2
|
+
import { z } from "@relkit/app/schema";
|
|
3
|
+
|
|
4
|
+
const priceOrder = defineFunction({
|
|
5
|
+
input: z.object({ quantity: z.number().int().positive() }),
|
|
6
|
+
output: z.object({ totalCents: z.number().int().nonnegative() }),
|
|
7
|
+
handler: ({ quantity }) => ({ totalCents: quantity * 100 }),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default priceOrder;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineRoute } from "@relkit/app/routes";
|
|
2
|
+
import orders from "@app/services/orders.service.js";
|
|
3
|
+
|
|
4
|
+
export const POST = defineRoute({
|
|
5
|
+
// Reuse the checked application function instead of duplicating HTTP logic.
|
|
6
|
+
target: orders.createOrder,
|
|
7
|
+
// Successful creates return the conventional HTTP 201 status.
|
|
8
|
+
successStatus: 201,
|
|
9
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineService } from "@relkit/app/services";
|
|
2
|
+
import createOrder from "@app/functions/orders/create-order.function.js";
|
|
3
|
+
import priceOrder from "@app/functions/orders/price-order.function.js";
|
|
4
|
+
|
|
5
|
+
const orders = defineService({ functions: { createOrder, priceOrder } });
|
|
6
|
+
|
|
7
|
+
export default orders;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { afterAll, expect, test } from "bun:test";
|
|
2
|
+
import { createTestApplication } from "@relkit/testing";
|
|
3
|
+
import config from "../../relkit.config.js";
|
|
4
|
+
|
|
5
|
+
const testApp = await createTestApplication(config);
|
|
6
|
+
|
|
7
|
+
test("POST /echo", async () => {
|
|
8
|
+
const response = await testApp.http.request("/echo", {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: { "content-type": "application/json" },
|
|
11
|
+
body: JSON.stringify({ message: "hello" }),
|
|
12
|
+
});
|
|
13
|
+
expect(response.status).toBe(200);
|
|
14
|
+
expect(await response.json()).toEqual({ message: "hello" });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterAll(() => testApp.close());
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { afterAll, expect, test } from "bun:test";
|
|
2
|
+
import { createTestApplication } from "@relkit/testing";
|
|
3
|
+
import config from "../../relkit.config.js";
|
|
4
|
+
|
|
5
|
+
const testApp = await createTestApplication(config);
|
|
6
|
+
|
|
7
|
+
test("GET /hello", async () => {
|
|
8
|
+
const response = await testApp.http.request("/hello?name=Mustafa");
|
|
9
|
+
expect(response.status).toBe(200);
|
|
10
|
+
expect(await response.json()).toEqual({ message: "Hello, Mustafa!" });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterAll(() => testApp.close());
|