@clawnify/app 0.1.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.
@@ -0,0 +1,58 @@
1
+ import { DiscoveryOptions, OpenAPIHono } from '@clawnify/routes';
2
+ export { DiscoverableApp, DiscoveryOptions, OpenAPIHono, createRoute, describeRoutes, mountDiscovery, z } from '@clawnify/routes';
3
+ import { Env } from 'hono';
4
+
5
+ /**
6
+ * @clawnify/app — the standard Clawnify app skeleton in one call.
7
+ *
8
+ * `createApp(opts)` returns a fully-wired OpenAPIHono with every always-required,
9
+ * cross-cutting concern pre-baked, so an app's server file is just imports +
10
+ * routes + `export default app`:
11
+ *
12
+ * import { createApp, createRoute, z } from "@clawnify/app";
13
+ * const app = createApp<Env>({ title: "CRM App", version: "1.0.0" });
14
+ * app.openapi(listContacts, handler);
15
+ * export default app;
16
+ *
17
+ * What it bakes in — the boilerplate every app used to re-write in its server
18
+ * file, and could forget:
19
+ * • OpenAPIHono construction (typed to your Env).
20
+ * • Database init — `initDB(c.env)` middleware on every request. @clawnify/db
21
+ * auto-detects the D1 binding (production WfP) or the Storage capability
22
+ * binding (Dynamic Workers preview), so handlers can query immediately.
23
+ * • API discovery — `mountDiscovery` serves GET /api/openapi.json (the machine
24
+ * contract) and GET /llms.txt (the lean agent index), generated from the
25
+ * live routes so they can't drift.
26
+ *
27
+ * The point: a new always-required concern is added HERE once and every app
28
+ * inherits it on the next rebuild — instead of a line each agent must remember
29
+ * to write (and a build gate to enforce) in every app.
30
+ */
31
+
32
+ interface CreateAppOptions extends DiscoveryOptions {
33
+ /**
34
+ * Wire the per-request database middleware (`initDB(c.env)` on `*`). Default
35
+ * true — every Clawnify app has a D1 / Storage binding. Set false only for the
36
+ * rare app with no database.
37
+ */
38
+ db?: boolean;
39
+ /**
40
+ * Mount GET /api/openapi.json + GET /llms.txt discovery. Default true. Set
41
+ * false only if the app deliberately opts out of API discovery.
42
+ */
43
+ discovery?: boolean;
44
+ }
45
+ /**
46
+ * Create a fully-wired Clawnify app.
47
+ *
48
+ * `E` is your Hono env — `{ Bindings: { DB: D1Database, ... } }` — pass it so
49
+ * route handlers get a typed `c.env`. Everything after this call is your app's
50
+ * own routes and business logic:
51
+ *
52
+ * const app = createApp<Env>({ title: "CRM App", version: "1.0.0" });
53
+ * app.openapi(route, handler);
54
+ * export default app;
55
+ */
56
+ declare function createApp<E extends Env = Env>(opts?: CreateAppOptions): OpenAPIHono<E>;
57
+
58
+ export { type CreateAppOptions, createApp };
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ // src/index.ts
2
+ import { OpenAPIHono, mountDiscovery } from "@clawnify/routes";
3
+ import { initDB } from "@clawnify/db";
4
+ import {
5
+ OpenAPIHono as OpenAPIHono2,
6
+ createRoute,
7
+ z,
8
+ mountDiscovery as mountDiscovery2,
9
+ describeRoutes
10
+ } from "@clawnify/routes";
11
+ function createApp(opts = {}) {
12
+ const app = new OpenAPIHono();
13
+ if (opts.db !== false) {
14
+ app.use("*", async (c, next) => {
15
+ initDB(c.env);
16
+ await next();
17
+ });
18
+ }
19
+ if (opts.discovery !== false) {
20
+ mountDiscovery(app, opts);
21
+ }
22
+ return app;
23
+ }
24
+ export {
25
+ OpenAPIHono2 as OpenAPIHono,
26
+ createApp,
27
+ createRoute,
28
+ describeRoutes,
29
+ mountDiscovery2 as mountDiscovery,
30
+ z
31
+ };
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @clawnify/app — the standard Clawnify app skeleton in one call.\n *\n * `createApp(opts)` returns a fully-wired OpenAPIHono with every always-required,\n * cross-cutting concern pre-baked, so an app's server file is just imports +\n * routes + `export default app`:\n *\n * import { createApp, createRoute, z } from \"@clawnify/app\";\n * const app = createApp<Env>({ title: \"CRM App\", version: \"1.0.0\" });\n * app.openapi(listContacts, handler);\n * export default app;\n *\n * What it bakes in — the boilerplate every app used to re-write in its server\n * file, and could forget:\n * • OpenAPIHono construction (typed to your Env).\n * • Database init — `initDB(c.env)` middleware on every request. @clawnify/db\n * auto-detects the D1 binding (production WfP) or the Storage capability\n * binding (Dynamic Workers preview), so handlers can query immediately.\n * • API discovery — `mountDiscovery` serves GET /api/openapi.json (the machine\n * contract) and GET /llms.txt (the lean agent index), generated from the\n * live routes so they can't drift.\n *\n * The point: a new always-required concern is added HERE once and every app\n * inherits it on the next rebuild — instead of a line each agent must remember\n * to write (and a build gate to enforce) in every app.\n */\nimport { OpenAPIHono, mountDiscovery, type DiscoveryOptions } from \"@clawnify/routes\";\nimport { initDB } from \"@clawnify/db\";\nimport type { Env } from \"hono\";\n\n// One routing import for app authors: everything needed to declare routes and\n// build the app comes from @clawnify/app. These are re-exports of the same\n// @hono/zod-openapi primitives @clawnify/routes exposes — never reimplemented —\n// so route creation, discovery, and construction all live behind one import.\nexport {\n OpenAPIHono,\n createRoute,\n z,\n mountDiscovery,\n describeRoutes,\n} from \"@clawnify/routes\";\nexport type { DiscoveryOptions, DiscoverableApp } from \"@clawnify/routes\";\n\nexport interface CreateAppOptions extends DiscoveryOptions {\n /**\n * Wire the per-request database middleware (`initDB(c.env)` on `*`). Default\n * true — every Clawnify app has a D1 / Storage binding. Set false only for the\n * rare app with no database.\n */\n db?: boolean;\n /**\n * Mount GET /api/openapi.json + GET /llms.txt discovery. Default true. Set\n * false only if the app deliberately opts out of API discovery.\n */\n discovery?: boolean;\n}\n\n/**\n * Create a fully-wired Clawnify app.\n *\n * `E` is your Hono env — `{ Bindings: { DB: D1Database, ... } }` — pass it so\n * route handlers get a typed `c.env`. Everything after this call is your app's\n * own routes and business logic:\n *\n * const app = createApp<Env>({ title: \"CRM App\", version: \"1.0.0\" });\n * app.openapi(route, handler);\n * export default app;\n */\nexport function createApp<E extends Env = Env>(\n opts: CreateAppOptions = {},\n): OpenAPIHono<E> {\n const app = new OpenAPIHono<E>();\n\n if (opts.db !== false) {\n app.use(\"*\", async (c, next) => {\n // @clawnify/db reads the DB (D1) or Storage binding off the env and caches\n // the Drizzle client for this request. Safe to call on every request.\n initDB(c.env as unknown as Parameters<typeof initDB>[0]);\n await next();\n });\n }\n\n if (opts.discovery !== false) {\n mountDiscovery(app, opts);\n }\n\n return app;\n}\n"],"mappings":";AA0BA,SAAS,aAAa,sBAA6C;AACnE,SAAS,cAAc;AAOvB;AAAA,EACE,eAAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,EACA;AAAA,OACK;AA4BA,SAAS,UACd,OAAyB,CAAC,GACV;AAChB,QAAM,MAAM,IAAI,YAAe;AAE/B,MAAI,KAAK,OAAO,OAAO;AACrB,QAAI,IAAI,KAAK,OAAO,GAAG,SAAS;AAG9B,aAAO,EAAE,GAA8C;AACvD,YAAM,KAAK;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,KAAK,cAAc,OAAO;AAC5B,mBAAe,KAAK,IAAI;AAAA,EAC1B;AAEA,SAAO;AACT;","names":["OpenAPIHono","mountDiscovery"]}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@clawnify/app",
3
+ "version": "0.1.0",
4
+ "description": "The standard Clawnify app skeleton in one call. createApp() returns a fully-wired OpenAPIHono with D1/Storage init + /api/openapi.json + /llms.txt discovery pre-baked, so an app is just imports + routes + export.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "@clawnify/db": "^0.4.1",
22
+ "@clawnify/routes": "^0.2.1"
23
+ },
24
+ "peerDependencies": {
25
+ "@hono/zod-openapi": ">=0.18 <1",
26
+ "hono": "*"
27
+ },
28
+ "devDependencies": {
29
+ "@cloudflare/workers-types": "^4.20260405.1",
30
+ "@hono/zod-openapi": "^0.18.0",
31
+ "hono": "^4.6.0",
32
+ "tsup": "^8.0.0",
33
+ "typescript": "^5.7.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsup",
37
+ "dev": "tsup --watch"
38
+ }
39
+ }