@effing/fn 0.38.4 → 0.40.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.
@@ -15,7 +15,11 @@ function imageResponse(bytes, options = {}) {
15
15
  if (!(bytes.buffer instanceof ArrayBuffer)) {
16
16
  throw new TypeError("SharedArrayBuffer is not supported");
17
17
  }
18
- return new Response(bytes.buffer, { status: 200, headers });
18
+ const body = bytes.buffer.slice(
19
+ bytes.byteOffset,
20
+ bytes.byteOffset + bytes.byteLength
21
+ );
22
+ return new Response(body, { status: 200, headers });
19
23
  }
20
24
  function annieResponse(frames, options = {}) {
21
25
  const {
@@ -49,4 +53,4 @@ export {
49
53
  annieResponse,
50
54
  effieResponse
51
55
  };
52
- //# sourceMappingURL=chunk-UHDIQDAF.js.map
56
+ //# sourceMappingURL=chunk-ANDDDI6X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/responses.ts"],"sourcesContent":["import type { EffieData, EffieSources } from \"@effing/effie\";\nimport { annieStream } from \"@effing/annie\";\nimport type { AnnieStreamOptions } from \"@effing/annie\";\n\nexport type ImageResponseOptions = {\n headers?: HeadersInit;\n cacheControl?: string;\n};\n\nfunction detectImageContentType(bytes: Uint8Array): string {\n if (bytes[0] === 0x89 && bytes[1] === 0x50) return \"image/png\";\n if (bytes[0] === 0xff && bytes[1] === 0xd8) return \"image/jpeg\";\n throw new Error(\"Unsupported image format: expected PNG or JPEG\");\n}\n\nexport function imageResponse(\n bytes: Uint8Array,\n options: ImageResponseOptions = {},\n): Response {\n const { headers: extraHeaders, cacheControl = \"public, max-age=3600\" } =\n options;\n\n const headers = new Headers(extraHeaders);\n headers.set(\"Content-Type\", detectImageContentType(bytes));\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n\n if (!(bytes.buffer instanceof ArrayBuffer)) {\n throw new TypeError(\"SharedArrayBuffer is not supported\");\n }\n\n // Serve only the window `bytes` describes, not its whole backing buffer:\n // `bytes` may be a view (offset/length) into a larger pooled buffer, and\n // serving the backing buffer would corrupt the body and leak adjacent bytes.\n const body = bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength,\n );\n\n return new Response(body, { status: 200, headers });\n}\n\nexport type AnnieResponseOptions = AnnieStreamOptions & {\n headers?: HeadersInit;\n cacheControl?: string;\n filename?: string;\n};\n\nexport function annieResponse(\n frames: AsyncIterable<Buffer>,\n options: AnnieResponseOptions = {},\n): Response {\n const {\n headers: extraHeaders,\n cacheControl = \"public, max-age=3600\",\n filename,\n ...streamOptions\n } = options;\n\n const stream = annieStream(frames, streamOptions);\n\n const headers = new Headers(extraHeaders);\n headers.set(\"Content-Type\", \"application/x-tar\");\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n if (filename) {\n headers.set(\"Content-Disposition\", `inline; filename=\"${filename}.tar\"`);\n }\n\n return new Response(stream, { status: 200, headers });\n}\n\nexport type EffieResponseOptions = {\n headers?: HeadersInit;\n cacheControl?: string;\n};\n\nexport function effieResponse<S extends EffieSources>(\n data: EffieData<S>,\n options: EffieResponseOptions = {},\n): Response {\n const { headers: extraHeaders, cacheControl = \"public, max-age=3600\" } =\n options;\n\n const headers = new Headers(extraHeaders);\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n\n return Response.json(data, { status: 200, headers });\n}\n"],"mappings":";AACA,SAAS,mBAAmB;AAQ5B,SAAS,uBAAuB,OAA2B;AACzD,MAAI,MAAM,CAAC,MAAM,OAAQ,MAAM,CAAC,MAAM,GAAM,QAAO;AACnD,MAAI,MAAM,CAAC,MAAM,OAAQ,MAAM,CAAC,MAAM,IAAM,QAAO;AACnD,QAAM,IAAI,MAAM,gDAAgD;AAClE;AAEO,SAAS,cACd,OACA,UAAgC,CAAC,GACvB;AACV,QAAM,EAAE,SAAS,cAAc,eAAe,uBAAuB,IACnE;AAEF,QAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,UAAQ,IAAI,gBAAgB,uBAAuB,KAAK,CAAC;AACzD,MAAI,cAAc;AAChB,YAAQ,IAAI,iBAAiB,YAAY;AAAA,EAC3C;AAEA,MAAI,EAAE,MAAM,kBAAkB,cAAc;AAC1C,UAAM,IAAI,UAAU,oCAAoC;AAAA,EAC1D;AAKA,QAAM,OAAO,MAAM,OAAO;AAAA,IACxB,MAAM;AAAA,IACN,MAAM,aAAa,MAAM;AAAA,EAC3B;AAEA,SAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,QAAQ,CAAC;AACpD;AAQO,SAAS,cACd,QACA,UAAgC,CAAC,GACvB;AACV,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,SAAS,YAAY,QAAQ,aAAa;AAEhD,QAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,UAAQ,IAAI,gBAAgB,mBAAmB;AAC/C,MAAI,cAAc;AAChB,YAAQ,IAAI,iBAAiB,YAAY;AAAA,EAC3C;AACA,MAAI,UAAU;AACZ,YAAQ,IAAI,uBAAuB,qBAAqB,QAAQ,OAAO;AAAA,EACzE;AAEA,SAAO,IAAI,SAAS,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAC;AACtD;AAOO,SAAS,cACd,MACA,UAAgC,CAAC,GACvB;AACV,QAAM,EAAE,SAAS,cAAc,eAAe,uBAAuB,IACnE;AAEF,QAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,MAAI,cAAc;AAChB,YAAQ,IAAI,iBAAiB,YAAY;AAAA,EAC3C;AAEA,SAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,QAAQ,CAAC;AACrD;","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,9 +1,42 @@
1
- import { F as FnModuleLoader, a as FnUrlBuilder, b as FnKind, c as FnModule, B as Bounds } from './types-8Q-DJL6t.js';
2
- export { e as AnnieFnModule, A as AnnieRunnerReturn, f as EffieFnModule, E as EffieRunnerReturn, d as ImageFnModule, I as ImageRunnerReturn, R as RunnerArgs } from './types-8Q-DJL6t.js';
1
+ import { F as FnKind, a as FnModule, B as Bounds, b as FnModuleLoader, c as FnUrlBuilder } from './types-CFYPy7AY.js';
2
+ export { e as AnnieFnModule, A as AnnieRunnerReturn, f as EffieFnModule, E as EffieRunnerReturn, d as ImageFnModule, I as ImageRunnerReturn, R as RunnerArgs } from './types-CFYPy7AY.js';
3
3
  import { EffieWebUrl, EffieSources, EffieData } from '@effing/effie';
4
4
  import { AnnieStreamOptions } from '@effing/annie';
5
5
  import 'zod';
6
6
 
7
+ /**
8
+ * A self-contained fn runtime: the module loader and URL builder are captured
9
+ * in the handle instead of living in module-global state, so multiple
10
+ * runtimes with different configurations can coexist in one process.
11
+ */
12
+ interface FnRuntime {
13
+ /** Load an fn module of the given kind by id. */
14
+ fnModule<K extends FnKind>(kind: K, id: string): Promise<FnModule<K>>;
15
+ /** Build a signed URL pointing at another fn's output. */
16
+ fnUrl<P extends Record<string, unknown>>(kind: FnKind, id: string, props: P, bounds: Bounds): Promise<EffieWebUrl>;
17
+ /** List the ids of all fn modules of the given kind. */
18
+ fnModuleIds(kind: FnKind): string[];
19
+ /** Check whether an fn module of the given kind exists. */
20
+ fnModuleExists(kind: FnKind, id: string): boolean;
21
+ }
22
+ /**
23
+ * Create an explicit fn runtime handle bound to the given module loader and
24
+ * URL builder. Unlike {@link initFnRuntime}, this involves no global state:
25
+ * each handle resolves through its own loader/builder, so independent
26
+ * runtimes can be used side by side (e.g. in parallel tests or multi-tenant
27
+ * servers).
28
+ */
29
+ declare function createFnRuntime(config: {
30
+ moduleLoader: FnModuleLoader;
31
+ urlBuilder: FnUrlBuilder;
32
+ }): FnRuntime;
33
+ /**
34
+ * Initialize the process-global fn runtime used by the standalone
35
+ * {@link fnModule}, {@link fnUrl}, {@link fnModuleIds} and
36
+ * {@link fnModuleExists} functions. This is a thin shim over
37
+ * {@link createFnRuntime}; prefer an explicit runtime handle when more than
38
+ * one configuration must coexist in a process.
39
+ */
7
40
  declare function initFnRuntime(config: {
8
41
  moduleLoader: FnModuleLoader;
9
42
  urlBuilder: FnUrlBuilder;
@@ -30,4 +63,4 @@ type EffieResponseOptions = {
30
63
  };
31
64
  declare function effieResponse<S extends EffieSources>(data: EffieData<S>, options?: EffieResponseOptions): Response;
32
65
 
33
- export { type AnnieResponseOptions, Bounds, type EffieResponseOptions, FnKind, FnModule, FnModuleLoader, FnUrlBuilder, type ImageResponseOptions, annieResponse, effieResponse, fnModule, fnModuleExists, fnModuleIds, fnUrl, imageResponse, initFnRuntime };
66
+ export { type AnnieResponseOptions, Bounds, type EffieResponseOptions, FnKind, FnModule, FnModuleLoader, type FnRuntime, FnUrlBuilder, type ImageResponseOptions, annieResponse, createFnRuntime, effieResponse, fnModule, fnModuleExists, fnModuleIds, fnUrl, imageResponse, initFnRuntime };
package/dist/index.js CHANGED
@@ -2,45 +2,45 @@ import {
2
2
  annieResponse,
3
3
  effieResponse,
4
4
  imageResponse
5
- } from "./chunk-UHDIQDAF.js";
5
+ } from "./chunk-ANDDDI6X.js";
6
6
 
7
7
  // src/runtime.ts
8
- var moduleLoader = null;
9
- var urlBuilder = null;
10
- function initFnRuntime(config) {
11
- moduleLoader = config.moduleLoader;
12
- urlBuilder = config.urlBuilder;
8
+ function createFnRuntime(config) {
9
+ const { moduleLoader, urlBuilder } = config;
10
+ return {
11
+ fnModule: (kind, id) => moduleLoader.loadModule(kind, id),
12
+ fnUrl: (kind, id, props, bounds) => urlBuilder.buildUrl(kind, id, props, bounds),
13
+ fnModuleIds: (kind) => moduleLoader.listModules(kind),
14
+ fnModuleExists: (kind, id) => moduleLoader.hasModule(kind, id)
15
+ };
13
16
  }
14
- function getModuleLoader() {
15
- if (!moduleLoader) {
16
- throw new Error(
17
- "attempting to access module loader before initFnRuntime() was called"
18
- );
19
- }
20
- return moduleLoader;
17
+ var globalRuntime = null;
18
+ function initFnRuntime(config) {
19
+ globalRuntime = createFnRuntime(config);
21
20
  }
22
- function getUrlBuilder() {
23
- if (!urlBuilder) {
21
+ function requireGlobalRuntime(subject) {
22
+ if (!globalRuntime) {
24
23
  throw new Error(
25
- "attempting to access URL builder before initFnRuntime() was called"
24
+ `attempting to access ${subject} before initFnRuntime() was called`
26
25
  );
27
26
  }
28
- return urlBuilder;
27
+ return globalRuntime;
29
28
  }
30
29
  function fnModule(kind, id) {
31
- return getModuleLoader().loadModule(kind, id);
30
+ return requireGlobalRuntime("module loader").fnModule(kind, id);
32
31
  }
33
32
  function fnUrl(kind, id, props, bounds) {
34
- return getUrlBuilder().buildUrl(kind, id, props, bounds);
33
+ return requireGlobalRuntime("URL builder").fnUrl(kind, id, props, bounds);
35
34
  }
36
35
  function fnModuleIds(kind) {
37
- return getModuleLoader().listModules(kind);
36
+ return requireGlobalRuntime("module loader").fnModuleIds(kind);
38
37
  }
39
38
  function fnModuleExists(kind, id) {
40
- return getModuleLoader().hasModule(kind, id);
39
+ return requireGlobalRuntime("module loader").fnModuleExists(kind, id);
41
40
  }
42
41
  export {
43
42
  annieResponse,
43
+ createFnRuntime,
44
44
  effieResponse,
45
45
  fnModule,
46
46
  fnModuleExists,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["import type { EffieWebUrl } from \"@effing/effie\";\nimport type {\n Bounds,\n FnKind,\n FnModule,\n FnModuleLoader,\n FnUrlBuilder,\n} from \"./types\";\n\nlet moduleLoader: FnModuleLoader | null = null;\nlet urlBuilder: FnUrlBuilder | null = null;\n\nexport function initFnRuntime(config: {\n moduleLoader: FnModuleLoader;\n urlBuilder: FnUrlBuilder;\n}): void {\n moduleLoader = config.moduleLoader;\n urlBuilder = config.urlBuilder;\n}\n\nfunction getModuleLoader(): FnModuleLoader {\n if (!moduleLoader) {\n throw new Error(\n \"attempting to access module loader before initFnRuntime() was called\",\n );\n }\n return moduleLoader;\n}\n\nfunction getUrlBuilder(): FnUrlBuilder {\n if (!urlBuilder) {\n throw new Error(\n \"attempting to access URL builder before initFnRuntime() was called\",\n );\n }\n return urlBuilder;\n}\n\nexport function fnModule<K extends FnKind>(\n kind: K,\n id: string,\n): Promise<FnModule<K>> {\n return getModuleLoader().loadModule(kind, id);\n}\n\nexport function fnUrl<P extends Record<string, unknown>>(\n kind: FnKind,\n id: string,\n props: P,\n bounds: Bounds,\n): Promise<EffieWebUrl> {\n return getUrlBuilder().buildUrl(kind, id, props, bounds);\n}\n\nexport function fnModuleIds(kind: FnKind): string[] {\n return getModuleLoader().listModules(kind);\n}\n\nexport function fnModuleExists(kind: FnKind, id: string): boolean {\n return getModuleLoader().hasModule(kind, id);\n}\n"],"mappings":";;;;;;;AASA,IAAI,eAAsC;AAC1C,IAAI,aAAkC;AAE/B,SAAS,cAAc,QAGrB;AACP,iBAAe,OAAO;AACtB,eAAa,OAAO;AACtB;AAEA,SAAS,kBAAkC;AACzC,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAA8B;AACrC,MAAI,CAAC,YAAY;AACf,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,SACd,MACA,IACsB;AACtB,SAAO,gBAAgB,EAAE,WAAW,MAAM,EAAE;AAC9C;AAEO,SAAS,MACd,MACA,IACA,OACA,QACsB;AACtB,SAAO,cAAc,EAAE,SAAS,MAAM,IAAI,OAAO,MAAM;AACzD;AAEO,SAAS,YAAY,MAAwB;AAClD,SAAO,gBAAgB,EAAE,YAAY,IAAI;AAC3C;AAEO,SAAS,eAAe,MAAc,IAAqB;AAChE,SAAO,gBAAgB,EAAE,UAAU,MAAM,EAAE;AAC7C;","names":[]}
1
+ {"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["import type { EffieWebUrl } from \"@effing/effie\";\nimport type {\n Bounds,\n FnKind,\n FnModule,\n FnModuleLoader,\n FnUrlBuilder,\n} from \"./types\";\n\n/**\n * A self-contained fn runtime: the module loader and URL builder are captured\n * in the handle instead of living in module-global state, so multiple\n * runtimes with different configurations can coexist in one process.\n */\nexport interface FnRuntime {\n /** Load an fn module of the given kind by id. */\n fnModule<K extends FnKind>(kind: K, id: string): Promise<FnModule<K>>;\n /** Build a signed URL pointing at another fn's output. */\n fnUrl<P extends Record<string, unknown>>(\n kind: FnKind,\n id: string,\n props: P,\n bounds: Bounds,\n ): Promise<EffieWebUrl>;\n /** List the ids of all fn modules of the given kind. */\n fnModuleIds(kind: FnKind): string[];\n /** Check whether an fn module of the given kind exists. */\n fnModuleExists(kind: FnKind, id: string): boolean;\n}\n\n/**\n * Create an explicit fn runtime handle bound to the given module loader and\n * URL builder. Unlike {@link initFnRuntime}, this involves no global state:\n * each handle resolves through its own loader/builder, so independent\n * runtimes can be used side by side (e.g. in parallel tests or multi-tenant\n * servers).\n */\nexport function createFnRuntime(config: {\n moduleLoader: FnModuleLoader;\n urlBuilder: FnUrlBuilder;\n}): FnRuntime {\n const { moduleLoader, urlBuilder } = config;\n return {\n fnModule: (kind, id) => moduleLoader.loadModule(kind, id),\n fnUrl: (kind, id, props, bounds) =>\n urlBuilder.buildUrl(kind, id, props, bounds),\n fnModuleIds: (kind) => moduleLoader.listModules(kind),\n fnModuleExists: (kind, id) => moduleLoader.hasModule(kind, id),\n };\n}\n\nlet globalRuntime: FnRuntime | null = null;\n\n/**\n * Initialize the process-global fn runtime used by the standalone\n * {@link fnModule}, {@link fnUrl}, {@link fnModuleIds} and\n * {@link fnModuleExists} functions. This is a thin shim over\n * {@link createFnRuntime}; prefer an explicit runtime handle when more than\n * one configuration must coexist in a process.\n */\nexport function initFnRuntime(config: {\n moduleLoader: FnModuleLoader;\n urlBuilder: FnUrlBuilder;\n}): void {\n globalRuntime = createFnRuntime(config);\n}\n\nfunction requireGlobalRuntime(subject: string): FnRuntime {\n if (!globalRuntime) {\n throw new Error(\n `attempting to access ${subject} before initFnRuntime() was called`,\n );\n }\n return globalRuntime;\n}\n\nexport function fnModule<K extends FnKind>(\n kind: K,\n id: string,\n): Promise<FnModule<K>> {\n return requireGlobalRuntime(\"module loader\").fnModule(kind, id);\n}\n\nexport function fnUrl<P extends Record<string, unknown>>(\n kind: FnKind,\n id: string,\n props: P,\n bounds: Bounds,\n): Promise<EffieWebUrl> {\n return requireGlobalRuntime(\"URL builder\").fnUrl(kind, id, props, bounds);\n}\n\nexport function fnModuleIds(kind: FnKind): string[] {\n return requireGlobalRuntime(\"module loader\").fnModuleIds(kind);\n}\n\nexport function fnModuleExists(kind: FnKind, id: string): boolean {\n return requireGlobalRuntime(\"module loader\").fnModuleExists(kind, id);\n}\n"],"mappings":";;;;;;;AAqCO,SAAS,gBAAgB,QAGlB;AACZ,QAAM,EAAE,cAAc,WAAW,IAAI;AACrC,SAAO;AAAA,IACL,UAAU,CAAC,MAAM,OAAO,aAAa,WAAW,MAAM,EAAE;AAAA,IACxD,OAAO,CAAC,MAAM,IAAI,OAAO,WACvB,WAAW,SAAS,MAAM,IAAI,OAAO,MAAM;AAAA,IAC7C,aAAa,CAAC,SAAS,aAAa,YAAY,IAAI;AAAA,IACpD,gBAAgB,CAAC,MAAM,OAAO,aAAa,UAAU,MAAM,EAAE;AAAA,EAC/D;AACF;AAEA,IAAI,gBAAkC;AAS/B,SAAS,cAAc,QAGrB;AACP,kBAAgB,gBAAgB,MAAM;AACxC;AAEA,SAAS,qBAAqB,SAA4B;AACxD,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI;AAAA,MACR,wBAAwB,OAAO;AAAA,IACjC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,SACd,MACA,IACsB;AACtB,SAAO,qBAAqB,eAAe,EAAE,SAAS,MAAM,EAAE;AAChE;AAEO,SAAS,MACd,MACA,IACA,OACA,QACsB;AACtB,SAAO,qBAAqB,aAAa,EAAE,MAAM,MAAM,IAAI,OAAO,MAAM;AAC1E;AAEO,SAAS,YAAY,MAAwB;AAClD,SAAO,qBAAqB,eAAe,EAAE,YAAY,IAAI;AAC/D;AAEO,SAAS,eAAe,MAAc,IAAqB;AAChE,SAAO,qBAAqB,eAAe,EAAE,eAAe,MAAM,EAAE;AACtE;","names":[]}
@@ -1,4 +1,4 @@
1
- import { B as Bounds, b as FnKind, a as FnUrlBuilder, F as FnModuleLoader } from '../types-8Q-DJL6t.js';
1
+ import { B as Bounds, F as FnKind, c as FnUrlBuilder, b as FnModuleLoader } from '../types-CFYPy7AY.js';
2
2
  import { ServerResponse, RequestListener } from 'node:http';
3
3
  import 'zod';
4
4
  import '@effing/effie';
@@ -2,7 +2,7 @@ import {
2
2
  annieResponse,
3
3
  effieResponse,
4
4
  imageResponse
5
- } from "../chunk-UHDIQDAF.js";
5
+ } from "../chunk-ANDDDI6X.js";
6
6
 
7
7
  // src/server/segments.ts
8
8
  import { deserialize, serialize } from "@effing/serde";
@@ -36,4 +36,4 @@ type FnUrlBuilder = {
36
36
  buildUrl<P extends Record<string, unknown>>(kind: FnKind, id: string, props: P, bounds: Bounds): Promise<EffieWebUrl>;
37
37
  };
38
38
 
39
- export type { AnnieRunnerReturn as A, Bounds as B, EffieRunnerReturn as E, FnModuleLoader as F, ImageRunnerReturn as I, RunnerArgs as R, FnUrlBuilder as a, FnKind as b, FnModule as c, ImageFnModule as d, AnnieFnModule as e, EffieFnModule as f };
39
+ export type { AnnieRunnerReturn as A, Bounds as B, EffieRunnerReturn as E, FnKind as F, ImageRunnerReturn as I, RunnerArgs as R, FnModule as a, FnModuleLoader as b, FnUrlBuilder as c, ImageFnModule as d, AnnieFnModule as e, EffieFnModule as f };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effing/fn",
3
- "version": "0.38.4",
3
+ "version": "0.40.0",
4
4
  "description": "Effing function runtime — pluggable module loading and URL building",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,9 +22,9 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@effing/annie": "0.38.4",
26
- "@effing/effie": "0.38.4",
27
- "@effing/serde": "0.38.4"
25
+ "@effing/annie": "0.40.0",
26
+ "@effing/effie": "0.40.0",
27
+ "@effing/serde": "0.40.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "tsup": "^8.0.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/responses.ts"],"sourcesContent":["import type { EffieData, EffieSources } from \"@effing/effie\";\nimport { annieStream } from \"@effing/annie\";\nimport type { AnnieStreamOptions } from \"@effing/annie\";\n\nexport type ImageResponseOptions = {\n headers?: HeadersInit;\n cacheControl?: string;\n};\n\nfunction detectImageContentType(bytes: Uint8Array): string {\n if (bytes[0] === 0x89 && bytes[1] === 0x50) return \"image/png\";\n if (bytes[0] === 0xff && bytes[1] === 0xd8) return \"image/jpeg\";\n throw new Error(\"Unsupported image format: expected PNG or JPEG\");\n}\n\nexport function imageResponse(\n bytes: Uint8Array,\n options: ImageResponseOptions = {},\n): Response {\n const { headers: extraHeaders, cacheControl = \"public, max-age=3600\" } =\n options;\n\n const headers = new Headers(extraHeaders);\n headers.set(\"Content-Type\", detectImageContentType(bytes));\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n\n if (!(bytes.buffer instanceof ArrayBuffer)) {\n throw new TypeError(\"SharedArrayBuffer is not supported\");\n }\n\n return new Response(bytes.buffer, { status: 200, headers });\n}\n\nexport type AnnieResponseOptions = AnnieStreamOptions & {\n headers?: HeadersInit;\n cacheControl?: string;\n filename?: string;\n};\n\nexport function annieResponse(\n frames: AsyncIterable<Buffer>,\n options: AnnieResponseOptions = {},\n): Response {\n const {\n headers: extraHeaders,\n cacheControl = \"public, max-age=3600\",\n filename,\n ...streamOptions\n } = options;\n\n const stream = annieStream(frames, streamOptions);\n\n const headers = new Headers(extraHeaders);\n headers.set(\"Content-Type\", \"application/x-tar\");\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n if (filename) {\n headers.set(\"Content-Disposition\", `inline; filename=\"${filename}.tar\"`);\n }\n\n return new Response(stream, { status: 200, headers });\n}\n\nexport type EffieResponseOptions = {\n headers?: HeadersInit;\n cacheControl?: string;\n};\n\nexport function effieResponse<S extends EffieSources>(\n data: EffieData<S>,\n options: EffieResponseOptions = {},\n): Response {\n const { headers: extraHeaders, cacheControl = \"public, max-age=3600\" } =\n options;\n\n const headers = new Headers(extraHeaders);\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n\n return Response.json(data, { status: 200, headers });\n}\n"],"mappings":";AACA,SAAS,mBAAmB;AAQ5B,SAAS,uBAAuB,OAA2B;AACzD,MAAI,MAAM,CAAC,MAAM,OAAQ,MAAM,CAAC,MAAM,GAAM,QAAO;AACnD,MAAI,MAAM,CAAC,MAAM,OAAQ,MAAM,CAAC,MAAM,IAAM,QAAO;AACnD,QAAM,IAAI,MAAM,gDAAgD;AAClE;AAEO,SAAS,cACd,OACA,UAAgC,CAAC,GACvB;AACV,QAAM,EAAE,SAAS,cAAc,eAAe,uBAAuB,IACnE;AAEF,QAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,UAAQ,IAAI,gBAAgB,uBAAuB,KAAK,CAAC;AACzD,MAAI,cAAc;AAChB,YAAQ,IAAI,iBAAiB,YAAY;AAAA,EAC3C;AAEA,MAAI,EAAE,MAAM,kBAAkB,cAAc;AAC1C,UAAM,IAAI,UAAU,oCAAoC;AAAA,EAC1D;AAEA,SAAO,IAAI,SAAS,MAAM,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAC;AAC5D;AAQO,SAAS,cACd,QACA,UAAgC,CAAC,GACvB;AACV,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,SAAS,YAAY,QAAQ,aAAa;AAEhD,QAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,UAAQ,IAAI,gBAAgB,mBAAmB;AAC/C,MAAI,cAAc;AAChB,YAAQ,IAAI,iBAAiB,YAAY;AAAA,EAC3C;AACA,MAAI,UAAU;AACZ,YAAQ,IAAI,uBAAuB,qBAAqB,QAAQ,OAAO;AAAA,EACzE;AAEA,SAAO,IAAI,SAAS,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAC;AACtD;AAOO,SAAS,cACd,MACA,UAAgC,CAAC,GACvB;AACV,QAAM,EAAE,SAAS,cAAc,eAAe,uBAAuB,IACnE;AAEF,QAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,MAAI,cAAc;AAChB,YAAQ,IAAI,iBAAiB,YAAY;AAAA,EAC3C;AAEA,SAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,QAAQ,CAAC;AACrD;","names":[]}