@nyte-ai/host 0.0.0-stage → 0.0.19

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 (250) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -2
  3. package/THIRD-PARTY-NOTICES.md +866 -0
  4. package/dist/chunks/canvas-preview-0cmbkp2j.js +65 -0
  5. package/dist/chunks/canvas-preview-0nq75h9k.js +7 -0
  6. package/dist/chunks/canvas-preview-11nadadc.js +241 -0
  7. package/dist/chunks/canvas-preview-1sq7z9jq.js +17 -0
  8. package/dist/chunks/canvas-preview-2jwbe14k.js +130 -0
  9. package/dist/chunks/canvas-preview-2zdyh9ny.js +26 -0
  10. package/dist/chunks/canvas-preview-31w7xm8z.js +34 -0
  11. package/dist/chunks/canvas-preview-4b6sayhg.js +295 -0
  12. package/dist/chunks/canvas-preview-4e0pxa32.js +63 -0
  13. package/dist/chunks/canvas-preview-518dh8by.js +169 -0
  14. package/dist/chunks/canvas-preview-55s0y68g.js +387 -0
  15. package/dist/chunks/canvas-preview-5ekjx6sw.js +613 -0
  16. package/dist/chunks/canvas-preview-5mex725c.js +14 -0
  17. package/dist/chunks/canvas-preview-5z63am63.js +295 -0
  18. package/dist/chunks/canvas-preview-65xqjw7f.js +20 -0
  19. package/dist/chunks/canvas-preview-69fkk9yn.js +95 -0
  20. package/dist/chunks/canvas-preview-8xc0vn7v.js +458 -0
  21. package/dist/chunks/canvas-preview-9aqczacs.js +73 -0
  22. package/dist/chunks/canvas-preview-af86jz8t.js +141 -0
  23. package/dist/chunks/canvas-preview-aq5j4p25.js +240 -0
  24. package/dist/chunks/canvas-preview-b2v8wfnz.js +36 -0
  25. package/dist/chunks/canvas-preview-befkjea2.js +60 -0
  26. package/dist/chunks/canvas-preview-bxnqt8cd.js +103 -0
  27. package/dist/chunks/canvas-preview-cawy6vbz.js +352 -0
  28. package/dist/chunks/canvas-preview-crmzxxt8.js +518 -0
  29. package/dist/chunks/canvas-preview-drctegz4.js +591 -0
  30. package/dist/chunks/canvas-preview-e3vnkkc5.js +134 -0
  31. package/dist/chunks/canvas-preview-ec2mt7es.js +108 -0
  32. package/dist/chunks/canvas-preview-fxa0rfb0.js +61 -0
  33. package/dist/chunks/canvas-preview-g5fkjs34.js +598 -0
  34. package/dist/chunks/canvas-preview-jeddjex8.js +166 -0
  35. package/dist/chunks/canvas-preview-k1yg4fgp.js +571 -0
  36. package/dist/chunks/canvas-preview-kdqgrstc.js +194 -0
  37. package/dist/chunks/canvas-preview-kn7kvbfj.js +12 -0
  38. package/dist/chunks/canvas-preview-kp75gb63.js +141 -0
  39. package/dist/chunks/canvas-preview-mgcx2b2p.js +271 -0
  40. package/dist/chunks/canvas-preview-n2a35zv5.js +81 -0
  41. package/dist/chunks/canvas-preview-pkzqg96v.js +63 -0
  42. package/dist/chunks/canvas-preview-rp4x6y1h.js +144 -0
  43. package/dist/chunks/canvas-preview-s94ebwf5.js +112 -0
  44. package/dist/chunks/canvas-preview-skzwvw4d.js +23 -0
  45. package/dist/chunks/canvas-preview-srgfpdmf.js +60 -0
  46. package/dist/chunks/canvas-preview-tjhabynd.js +252 -0
  47. package/dist/chunks/canvas-preview-tnqe7k0b.js +374 -0
  48. package/dist/chunks/canvas-preview-vaatfznm.js +189 -0
  49. package/dist/chunks/canvas-preview-vm9zdp2t.js +398 -0
  50. package/dist/chunks/canvas-preview-w54ymtb3.js +272 -0
  51. package/dist/chunks/canvas-preview-wg80rbc2.js +46 -0
  52. package/dist/chunks/canvas-preview-y5y6ghaw.js +125 -0
  53. package/dist/chunks/canvas-preview-ycepb05s.js +176 -0
  54. package/dist/chunks/canvas-preview-yjz0f7n4.js +50 -0
  55. package/dist/chunks/canvas-preview-zaaj99wd.js +244 -0
  56. package/dist/src/canvas-preview.d.ts +29 -0
  57. package/dist/src/canvas-preview.js +271 -0
  58. package/dist/src/credentials.d.ts +44 -0
  59. package/dist/src/credentials.js +10 -0
  60. package/dist/src/deploy/cloudflare/worker.d.ts +50 -0
  61. package/dist/src/deploy/cloudflare/worker.js +196 -0
  62. package/dist/src/deploy/vercel/nitro.config.d.ts +2 -0
  63. package/dist/src/deploy/vercel/nitro.config.js +30 -0
  64. package/dist/src/deploy/vercel/server/routes/[...].d.ts +2 -0
  65. package/dist/src/deploy/vercel/server/routes/[...].js +18 -0
  66. package/dist/src/deploy/vercel/server/utils/host.d.ts +13 -0
  67. package/dist/src/deploy/vercel/server/utils/host.js +7 -0
  68. package/dist/src/deploy/vercel/server/utils/repair.d.ts +1 -0
  69. package/dist/src/deploy/vercel/server/utils/repair.js +6 -0
  70. package/dist/src/deploy/vercel/server/utils/step.d.ts +10 -0
  71. package/dist/src/deploy/vercel/server/utils/step.js +6 -0
  72. package/dist/src/deploy/vercel/server/workflows/drive.d.ts +14 -0
  73. package/dist/src/deploy/vercel/server/workflows/drive.js +13 -0
  74. package/dist/src/durable-object.d.ts +14 -0
  75. package/dist/src/durable-object.js +231 -0
  76. package/dist/src/hash.d.ts +1 -0
  77. package/dist/src/hash.js +6 -0
  78. package/dist/src/identity-key.d.ts +11 -0
  79. package/dist/src/identity-key.js +9 -0
  80. package/dist/src/identity.d.ts +12 -0
  81. package/dist/src/identity.js +6 -0
  82. package/dist/src/images/exif.d.ts +1 -0
  83. package/dist/src/images/exif.js +6 -0
  84. package/dist/src/images/node.d.ts +37 -0
  85. package/dist/src/images/node.js +12 -0
  86. package/dist/src/images/photon.d.ts +3 -0
  87. package/dist/src/images/photon.js +7 -0
  88. package/dist/src/images/worker.d.ts +1 -0
  89. package/dist/src/images/worker.js +23 -0
  90. package/dist/src/index.d.ts +20 -0
  91. package/dist/src/index.js +121 -0
  92. package/dist/src/key-file.d.ts +1 -0
  93. package/dist/src/key-file.js +7 -0
  94. package/dist/src/listen-fetch.d.ts +8 -0
  95. package/dist/src/listen-fetch.js +9 -0
  96. package/dist/src/listen.d.ts +4 -0
  97. package/dist/src/listen.js +10 -0
  98. package/dist/src/local/command.d.ts +20 -0
  99. package/dist/src/local/command.js +12 -0
  100. package/dist/src/local/feed.d.ts +7 -0
  101. package/dist/src/local/feed.js +6 -0
  102. package/dist/src/local/files.d.ts +18 -0
  103. package/dist/src/local/files.js +13 -0
  104. package/dist/src/local/git-watch.d.ts +15 -0
  105. package/dist/src/local/git-watch.js +7 -0
  106. package/dist/src/local/git.d.ts +5 -0
  107. package/dist/src/local/git.js +13 -0
  108. package/dist/src/local/github.d.ts +30 -0
  109. package/dist/src/local/github.js +9 -0
  110. package/dist/src/local/identity.d.ts +3 -0
  111. package/dist/src/local/identity.js +7 -0
  112. package/dist/src/local/jobs.d.ts +7 -0
  113. package/dist/src/local/jobs.js +7 -0
  114. package/dist/src/local/legacy-trust.d.ts +10 -0
  115. package/dist/src/local/legacy-trust.js +6 -0
  116. package/dist/src/local/patch.d.ts +16 -0
  117. package/dist/src/local/patch.js +17 -0
  118. package/dist/src/local/provider.d.ts +11 -0
  119. package/dist/src/local/provider.js +20 -0
  120. package/dist/src/local/snapshots.d.ts +7 -0
  121. package/dist/src/local/snapshots.js +11 -0
  122. package/dist/src/local/text.d.ts +1 -0
  123. package/dist/src/local/text.js +6 -0
  124. package/dist/src/local/tree.d.ts +50 -0
  125. package/dist/src/local/tree.js +16 -0
  126. package/dist/src/local/workspace-migration.d.ts +2 -0
  127. package/dist/src/local/workspace-migration.js +7 -0
  128. package/dist/src/local/worktrees.d.ts +46 -0
  129. package/dist/src/local/worktrees.js +14 -0
  130. package/dist/src/mcp/config.d.ts +75 -0
  131. package/dist/src/mcp/config.js +12 -0
  132. package/dist/src/mcp/connect.d.ts +15 -0
  133. package/dist/src/mcp/connect.js +9 -0
  134. package/dist/src/mcp/hub.d.ts +19 -0
  135. package/dist/src/mcp/hub.js +11 -0
  136. package/dist/src/mcp/oauth.d.ts +46 -0
  137. package/dist/src/mcp/oauth.js +12 -0
  138. package/dist/src/mcp/tools.d.ts +29 -0
  139. package/dist/src/mcp/tools.js +12 -0
  140. package/dist/src/open.d.ts +14 -0
  141. package/dist/src/open.js +46 -0
  142. package/dist/src/plugins/loader.d.ts +21 -0
  143. package/dist/src/plugins/loader.js +11 -0
  144. package/dist/src/postgres.d.ts +19 -0
  145. package/dist/src/postgres.js +8 -0
  146. package/dist/src/providers.d.ts +16 -0
  147. package/dist/src/providers.js +112 -0
  148. package/dist/src/secrets.d.ts +12 -0
  149. package/dist/src/secrets.js +8 -0
  150. package/dist/src/serve/binding.d.ts +39 -0
  151. package/dist/src/serve/binding.js +6 -0
  152. package/dist/src/serve/handler.d.ts +15 -0
  153. package/dist/src/serve/handler.js +8 -0
  154. package/dist/src/serve/stream-server.d.ts +6 -0
  155. package/dist/src/serve/stream-server.js +6 -0
  156. package/dist/src/session-index.d.ts +11 -0
  157. package/dist/src/session-index.js +11 -0
  158. package/dist/src/shell-env.d.ts +14 -0
  159. package/dist/src/shell-env.js +108 -0
  160. package/dist/src/sqlite-workers.d.ts +6 -0
  161. package/dist/src/sqlite-workers.js +6 -0
  162. package/dist/src/sqlite.d.ts +8 -0
  163. package/dist/src/sqlite.js +11 -0
  164. package/dist/src/store-rows.d.ts +13 -0
  165. package/dist/src/store-rows.js +26 -0
  166. package/dist/src/store-usage.d.ts +25 -0
  167. package/dist/src/store-usage.js +19 -0
  168. package/dist/src/usage-history.d.ts +54 -0
  169. package/dist/src/usage-history.js +14 -0
  170. package/dist/src/usage-scan.d.ts +24 -0
  171. package/dist/src/usage-scan.js +65 -0
  172. package/dist/src/usage-service.d.ts +23 -0
  173. package/dist/src/usage-service.js +16 -0
  174. package/dist/src/usage-summary.d.ts +9 -0
  175. package/dist/src/usage-summary.js +16 -0
  176. package/dist/src/usage-types.d.ts +86 -0
  177. package/dist/src/usage-types.js +0 -0
  178. package/dist/src/usage-worker.d.ts +1 -0
  179. package/dist/src/usage-worker.js +29 -0
  180. package/dist/src/usage.d.ts +195 -0
  181. package/dist/src/usage.js +23 -0
  182. package/package.json +140 -3
  183. package/src/canvas-preview.ts +403 -0
  184. package/src/credentials.ts +294 -0
  185. package/src/deploy/cloudflare/README.md +3 -0
  186. package/src/deploy/cloudflare/worker.ts +306 -0
  187. package/src/deploy/cloudflare/wrangler.jsonc +12 -0
  188. package/src/deploy/vercel/README.md +3 -0
  189. package/src/deploy/vercel/nitro.config.ts +29 -0
  190. package/src/deploy/vercel/server/routes/[...].ts +10 -0
  191. package/src/deploy/vercel/server/utils/host.ts +104 -0
  192. package/src/deploy/vercel/server/utils/repair.ts +35 -0
  193. package/src/deploy/vercel/server/utils/step.ts +25 -0
  194. package/src/deploy/vercel/server/workflows/drive.ts +46 -0
  195. package/src/deploy/vercel/tsconfig.json +9 -0
  196. package/src/deploy/vercel/types/bun.d.ts +2 -0
  197. package/src/durable-object.ts +386 -0
  198. package/src/hash.ts +5 -0
  199. package/src/identity-key.ts +20 -0
  200. package/src/identity.ts +66 -0
  201. package/src/images/exif.ts +69 -0
  202. package/src/images/node.ts +163 -0
  203. package/src/images/photon.ts +141 -0
  204. package/src/images/worker.ts +29 -0
  205. package/src/index.ts +39 -0
  206. package/src/key-file.ts +53 -0
  207. package/src/listen-fetch.ts +409 -0
  208. package/src/listen.ts +228 -0
  209. package/src/local/command.ts +161 -0
  210. package/src/local/feed.ts +70 -0
  211. package/src/local/files.ts +817 -0
  212. package/src/local/git-watch.ts +199 -0
  213. package/src/local/git.ts +919 -0
  214. package/src/local/github.ts +691 -0
  215. package/src/local/identity.ts +21 -0
  216. package/src/local/jobs.ts +573 -0
  217. package/src/local/legacy-trust.ts +105 -0
  218. package/src/local/patch.ts +334 -0
  219. package/src/local/provider.ts +184 -0
  220. package/src/local/snapshots.ts +778 -0
  221. package/src/local/text.ts +9 -0
  222. package/src/local/tree.ts +398 -0
  223. package/src/local/workspace-migration.ts +95 -0
  224. package/src/local/worktrees.ts +239 -0
  225. package/src/mcp/config.ts +330 -0
  226. package/src/mcp/connect.ts +92 -0
  227. package/src/mcp/hub.ts +836 -0
  228. package/src/mcp/oauth.ts +436 -0
  229. package/src/mcp/tools.ts +333 -0
  230. package/src/open.ts +449 -0
  231. package/src/plugins/loader.ts +186 -0
  232. package/src/postgres.ts +492 -0
  233. package/src/providers.ts +135 -0
  234. package/src/secrets.ts +31 -0
  235. package/src/serve/binding.ts +629 -0
  236. package/src/serve/handler.ts +362 -0
  237. package/src/serve/stream-server.ts +176 -0
  238. package/src/session-index.ts +99 -0
  239. package/src/shell-env.ts +153 -0
  240. package/src/sqlite-workers.ts +283 -0
  241. package/src/sqlite.ts +553 -0
  242. package/src/store-rows.ts +110 -0
  243. package/src/store-usage.ts +347 -0
  244. package/src/usage-history.ts +219 -0
  245. package/src/usage-scan.ts +81 -0
  246. package/src/usage-service.ts +82 -0
  247. package/src/usage-summary.ts +79 -0
  248. package/src/usage-types.ts +87 -0
  249. package/src/usage-worker.ts +24 -0
  250. package/src/usage.ts +776 -0
