@effing/fn 0.28.0 → 0.29.1

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 (2) hide show
  1. package/README.md +243 -0
  2. package/package.json +3 -3
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # @effing/fn
2
+
3
+ **Pluggable function runtime for loading and executing generative modules.**
4
+
5
+ > Part of the [**Effing**](../../README.md) family — programmatic video creation with TypeScript.
6
+
7
+ Define functions that generate images, animations, or video compositions — then load and execute them through a pluggable runtime with built-in schema validation and URL building.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @effing/fn
13
+ ```
14
+
15
+ ## Concepts
16
+
17
+ ### Function Kinds
18
+
19
+ Every function module produces one of three output types:
20
+
21
+ | Kind | Output | Description |
22
+ | --------- | ----------------------- | ------------------------------- |
23
+ | `"image"` | `Promise<Buffer>` | A single PNG or JPEG image |
24
+ | `"annie"` | `AsyncIterable<Buffer>` | A stream of animation frames |
25
+ | `"effie"` | `Promise<EffieData>` | A declarative video composition |
26
+
27
+ ### Function Modules
28
+
29
+ A function module bundles a runner with its schema and preview data:
30
+
31
+ ```typescript
32
+ import { z } from "zod";
33
+ import type { ImageFnModule } from "@effing/fn";
34
+
35
+ const myImageFn: ImageFnModule = {
36
+ propsSchema: z.object({
37
+ title: z.string(),
38
+ color: z.string().default("#ffffff"),
39
+ }),
40
+ previewProps: { title: "Hello", color: "#ff0000" },
41
+ runner: async ({ props, bounds }) => {
42
+ // Generate and return PNG/JPEG bytes
43
+ return renderImage(props, bounds);
44
+ },
45
+ };
46
+ ```
47
+
48
+ - **`runner`** — Async function that receives `{ props, bounds }` and returns the output
49
+ - **`propsSchema`** — Zod schema for validating input props
50
+ - **`previewProps`** — Default props for UI previews
51
+
52
+ ### Bounds
53
+
54
+ Every runner receives a `bounds` object describing the output dimensions:
55
+
56
+ ```typescript
57
+ type Bounds = Readonly<{ width: number; height: number }>;
58
+ ```
59
+
60
+ ### Pluggable Runtime
61
+
62
+ The runtime is initialized once with a **module loader** (discovers and loads function modules) and a **URL builder** (constructs execution URLs). This keeps the core framework-agnostic — implementations are provided by the host environment.
63
+
64
+ ```typescript
65
+ import { initFnRuntime } from "@effing/fn";
66
+
67
+ initFnRuntime({
68
+ moduleLoader: myModuleLoader,
69
+ urlBuilder: myUrlBuilder,
70
+ });
71
+ ```
72
+
73
+ ## Quick Start
74
+
75
+ ```typescript
76
+ import { initFnRuntime, fnModule, fnUrl, fnModuleIds } from "@effing/fn";
77
+
78
+ // Initialize the runtime (once, at startup)
79
+ initFnRuntime({
80
+ moduleLoader: myModuleLoader,
81
+ urlBuilder: myUrlBuilder,
82
+ });
83
+
84
+ // Load and execute a function module
85
+ const mod = await fnModule("image", "social-card");
86
+ const result = await mod.runner({
87
+ props: { title: "Hello World" },
88
+ bounds: { width: 1200, height: 630 },
89
+ });
90
+
91
+ // Build a URL for a function
92
+ const url = await fnUrl(
93
+ "annie",
94
+ "intro-animation",
95
+ { text: "Welcome" },
96
+ { width: 1080, height: 1920 },
97
+ );
98
+
99
+ // List available modules
100
+ const imageIds = fnModuleIds("image");
101
+ ```
102
+
103
+ ## API Overview
104
+
105
+ ### Runtime
106
+
107
+ #### `initFnRuntime(config)`
108
+
109
+ Initialize the global runtime with a module loader and URL builder. Must be called before any other runtime function.
110
+
111
+ ```typescript
112
+ function initFnRuntime(config: {
113
+ moduleLoader: FnModuleLoader;
114
+ urlBuilder: FnUrlBuilder;
115
+ }): void;
116
+ ```
117
+
118
+ #### `fnModule(kind, id)`
119
+
120
+ Load a function module by kind and ID.
121
+
122
+ ```typescript
123
+ function fnModule<K extends FnKind>(kind: K, id: string): Promise<FnModule<K>>;
124
+ ```
125
+
126
+ #### `fnUrl(kind, id, props, bounds)`
127
+
128
+ Build an execution URL for a function.
129
+
130
+ ```typescript
131
+ function fnUrl<P extends Record<string, unknown>>(
132
+ kind: FnKind,
133
+ id: string,
134
+ props: P,
135
+ bounds: Bounds,
136
+ ): Promise<EffieWebUrl>;
137
+ ```
138
+
139
+ #### `fnModuleIds(kind)`
140
+
141
+ List all available module IDs for a given kind.
142
+
143
+ ```typescript
144
+ function fnModuleIds(kind: FnKind): string[];
145
+ ```
146
+
147
+ #### `fnModuleExists(kind, id)`
148
+
149
+ Check whether a module exists.
150
+
151
+ ```typescript
152
+ function fnModuleExists(kind: FnKind, id: string): boolean;
153
+ ```
154
+
155
+ ### Response Helpers
156
+
157
+ Convenience functions for returning function output as HTTP responses.
158
+
159
+ #### `imageResponse(bytes, options?)`
160
+
161
+ Create a `Response` with auto-detected MIME type (PNG or JPEG).
162
+
163
+ ```typescript
164
+ function imageResponse(
165
+ bytes: Uint8Array,
166
+ options?: ImageResponseOptions,
167
+ ): Response;
168
+ ```
169
+
170
+ **Options:**
171
+
172
+ - `headers` — Additional response headers
173
+ - `cacheControl` — Cache-Control header value (default: `"public, max-age=3600"`)
174
+
175
+ #### `annieResponse(frames, options?)`
176
+
177
+ Stream animation frames as a TAR archive response.
178
+
179
+ ```typescript
180
+ function annieResponse(
181
+ frames: AsyncIterable<Buffer>,
182
+ options?: AnnieResponseOptions,
183
+ ): Response;
184
+ ```
185
+
186
+ **Options:**
187
+
188
+ - `signal` — AbortSignal for cancellation
189
+ - `headers` — Additional response headers
190
+ - `cacheControl` — Cache-Control header value (default: `"public, max-age=3600"`)
191
+ - `filename` — Sets Content-Disposition filename
192
+
193
+ #### `effieResponse(data, options?)`
194
+
195
+ Serialize an Effie composition as a JSON response.
196
+
197
+ ```typescript
198
+ function effieResponse<S extends EffieSources>(
199
+ data: EffieData<S>,
200
+ options?: EffieResponseOptions,
201
+ ): Response;
202
+ ```
203
+
204
+ **Options:**
205
+
206
+ - `headers` — Additional response headers
207
+ - `cacheControl` — Cache-Control header value (default: `"public, max-age=3600"`)
208
+
209
+ ### Types
210
+
211
+ #### Module Loader
212
+
213
+ Implement `FnModuleLoader` to provide module discovery and loading:
214
+
215
+ ```typescript
216
+ type FnModuleLoader = {
217
+ loadModule<K extends FnKind>(kind: K, id: string): Promise<FnModule<K>>;
218
+ listModules(kind: FnKind): string[];
219
+ hasModule(kind: FnKind, id: string): boolean;
220
+ };
221
+ ```
222
+
223
+ #### URL Builder
224
+
225
+ Implement `FnUrlBuilder` to provide URL construction:
226
+
227
+ ```typescript
228
+ type FnUrlBuilder = {
229
+ buildUrl<P extends Record<string, unknown>>(
230
+ kind: FnKind,
231
+ id: string,
232
+ props: P,
233
+ bounds: Bounds,
234
+ ): Promise<EffieWebUrl>;
235
+ };
236
+ ```
237
+
238
+ ## Related Packages
239
+
240
+ - [`@effing/annie`](../annie) — Annie animation format used by `"annie"` functions
241
+ - [`@effing/effie`](../effie) — Effie composition format used by `"effie"` functions
242
+ - [`@effing/canvas`](../canvas) — Render JSX to PNG for image function runners
243
+ - [`@effing/tween`](../tween) — Step iteration and easing for animation runners
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effing/fn",
3
- "version": "0.28.0",
3
+ "version": "0.29.1",
4
4
  "description": "Effing function runtime — pluggable module loading and URL building",
5
5
  "type": "module",
6
6
  "exports": {
@@ -13,14 +13,14 @@
13
13
  "dist"
14
14
  ],
15
15
  "dependencies": {
16
- "@effing/annie": "0.28.0"
16
+ "@effing/annie": "0.29.1"
17
17
  },
18
18
  "devDependencies": {
19
19
  "tsup": "^8.0.0",
20
20
  "typescript": "^5.9.3",
21
21
  "vitest": "^3.2.4",
22
22
  "zod": "^3.25.76",
23
- "@effing/effie": "0.28.0"
23
+ "@effing/effie": "0.29.1"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "zod": "^3.0.0"