@apollo-deploy/tesseract 0.4.4 → 0.5.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.
Files changed (66) hide show
  1. package/README.md +330 -11
  2. package/dist/adapters/types.d.ts +2 -1
  3. package/dist/adapters/types.d.ts.map +1 -1
  4. package/dist/adapters/typescript/index.d.ts +2 -1
  5. package/dist/adapters/typescript/index.d.ts.map +1 -1
  6. package/dist/adapters/typescript/index.js +27 -10
  7. package/dist/adapters/typescript/index.js.map +1 -1
  8. package/dist/cli.js +19 -1
  9. package/dist/cli.js.map +1 -1
  10. package/dist/collector.d.ts +135 -0
  11. package/dist/collector.d.ts.map +1 -0
  12. package/dist/collector.js +159 -0
  13. package/dist/collector.js.map +1 -0
  14. package/dist/elysia.d.ts +65 -0
  15. package/dist/elysia.d.ts.map +1 -0
  16. package/dist/elysia.js +70 -0
  17. package/dist/elysia.js.map +1 -0
  18. package/dist/express.d.ts +74 -0
  19. package/dist/express.d.ts.map +1 -0
  20. package/dist/express.js +73 -0
  21. package/dist/express.js.map +1 -0
  22. package/dist/fastify.d.ts +135 -0
  23. package/dist/fastify.d.ts.map +1 -0
  24. package/dist/fastify.js +188 -0
  25. package/dist/fastify.js.map +1 -0
  26. package/dist/hono.d.ts +65 -0
  27. package/dist/hono.d.ts.map +1 -0
  28. package/dist/hono.js +64 -0
  29. package/dist/hono.js.map +1 -0
  30. package/dist/index.d.ts +5 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +4 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/koa.d.ts +69 -0
  35. package/dist/koa.d.ts.map +1 -0
  36. package/dist/koa.js +68 -0
  37. package/dist/koa.js.map +1 -0
  38. package/dist/nestjs.d.ts +107 -0
  39. package/dist/nestjs.d.ts.map +1 -0
  40. package/dist/nestjs.js +143 -0
  41. package/dist/nestjs.js.map +1 -0
  42. package/dist/pipeline/intake.d.ts.map +1 -1
  43. package/dist/pipeline/intake.js +35 -21
  44. package/dist/pipeline/intake.js.map +1 -1
  45. package/dist/pipeline/write.d.ts +1 -0
  46. package/dist/pipeline/write.d.ts.map +1 -1
  47. package/dist/pipeline/write.js +21 -3
  48. package/dist/pipeline/write.js.map +1 -1
  49. package/dist/types/config.d.ts +13 -3
  50. package/dist/types/config.d.ts.map +1 -1
  51. package/dist/types/config.js +5 -2
  52. package/dist/types/config.js.map +1 -1
  53. package/dist/types/ir.d.ts +8 -0
  54. package/dist/types/ir.d.ts.map +1 -1
  55. package/dist/types/manifest.d.ts +5 -30
  56. package/dist/types/manifest.d.ts.map +1 -1
  57. package/dist/types/manifest.js.map +1 -1
  58. package/dist/types/sdk-module.d.ts +128 -0
  59. package/dist/types/sdk-module.d.ts.map +1 -0
  60. package/dist/types/sdk-module.js +50 -0
  61. package/dist/types/sdk-module.js.map +1 -0
  62. package/package.json +63 -1
  63. package/templates/typescript/client-class.hbs +136 -0
  64. package/templates/typescript/domain-class.hbs +188 -0
  65. package/templates/typescript/domain.hbs +5 -1
  66. package/templates/typescript/index-class.hbs +68 -0