@@ -0,0 +1,163 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { fileURLToPath } from "node:url";
3
+ import { Worker } from "node:worker_threads";
4
+ import type { ImageLimits, ImageProcessor, PreparedImage } from "@nyte-ai/core";
5
+ import { Type } from "typebox";
6
+ import { Value } from "typebox/value";
7
+ import { photonImages } from "./photon.ts";
8
+
9
+ export interface NodeImagesOptions {
10
+ readonly worker?: string | URL;
11
+ readonly wasm?: string;
12
+ }
13
+
14
+ export interface PrepareRequest {
15
+ readonly id: number;
16
+ readonly bytes: Uint8Array;
17
+ readonly mimeType: string;
18
+ readonly limits: ImageLimits;
19
+ }
20
+
21
+ const size = Type.Object({ width: Type.Number(), height: Type.Number() });
22
+
23
+ export const prepareReply = Type.Union([
24
+ Type.Object({ id: Type.Integer(), result: Type.Null() }),
25
+ Type.Object({
26
+ id: Type.Integer(),
27
+ result: Type.Object({
28
+ data: Type.String(),
29
+ mimeType: Type.String(),
30
+ resized: Type.Optional(Type.Object({ from: size, to: size })),
31
+ }),
32
+ }),
33
+ Type.Object({ id: Type.Integer(), error: Type.String() }),
34
+ ]);
35
+
36
+ const IDLE_MS = 30_000;
37
+
38
+ export function nodeImages(options: NodeImagesOptions = {}): ImageProcessor {
39
+ const worker =
40
+ options.worker ??
41
+ new URL(import.meta.url.endsWith(".ts") ? "./worker.ts" : "./worker.js", import.meta.url);
42
+
43
+ let wasm: Promise<Uint8Array> | undefined;
44
+
45
+ const loadWasm = (): Promise<Uint8Array> =>
46
+ (wasm ??= readFile(options.wasm ?? resolvePhotonWasmPath()));
47
+
48
+ let thread: PhotonThread | undefined;
49
+ let inProcess: ImageProcessor | undefined;
50
+
51
+ return {
52
+ async prepare(bytes, mimeType, limits) {
53
+ if (inProcess !== undefined) return inProcess.prepare(bytes, mimeType, limits);
54
+ const module = await loadWasm();
55
+
56
+ try {
57
+ thread ??= new PhotonThread(worker, module, (ended) => {
58
+ if (thread === ended) thread = undefined;
59
+ });
60
+
61
+ return await thread.prepare(bytes, mimeType, limits);
62
+ } catch (cause) {
63
+ if (!(cause instanceof WorkerUnavailable)) throw cause;
64
+ inProcess ??= photonImages(module);
65
+
66
+ return inProcess.prepare(bytes, mimeType, limits);
67
+ }
68
+ },
69
+ };
70
+ }
71
+
72
+ export function resolvePhotonWasmPath(): string {
73
+ return fileURLToPath(import.meta.resolve("@silvia-odwyer/photon/photon_rs_bg.wasm"));
74
+ }
75
+
76
+ class WorkerUnavailable extends Error {}
77
+
78
+ class PhotonThread {
79
+ readonly #worker: Worker;
80
+ readonly #pending = new Map<number, PromiseWithResolvers<PreparedImage | undefined>>();
81
+ readonly #onExit: (ended: PhotonThread) => void;
82
+ #nextId = 0;
83
+ #idle: ReturnType<typeof setTimeout> | undefined;
84
+ #started = false;
85
+
86
+ constructor(entry: string | URL, wasm: Uint8Array, onExit: (ended: PhotonThread) => void) {
87
+ this.#onExit = onExit;
88
+
89
+ try {
90
+ this.#worker = new Worker(entry, { workerData: wasm });
91
+ } catch (cause) {
92
+ throw new WorkerUnavailable("The image worker cannot start", { cause });
93
+ }
94
+
95
+ this.#worker.on("message", (reply: unknown) => {
96
+ if (!Value.Check(prepareReply, reply)) {
97
+ this.#fail(new Error("Malformed image worker reply"));
98
+ void this.#worker.terminate();
99
+
100
+ return;
101
+ }
102
+
103
+ this.#started = true;
104
+ const request = this.#pending.get(reply.id);
105
+
106
+ if (request === undefined) return;
107
+ this.#pending.delete(reply.id);
108
+
109
+ if ("error" in reply) request.reject(new Error(reply.error));
110
+ else request.resolve(reply.result ?? undefined);
111
+ this.#settled();
112
+ });
113
+
114
+ this.#worker.on("error", (cause) => this.#fail(cause));
115
+
116
+ this.#worker.on("exit", (code) =>
117
+ this.#fail(new Error(`The image worker exited with code ${String(code)}`)),
118
+ );
119
+ }
120
+
121
+ prepare(
122
+ bytes: Uint8Array,
123
+ mimeType: string,
124
+ limits: ImageLimits,
125
+ ): Promise<PreparedImage | undefined> {
126
+ const id = this.#nextId++;
127
+ const request = Promise.withResolvers<PreparedImage | undefined>();
128
+ this.#pending.set(id, request);
129
+ clearTimeout(this.#idle);
130
+ this.#idle = undefined;
131
+ this.#worker.ref();
132
+ const copy = bytes.slice();
133
+
134
+ this.#worker.postMessage({ id, bytes: copy, mimeType, limits } satisfies PrepareRequest, [
135
+ copy.buffer,
136
+ ]);
137
+
138
+ return request.promise;
139
+ }
140
+
141
+ #settled(): void {
142
+ if (this.#pending.size > 0) return;
143
+ this.#worker.unref();
144
+
145
+ this.#idle = setTimeout(() => {
146
+ this.#onExit(this);
147
+ void this.#worker.terminate();
148
+ }, IDLE_MS);
149
+
150
+ this.#idle.unref();
151
+ }
152
+
153
+ #fail(cause: unknown): void {
154
+ const failure = this.#started
155
+ ? cause
156
+ : new WorkerUnavailable("The image worker cannot start", { cause });
157
+
158
+ for (const request of this.#pending.values()) request.reject(failure);
159
+ this.#pending.clear();
160
+ clearTimeout(this.#idle);
161
+ this.#onExit(this);
162
+ }
163
+ }
@@ -0,0 +1,141 @@
1
+ import {
2
+ PhotonImage,
3
+ SamplingFilter,
4
+ fliph,
5
+ flipv,
6
+ initSync,
7
+ resize,
8
+ } from "@silvia-odwyer/photon/photon_rs.js";
9
+ import type { SyncInitInput } from "@silvia-odwyer/photon/photon_rs.js";
10
+ import type { ImageLimits, ImageProcessor, PreparedImage } from "@nyte-ai/core";
11
+ import { exifOrientation } from "./exif.ts";
12
+
13
+ const INLINE_IMAGE_TYPES: ReadonlySet<string> = new Set([
14
+ "image/png",
15
+ "image/jpeg",
16
+ "image/gif",
17
+ "image/webp",
18
+ ]);
19
+
20
+ const JPEG_QUALITIES = [80, 70, 55, 40];
21
+
22
+ export function photonImages(wasm: SyncInitInput): ImageProcessor {
23
+ initSync({ module: wasm });
24
+
25
+ return {
26
+ prepare: (bytes, mimeType, limits) => Promise.resolve(prepare(bytes, mimeType, limits)),
27
+ };
28
+ }
29
+
30
+ function prepare(
31
+ bytes: Uint8Array,
32
+ mimeType: string,
33
+ limits: ImageLimits,
34
+ ): PreparedImage | undefined {
35
+ const orientation = exifOrientation(bytes);
36
+ let image: PhotonImage | undefined;
37
+
38
+ try {
39
+ image = PhotonImage.new_from_byteslice(bytes);
40
+
41
+ if (
42
+ INLINE_IMAGE_TYPES.has(mimeType) &&
43
+ orientation === 1 &&
44
+ image.get_width() <= limits.maxWidth &&
45
+ image.get_height() <= limits.maxHeight &&
46
+ base64Length(bytes.byteLength) <= limits.maxBase64Bytes
47
+ )
48
+ return { data: bytes.toBase64(), mimeType };
49
+
50
+ if (orientation >= 5) {
51
+ const upright = transposed(image, orientation);
52
+ image.free();
53
+ image = undefined;
54
+ image = new PhotonImage(upright.pixels, upright.width, upright.height);
55
+ } else if (orientation !== 1) {
56
+ if (orientation !== 4) fliph(image);
57
+
58
+ if (orientation !== 2) flipv(image);
59
+ }
60
+
61
+ const width = image.get_width();
62
+ const height = image.get_height();
63
+ const scale = Math.min(1, limits.maxWidth / width, limits.maxHeight / height);
64
+
65
+ let target = {
66
+ width: Math.max(1, Math.round(width * scale)),
67
+ height: Math.max(1, Math.round(height * scale)),
68
+ };
69
+
70
+ for (;;) {
71
+ const encoded = encodeWithin(image, target, limits.maxBase64Bytes, mimeType === "image/jpeg");
72
+
73
+ if (encoded !== undefined)
74
+ return target.width === width && target.height === height
75
+ ? encoded
76
+ : { ...encoded, resized: { from: { width, height }, to: target } };
77
+
78
+ if (target.width === 1 && target.height === 1) return undefined;
79
+ target = {
80
+ width: Math.max(1, Math.floor(target.width * 0.75)),
81
+ height: Math.max(1, Math.floor(target.height * 0.75)),
82
+ };
83
+ }
84
+ } catch {
85
+ return undefined;
86
+ } finally {
87
+ image?.free();
88
+ }
89
+ }
90
+
91
+ function encodeWithin(
92
+ image: PhotonImage,
93
+ size: { readonly width: number; readonly height: number },
94
+ maxBase64Bytes: number,
95
+ jpegFirst: boolean,
96
+ ): { readonly data: string; readonly mimeType: string } | undefined {
97
+ const same = size.width === image.get_width() && size.height === image.get_height();
98
+ const scaled = same ? image : resize(image, size.width, size.height, SamplingFilter.Lanczos3);
99
+
100
+ try {
101
+ const png = { mimeType: "image/png", encode: () => scaled.get_bytes() };
102
+
103
+ const jpegs = JPEG_QUALITIES.map((quality) => ({
104
+ mimeType: "image/jpeg",
105
+ encode: () => scaled.get_bytes_jpeg(quality),
106
+ }));
107
+
108
+ for (const candidate of jpegFirst ? [...jpegs, png] : [png, ...jpegs]) {
109
+ const encoded = candidate.encode();
110
+
111
+ if (base64Length(encoded.byteLength) <= maxBase64Bytes)
112
+ return { data: encoded.toBase64(), mimeType: candidate.mimeType };
113
+ }
114
+
115
+ return undefined;
116
+ } finally {
117
+ if (!same) scaled.free();
118
+ }
119
+ }
120
+
121
+ function transposed(image: PhotonImage, orientation: number) {
122
+ const width = image.get_width();
123
+ const height = image.get_height();
124
+ const source = image.get_raw_pixels();
125
+ const pixels = new Uint8Array(source.length);
126
+
127
+ for (let y = 0; y < height; y++) {
128
+ for (let x = 0; x < width; x++) {
129
+ const outX = orientation === 5 || orientation === 8 ? y : height - 1 - y;
130
+ const outY = orientation === 5 || orientation === 6 ? x : width - 1 - x;
131
+ const from = (y * width + x) * 4;
132
+ pixels.set(source.subarray(from, from + 4), (outY * height + outX) * 4);
133
+ }
134
+ }
135
+
136
+ return { pixels, width: height, height: width };
137
+ }
138
+
139
+ function base64Length(byteLength: number): number {
140
+ return Math.ceil(byteLength / 3) * 4;
141
+ }
@@ -0,0 +1,29 @@
1
+ import { parentPort, workerData } from "node:worker_threads";
2
+ import type { Static } from "typebox";
3
+ import type { PrepareRequest, prepareReply } from "./node.ts";
4
+ import { photonImages } from "./photon.ts";
5
+
6
+ const port = parentPort;
7
+
8
+ if (port === null) throw new Error("The image worker needs a parent thread");
9
+
10
+ const wasm: unknown = workerData;
11
+
12
+ if (!(wasm instanceof Uint8Array)) throw new Error("The image worker needs Photon's WebAssembly");
13
+
14
+ const images = photonImages(wasm);
15
+
16
+ port.on("message", (request: PrepareRequest) => {
17
+ void images.prepare(request.bytes, request.mimeType, request.limits).then(
18
+ (result) =>
19
+ port.postMessage({
20
+ id: request.id,
21
+ result: result ?? null,
22
+ } satisfies Static<typeof prepareReply>),
23
+ (cause: unknown) =>
24
+ port.postMessage({
25
+ id: request.id,
26
+ error: cause instanceof Error ? cause.message : String(cause),
27
+ } satisfies Static<typeof prepareReply>),
28
+ );
29
+ });
package/src/index.ts ADDED
@@ -0,0 +1,39 @@
1
+ export * from "./credentials.ts";
2
+
3
+ export * from "./identity.ts";
4
+
5
+ export { identitySigner } from "./identity-key.ts";
6
+
7
+ export * from "./listen.ts";
8
+
9
+ export * from "./listen-fetch.ts";
10
+
11
+ export * from "./local/files.ts";
12
+
13
+ export * from "./local/git.ts";
14
+
15
+ export * from "./local/github.ts";
16
+
17
+ export * from "./local/identity.ts";
18
+
19
+ export * from "./local/jobs.ts";
20
+
21
+ export * from "./local/provider.ts";
22
+
23
+ export { createMcpHub } from "./mcp/hub.ts";
24
+
25
+ export type { McpConnector } from "./mcp/connect.ts";
26
+
27
+ export * from "./local/snapshots.ts";
28
+
29
+ export * from "./local/worktrees.ts";
30
+
31
+ export * from "./open.ts";
32
+
33
+ export * from "./plugins/loader.ts";
34
+
35
+ export * from "./postgres.ts";
36
+
37
+ export * from "./secrets.ts";
38
+
39
+ export * from "./sqlite.ts";
@@ -0,0 +1,53 @@
1
+ import { link, mkdir, open, readFile, unlink } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { SdkError } from "@nyte-ai/schema";
4
+ import { readErrorCode } from "./local/tree.ts";
5
+
6
+ export async function readKeyFile(path: string, name: string): Promise<Uint8Array> {
7
+ const bytes = await readFile(path)
8
+ .then(
9
+ (stored) => new Uint8Array(stored),
10
+ (error: unknown) => {
11
+ if (readErrorCode(error) === "ENOENT") return mintKeyFile(path);
12
+
13
+ throw error;
14
+ },
15
+ )
16
+ .catch((error: unknown) => {
17
+ throw new SdkError(
18
+ "unavailable",
19
+ `The ${name} at ${path} cannot be read: ${error instanceof Error ? error.message : String(error)}`,
20
+ );
21
+ });
22
+
23
+ if (bytes.length !== 32)
24
+ throw new SdkError("invalid", `The ${name} at ${path} is ${bytes.length} bytes, not 32.`);
25
+
26
+ return bytes;
27
+ }
28
+
29
+ async function mintKeyFile(path: string): Promise<Uint8Array> {
30
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
31
+ const bytes = crypto.getRandomValues(new Uint8Array(32));
32
+ const temp = `${path}.${crypto.randomUUID()}`;
33
+ const file = await open(temp, "wx", 0o600);
34
+
35
+ try {
36
+ await file.writeFile(bytes);
37
+ await file.sync();
38
+ } finally {
39
+ await file.close();
40
+ }
41
+
42
+ try {
43
+ await link(temp, path);
44
+
45
+ return bytes;
46
+ } catch (error) {
47
+ if (readErrorCode(error) !== "EEXIST") throw error;
48
+
49
+ return new Uint8Array(await readFile(path));
50
+ } finally {
51
+ await unlink(temp).catch(() => undefined);
52
+ }
53
+ }