@@ -0,0 +1,135 @@
1
+ /**
2
+ * SDKCollector — framework-agnostic route and domain collector.
3
+ *
4
+ * The core primitive behind all framework adapters. Accumulates route
5
+ * definitions and domain metadata, then builds a `BackendManifest` in memory
6
+ * and calls the Tesseract generator.
7
+ *
8
+ * Used directly for framework-agnostic workflows and internally by all
9
+ * framework adapters (Express, Hono, Koa, Elysia, NestJS).
10
+ *
11
+ * ```ts
12
+ * import { SDKCollector } from '@apollo-deploy/tesseract';
13
+ *
14
+ * const collector = new SDKCollector({
15
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
16
+ * output: './packages/api-sdk',
17
+ * });
18
+ *
19
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
20
+ * collector.route('/users/:id', 'GET', { sdk: { methodName: 'getUser' } });
21
+ * collector.route('/users', 'POST', { sdk: { methodName: 'createUser' } });
22
+ *
23
+ * if (process.env.TESSERACT_GENERATE) {
24
+ * await collector.generate();
25
+ * process.exit(0);
26
+ * }
27
+ * ```
28
+ */
29
+ import type { BackendManifest, ManifestRouteSchema } from './types/manifest.js';
30
+ import type { SDKModuleConfig, SDKRouteConfig } from './types/sdk-module.js';
31
+ export interface CollectorOptions {
32
+ /** API metadata written into the generated package.json and README. */
33
+ info: {
34
+ title: string;
35
+ version: string;
36
+ baseUrl?: string;
37
+ description?: string;
38
+ };
39
+ /** Output directory for the generated SDK. */
40
+ output: string;
41
+ /**
42
+ * Shared type package used across your backend and generated SDK.
43
+ *
44
+ * When set, bare `$ref` values in route schemas (e.g. `{ $ref: 'User' }`)
45
+ * are treated as type names from this package rather than generating them inline.
46
+ */
47
+ schemaPackage?: {
48
+ name: string;
49
+ version?: string;
50
+ importPath?: string;
51
+ };
52
+ /** `'functional'` (default) or `'class'` (Resend-style `new MySDK('key')`). */
53
+ sdkStyle?: 'functional' | 'class';
54
+ /** `'internal'` (default) or `'public'` (auth key only, baseUrl baked in). */
55
+ clientType?: 'internal' | 'public';
56
+ /** Override the generated npm package name. */
57
+ packageName?: string;
58
+ /** Override the generated package version. */
59
+ packageVersion?: string;
60
+ }
61
+ export interface CollectorRouteConfig {
62
+ /** JSON Schemas for params, querystring, body, headers, and response. */
63
+ schema?: ManifestRouteSchema;
64
+ /** SDK-specific options for this route. */
65
+ sdk: SDKRouteConfig;
66
+ /** Whether the route is a Server-Sent Events stream. */
67
+ sse?: boolean;
68
+ }
69
+ interface InternalRoute {
70
+ url: string;
71
+ method: string;
72
+ schema?: ManifestRouteSchema;
73
+ sdk: SDKRouteConfig;
74
+ sse?: boolean;
75
+ }
76
+ /**
77
+ * Framework-agnostic route and domain collector.
78
+ *
79
+ * Works with any Node.js HTTP framework — Express, Hono, Koa, Elysia, NestJS,
80
+ * or plain `node:http`. Framework-specific subpackages export pre-wired
81
+ * subclasses or helpers that build on this class.
82
+ */
83
+ export declare class SDKCollector {
84
+ protected readonly _routes: InternalRoute[];
85
+ protected readonly _registry: Map<string, SDKModuleConfig>;
86
+ readonly opts: Readonly<CollectorOptions>;
87
+ constructor(opts: CollectorOptions);
88
+ /**
89
+ * Declare a domain (route group) by its URL prefix.
90
+ *
91
+ * @param prefix - The URL prefix shared by all routes in this domain (e.g. `/users`).
92
+ * @param config - Optional domain metadata — name override, description, stability.
93
+ */
94
+ domain(prefix: string, config?: Omit<SDKModuleConfig, 'prefix'>): this;
95
+ /**
96
+ * Register a route with the collector.
97
+ *
98
+ * Routes with `sdk.exclude: true` are silently ignored.
99
+ *
100
+ * @param url - Full URL path, e.g. `/users/:id`.
101
+ * @param method - HTTP method (case-insensitive).
102
+ * @param config - Schema and SDK options for this route.
103
+ */
104
+ route(url: string, method: string, config: CollectorRouteConfig): this;
105
+ /** Build and return the `BackendManifest` from all accumulated routes and domains. */
106
+ buildManifest(): BackendManifest;
107
+ /** Generate the SDK from accumulated routes and domains. */
108
+ generate(): Promise<import('./index.js').GenerateResult>;
109
+ /**
110
+ * Check if `TESSERACT_GENERATE=1` is set and generate the SDK if so.
111
+ *
112
+ * Returns `true` if generation was triggered. Call after all routes have
113
+ * been registered:
114
+ *
115
+ * ```ts
116
+ * // At the bottom of your app setup file:
117
+ * if (await collector.tryGenerate()) process.exit(0);
118
+ * ```
119
+ */
120
+ tryGenerate(): Promise<boolean>;
121
+ }
122
+ /**
123
+ * Builds a `BackendManifest` from a flat list of collected routes and a domain
124
+ * registry. Exported so framework adapters (including the Fastify plugin) can
125
+ * use it directly without going through `SDKCollector`.
126
+ */
127
+ export declare function buildManifestFromRoutes(routes: ReadonlyArray<{
128
+ url: string;
129
+ method: string;
130
+ schema?: ManifestRouteSchema;
131
+ sdk: SDKRouteConfig;
132
+ sse?: boolean;
133
+ }>, registry: ReadonlyMap<string, SDKModuleConfig>, info: CollectorOptions['info'], schemaPackage?: CollectorOptions['schemaPackage']): BackendManifest;
134
+ export {};
135
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAiB,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/F,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE7E,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,aAAa,CAAC,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC;IAClC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACnC,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,2CAA2C;IAC3C,GAAG,EAAE,cAAc,CAAC;IACpB,wDAAwD;IACxD,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,CAAM;IACjD,SAAS,CAAC,QAAQ,CAAC,SAAS,+BAAsC;IAClE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;gBAE9B,IAAI,EAAE,gBAAgB;IAIlC;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,GAAG,IAAI;IAKtE;;;;;;;;OAQG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAYtE,sFAAsF;IACtF,aAAa,IAAI,eAAe;IAIhC,4DAA4D;IACtD,QAAQ,IAAI,OAAO,CAAC,OAAO,YAAY,EAAE,cAAc,CAAC;IAa9D;;;;;;;;;;OAUG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAStC;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC,EACF,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC9C,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC9B,aAAa,CAAC,EAAE,gBAAgB,CAAC,eAAe,CAAC,GAChD,eAAe,CAuCjB"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * SDKCollector — framework-agnostic route and domain collector.
3
+ *
4
+ * The core primitive behind all framework adapters. Accumulates route
5
+ * definitions and domain metadata, then builds a `BackendManifest` in memory
6
+ * and calls the Tesseract generator.
7
+ *
8
+ * Used directly for framework-agnostic workflows and internally by all
9
+ * framework adapters (Express, Hono, Koa, Elysia, NestJS).
10
+ *
11
+ * ```ts
12
+ * import { SDKCollector } from '@apollo-deploy/tesseract';
13
+ *
14
+ * const collector = new SDKCollector({
15
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
16
+ * output: './packages/api-sdk',
17
+ * });
18
+ *
19
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
20
+ * collector.route('/users/:id', 'GET', { sdk: { methodName: 'getUser' } });
21
+ * collector.route('/users', 'POST', { sdk: { methodName: 'createUser' } });
22
+ *
23
+ * if (process.env.TESSERACT_GENERATE) {
24
+ * await collector.generate();
25
+ * process.exit(0);
26
+ * }
27
+ * ```
28
+ */
29
+ /**
30
+ * Framework-agnostic route and domain collector.
31
+ *
32
+ * Works with any Node.js HTTP framework — Express, Hono, Koa, Elysia, NestJS,
33
+ * or plain `node:http`. Framework-specific subpackages export pre-wired
34
+ * subclasses or helpers that build on this class.
35
+ */
36
+ export class SDKCollector {
37
+ _routes = [];
38
+ _registry = new Map();
39
+ opts;
40
+ constructor(opts) {
41
+ this.opts = opts;
42
+ }
43
+ /**
44
+ * Declare a domain (route group) by its URL prefix.
45
+ *
46
+ * @param prefix - The URL prefix shared by all routes in this domain (e.g. `/users`).
47
+ * @param config - Optional domain metadata — name override, description, stability.
48
+ */
49
+ domain(prefix, config) {
50
+ this._registry.set(prefix, { prefix, ...config });
51
+ return this;
52
+ }
53
+ /**
54
+ * Register a route with the collector.
55
+ *
56
+ * Routes with `sdk.exclude: true` are silently ignored.
57
+ *
58
+ * @param url - Full URL path, e.g. `/users/:id`.
59
+ * @param method - HTTP method (case-insensitive).
60
+ * @param config - Schema and SDK options for this route.
61
+ */
62
+ route(url, method, config) {
63
+ if (config.sdk?.exclude)
64
+ return this;
65
+ this._routes.push({
66
+ url,
67
+ method: method.toUpperCase(),
68
+ schema: config.schema,
69
+ sdk: config.sdk,
70
+ sse: config.sse,
71
+ });
72
+ return this;
73
+ }
74
+ /** Build and return the `BackendManifest` from all accumulated routes and domains. */
75
+ buildManifest() {
76
+ return buildManifestFromRoutes(this._routes, this._registry, this.opts.info, this.opts.schemaPackage);
77
+ }
78
+ /** Generate the SDK from accumulated routes and domains. */
79
+ async generate() {
80
+ const { generate } = await import('./index.js');
81
+ const manifest = this.buildManifest();
82
+ return generate({
83
+ manifest,
84
+ output: this.opts.output,
85
+ clientType: this.opts.clientType,
86
+ packageName: this.opts.packageName,
87
+ packageVersion: this.opts.packageVersion,
88
+ sdkStyle: this.opts.sdkStyle,
89
+ });
90
+ }
91
+ /**
92
+ * Check if `TESSERACT_GENERATE=1` is set and generate the SDK if so.
93
+ *
94
+ * Returns `true` if generation was triggered. Call after all routes have
95
+ * been registered:
96
+ *
97
+ * ```ts
98
+ * // At the bottom of your app setup file:
99
+ * if (await collector.tryGenerate()) process.exit(0);
100
+ * ```
101
+ */
102
+ async tryGenerate() {
103
+ if (!process.env.TESSERACT_GENERATE)
104
+ return false;
105
+ const result = await this.generate();
106
+ if (result.warnings.length > 0) {
107
+ for (const w of result.warnings)
108
+ console.warn(` ⚠ ${w}`);
109
+ }
110
+ console.log(`[tesseract] ✓ ${result.filesWritten} files written → ${this.opts.output}`);
111
+ return true;
112
+ }
113
+ }
114
+ // ── Shared manifest builder ───────────────────────────────────────────────────
115
+ /**
116
+ * Builds a `BackendManifest` from a flat list of collected routes and a domain
117
+ * registry. Exported so framework adapters (including the Fastify plugin) can
118
+ * use it directly without going through `SDKCollector`.
119
+ */
120
+ export function buildManifestFromRoutes(routes, registry, info, schemaPackage) {
121
+ // Longest-prefix-first so more specific prefixes match before their parents
122
+ const sortedPrefixes = [...registry.keys()].sort((a, b) => b.length - a.length);
123
+ const domainMap = new Map();
124
+ for (const route of routes) {
125
+ const matchedPrefix = sortedPrefixes.find((p) => route.url === p || route.url.startsWith(p + '/')) ??
126
+ derivePrefix(route.url);
127
+ if (!domainMap.has(matchedPrefix)) {
128
+ domainMap.set(matchedPrefix, {
129
+ config: registry.get(matchedPrefix) ?? { prefix: matchedPrefix },
130
+ routes: [],
131
+ });
132
+ }
133
+ const tail = route.url.substring(matchedPrefix.length) || '/';
134
+ domainMap.get(matchedPrefix).routes.push({
135
+ method: route.method,
136
+ url: tail.startsWith('/') ? tail : '/' + tail,
137
+ schema: route.schema,
138
+ sdk: route.sdk,
139
+ sse: route.sse,
140
+ });
141
+ }
142
+ return {
143
+ $schema: 'sdk-manifold/v1',
144
+ info: {
145
+ title: info.title,
146
+ version: info.version,
147
+ description: info.description,
148
+ baseUrl: info.baseUrl,
149
+ },
150
+ ...(schemaPackage && { schemaPackage }),
151
+ domains: [...domainMap.values()].map(({ config, routes }) => ({ ...config, routes })),
152
+ };
153
+ }
154
+ /** Derives a domain prefix from the first non-parameter URL segment. */
155
+ function derivePrefix(url) {
156
+ const first = url.split('/').find((s) => s.length > 0 && !s.startsWith(':'));
157
+ return first ? '/' + first : '/';
158
+ }
159
+ //# sourceMappingURL=collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.js","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Tesseract Elysia integration.
3
+ *
4
+ * Provides a `tesseractPlugin()` factory that returns an Elysia plugin and a
5
+ * paired `SDKCollector`. Register the plugin with your app, then annotate
6
+ * routes with the collector. The plugin triggers SDK generation automatically
7
+ * when `TESSERACT_GENERATE=1` is set.
8
+ *
9
+ * ```ts
10
+ * import { Elysia } from 'elysia';
11
+ * import { tesseractPlugin } from '@apollo-deploy/tesseract/elysia';
12
+ *
13
+ * const { plugin, collector } = tesseractPlugin({
14
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
15
+ * output: './packages/api-sdk',
16
+ * });
17
+ *
18
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
19
+ * collector.route('/users/:id', 'GET', { sdk: { methodName: 'getUser' } });
20
+ * collector.route('/users', 'POST', { sdk: { methodName: 'createUser' } });
21
+ *
22
+ * const app = new Elysia()
23
+ * .use(plugin)
24
+ * .get('/users/:id', ({ params }) => getUser(params.id))
25
+ * .post('/users', ({ body }) => createUser(body))
26
+ * .listen(3000);
27
+ * ```
28
+ *
29
+ * **Triggering generation:**
30
+ * ```bash
31
+ * TESSERACT_GENERATE=1 bun run dist/app.js
32
+ * ```
33
+ */
34
+ import { SDKCollector } from './collector.js';
35
+ import type { CollectorOptions } from './collector.js';
36
+ export { SDKCollector } from './collector.js';
37
+ export type { CollectorOptions, CollectorRouteConfig } from './collector.js';
38
+ /**
39
+ * Minimal Elysia plugin type — typed as `unknown` to avoid requiring a hard
40
+ * dependency on the `elysia` package.
41
+ */
42
+ type ElysiaLike = {
43
+ onStart(handler: () => void | Promise<void>): unknown;
44
+ };
45
+ export interface TesseractElysiaPlugin {
46
+ /** The Elysia plugin. Pass to `.use(plugin)` on your app. */
47
+ plugin: (app: ElysiaLike) => ElysiaLike;
48
+ /** The collector. Register domains and routes on this before your app starts. */
49
+ collector: SDKCollector;
50
+ }
51
+ /**
52
+ * Create a Tesseract Elysia plugin and a paired `SDKCollector`.
53
+ *
54
+ * The plugin registers an `onStart` hook that triggers SDK generation when
55
+ * `TESSERACT_GENERATE=1` is set. It is a no-op otherwise.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const { plugin, collector } = tesseractPlugin({ info: { ... }, output: './sdk' });
60
+ * collector.route('/users/:id', 'GET', { sdk: { methodName: 'getUser' } });
61
+ * new Elysia().use(plugin).get('/users/:id', handler).listen(3000);
62
+ * ```
63
+ */
64
+ export declare function tesseractPlugin(opts: CollectorOptions): TesseractElysiaPlugin;
65
+ //# sourceMappingURL=elysia.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elysia.d.ts","sourceRoot":"","sources":["../src/elysia.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;;GAGG;AACH,KAAK,UAAU,GAAG;IAChB,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;CACvD,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,6DAA6D;IAC7D,MAAM,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,UAAU,CAAC;IACxC,iFAAiF;IACjF,SAAS,EAAE,YAAY,CAAC;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,qBAAqB,CA2B7E"}
package/dist/elysia.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Tesseract Elysia integration.
3
+ *
4
+ * Provides a `tesseractPlugin()` factory that returns an Elysia plugin and a
5
+ * paired `SDKCollector`. Register the plugin with your app, then annotate
6
+ * routes with the collector. The plugin triggers SDK generation automatically
7
+ * when `TESSERACT_GENERATE=1` is set.
8
+ *
9
+ * ```ts
10
+ * import { Elysia } from 'elysia';
11
+ * import { tesseractPlugin } from '@apollo-deploy/tesseract/elysia';
12
+ *
13
+ * const { plugin, collector } = tesseractPlugin({
14
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
15
+ * output: './packages/api-sdk',
16
+ * });
17
+ *
18
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
19
+ * collector.route('/users/:id', 'GET', { sdk: { methodName: 'getUser' } });
20
+ * collector.route('/users', 'POST', { sdk: { methodName: 'createUser' } });
21
+ *
22
+ * const app = new Elysia()
23
+ * .use(plugin)
24
+ * .get('/users/:id', ({ params }) => getUser(params.id))
25
+ * .post('/users', ({ body }) => createUser(body))
26
+ * .listen(3000);
27
+ * ```
28
+ *
29
+ * **Triggering generation:**
30
+ * ```bash
31
+ * TESSERACT_GENERATE=1 bun run dist/app.js
32
+ * ```
33
+ */
34
+ import { SDKCollector } from './collector.js';
35
+ export { SDKCollector } from './collector.js';
36
+ /**
37
+ * Create a Tesseract Elysia plugin and a paired `SDKCollector`.
38
+ *
39
+ * The plugin registers an `onStart` hook that triggers SDK generation when
40
+ * `TESSERACT_GENERATE=1` is set. It is a no-op otherwise.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const { plugin, collector } = tesseractPlugin({ info: { ... }, output: './sdk' });
45
+ * collector.route('/users/:id', 'GET', { sdk: { methodName: 'getUser' } });
46
+ * new Elysia().use(plugin).get('/users/:id', handler).listen(3000);
47
+ * ```
48
+ */
49
+ export function tesseractPlugin(opts) {
50
+ const collector = new SDKCollector(opts);
51
+ const plugin = (app) => {
52
+ app.onStart(async () => {
53
+ if (!process.env.TESSERACT_GENERATE)
54
+ return;
55
+ if (collector['_routes'].length === 0) {
56
+ console.error('\n[tesseract] No SDK routes found. Call collector.route() before the app starts.');
57
+ process.exit(1);
58
+ }
59
+ const result = await collector.generate();
60
+ for (const w of result.warnings)
61
+ console.warn(` ⚠ ${w}`);
62
+ console.log(`\n[tesseract] ${collector['_routes'].length} route(s) → ${opts.output}`);
63
+ console.log(`[tesseract] ✓ ${result.filesWritten} files written\n`);
64
+ process.exit(0);
65
+ });
66
+ return app;
67
+ };
68
+ return { plugin, collector };
69
+ }
70
+ //# sourceMappingURL=elysia.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elysia.js","sourceRoot":"","sources":["../src/elysia.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAkB9C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,IAAsB;IACpD,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,CAAC,GAAe,EAAc,EAAE;QAC7C,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB;gBAAE,OAAO;YAE5C,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtC,OAAO,CAAC,KAAK,CACX,kFAAkF,CACnF,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC;YAC1C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ;gBAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,GAAG,CACT,iBAAiB,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,eAAe,IAAI,CAAC,MAAM,EAAE,CACzE,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,YAAY,kBAAkB,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Tesseract Express integration.
3
+ *
4
+ * Re-exports `SDKCollector` and adds an `ExpressSDKCollector` subclass with a
5
+ * `.expressRoute()` helper that registers a route with the collector and returns
6
+ * a no-op Express middleware in a single call — keeping SDK metadata co-located
7
+ * with the route definition.
8
+ *
9
+ * Because Express has no route-registration hook, routes are registered with the
10
+ * collector explicitly. Generation is triggered by calling
11
+ * `collector.tryGenerate()` after all routes are set up.
12
+ *
13
+ * ```ts
14
+ * import express from 'express';
15
+ * import { ExpressSDKCollector } from '@apollo-deploy/tesseract/express';
16
+ *
17
+ * const app = express();
18
+ * const collector = new ExpressSDKCollector({
19
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
20
+ * output: './packages/api-sdk',
21
+ * });
22
+ *
23
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
24
+ *
25
+ * app.get('/users/:id',
26
+ * collector.expressRoute('/users/:id', 'GET', { sdk: { methodName: 'getUser' } }),
27
+ * getUserHandler,
28
+ * );
29
+ *
30
+ * app.post('/users',
31
+ * collector.expressRoute('/users', 'POST', { sdk: { methodName: 'createUser' } }),
32
+ * createUserHandler,
33
+ * );
34
+ *
35
+ * // After all routes are registered:
36
+ * if (await collector.tryGenerate()) process.exit(0);
37
+ *
38
+ * app.listen(3000);
39
+ * ```
40
+ *
41
+ * **Triggering generation:**
42
+ * ```bash
43
+ * TESSERACT_GENERATE=1 node dist/app.js
44
+ * ```
45
+ */
46
+ import { SDKCollector } from './collector.js';
47
+ import type { CollectorRouteConfig } from './collector.js';
48
+ /** Minimal Express RequestHandler type — avoids a hard import of the `express` package. */
49
+ type RequestHandler = (req: unknown, res: unknown, next: () => void) => void;
50
+ export { SDKCollector } from './collector.js';
51
+ export type { CollectorOptions, CollectorRouteConfig } from './collector.js';
52
+ /**
53
+ * `SDKCollector` subclass with an Express-specific `.expressRoute()` helper.
54
+ *
55
+ * `.expressRoute()` registers a route with the collector **and** returns a
56
+ * no-op `RequestHandler` for inline placement in `app.get()` / `router.post()` etc.
57
+ */
58
+ export declare class ExpressSDKCollector extends SDKCollector {
59
+ /**
60
+ * Register a route with the collector and return a no-op Express middleware.
61
+ *
62
+ * Placing the returned middleware in your route definition keeps the SDK
63
+ * metadata co-located with the handler:
64
+ *
65
+ * ```ts
66
+ * app.get('/users/:id', collector.expressRoute('/users/:id', 'GET', {
67
+ * sdk: { methodName: 'getUser' },
68
+ * schema: { response: { 200: { $ref: 'User' } } },
69
+ * }), handler);
70
+ * ```
71
+ */
72
+ expressRoute(url: string, method: string, config: CollectorRouteConfig): RequestHandler;
73
+ }
74
+ //# sourceMappingURL=express.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,2FAA2F;AAC3F,KAAK,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAE7E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;IACnD;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,cAAc;CAIxF"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Tesseract Express integration.
3
+ *
4
+ * Re-exports `SDKCollector` and adds an `ExpressSDKCollector` subclass with a
5
+ * `.expressRoute()` helper that registers a route with the collector and returns
6
+ * a no-op Express middleware in a single call — keeping SDK metadata co-located
7
+ * with the route definition.
8
+ *
9
+ * Because Express has no route-registration hook, routes are registered with the
10
+ * collector explicitly. Generation is triggered by calling
11
+ * `collector.tryGenerate()` after all routes are set up.
12
+ *
13
+ * ```ts
14
+ * import express from 'express';
15
+ * import { ExpressSDKCollector } from '@apollo-deploy/tesseract/express';
16
+ *
17
+ * const app = express();
18
+ * const collector = new ExpressSDKCollector({
19
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
20
+ * output: './packages/api-sdk',
21
+ * });
22
+ *
23
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
24
+ *
25
+ * app.get('/users/:id',
26
+ * collector.expressRoute('/users/:id', 'GET', { sdk: { methodName: 'getUser' } }),
27
+ * getUserHandler,
28
+ * );
29
+ *
30
+ * app.post('/users',
31
+ * collector.expressRoute('/users', 'POST', { sdk: { methodName: 'createUser' } }),
32
+ * createUserHandler,
33
+ * );
34
+ *
35
+ * // After all routes are registered:
36
+ * if (await collector.tryGenerate()) process.exit(0);
37
+ *
38
+ * app.listen(3000);
39
+ * ```
40
+ *
41
+ * **Triggering generation:**
42
+ * ```bash
43
+ * TESSERACT_GENERATE=1 node dist/app.js
44
+ * ```
45
+ */
46
+ import { SDKCollector } from './collector.js';
47
+ export { SDKCollector } from './collector.js';
48
+ /**
49
+ * `SDKCollector` subclass with an Express-specific `.expressRoute()` helper.
50
+ *
51
+ * `.expressRoute()` registers a route with the collector **and** returns a
52
+ * no-op `RequestHandler` for inline placement in `app.get()` / `router.post()` etc.
53
+ */
54
+ export class ExpressSDKCollector extends SDKCollector {
55
+ /**
56
+ * Register a route with the collector and return a no-op Express middleware.
57
+ *
58
+ * Placing the returned middleware in your route definition keeps the SDK
59
+ * metadata co-located with the handler:
60
+ *
61
+ * ```ts
62
+ * app.get('/users/:id', collector.expressRoute('/users/:id', 'GET', {
63
+ * sdk: { methodName: 'getUser' },
64
+ * schema: { response: { 200: { $ref: 'User' } } },
65
+ * }), handler);
66
+ * ```
67
+ */
68
+ expressRoute(url, method, config) {
69
+ this.route(url, method, config);
70
+ return (_req, _res, next) => next();
71
+ }
72
+ }
73
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;;;;GAKG;AACH,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACnD;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,GAAW,EAAE,MAAc,EAAE,MAA4B;QACpE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,CAAC,IAAa,EAAE,IAAa,EAAE,IAAgB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IACpE,CAAC;CACF"}