@paperclipai/server 0.2.2

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 (317) hide show
  1. package/dist/adapters/codex-models.d.ts +4 -0
  2. package/dist/adapters/codex-models.d.ts.map +1 -0
  3. package/dist/adapters/codex-models.js +98 -0
  4. package/dist/adapters/codex-models.js.map +1 -0
  5. package/dist/adapters/http/execute.d.ts +3 -0
  6. package/dist/adapters/http/execute.d.ts.map +1 -0
  7. package/dist/adapters/http/execute.js +39 -0
  8. package/dist/adapters/http/execute.js.map +1 -0
  9. package/dist/adapters/http/index.d.ts +3 -0
  10. package/dist/adapters/http/index.d.ts.map +1 -0
  11. package/dist/adapters/http/index.js +20 -0
  12. package/dist/adapters/http/index.js.map +1 -0
  13. package/dist/adapters/http/test.d.ts +3 -0
  14. package/dist/adapters/http/test.d.ts.map +1 -0
  15. package/dist/adapters/http/test.js +106 -0
  16. package/dist/adapters/http/test.js.map +1 -0
  17. package/dist/adapters/index.d.ts +4 -0
  18. package/dist/adapters/index.d.ts.map +1 -0
  19. package/dist/adapters/index.js +3 -0
  20. package/dist/adapters/index.js.map +1 -0
  21. package/dist/adapters/process/execute.d.ts +3 -0
  22. package/dist/adapters/process/execute.d.ts.map +1 -0
  23. package/dist/adapters/process/execute.js +63 -0
  24. package/dist/adapters/process/execute.js.map +1 -0
  25. package/dist/adapters/process/index.d.ts +3 -0
  26. package/dist/adapters/process/index.d.ts.map +1 -0
  27. package/dist/adapters/process/index.js +23 -0
  28. package/dist/adapters/process/index.js.map +1 -0
  29. package/dist/adapters/process/test.d.ts +3 -0
  30. package/dist/adapters/process/test.d.ts.map +1 -0
  31. package/dist/adapters/process/test.js +77 -0
  32. package/dist/adapters/process/test.js.map +1 -0
  33. package/dist/adapters/registry.d.ts +9 -0
  34. package/dist/adapters/registry.d.ts.map +1 -0
  35. package/dist/adapters/registry.js +63 -0
  36. package/dist/adapters/registry.js.map +1 -0
  37. package/dist/adapters/types.d.ts +2 -0
  38. package/dist/adapters/types.d.ts.map +1 -0
  39. package/dist/adapters/types.js +2 -0
  40. package/dist/adapters/types.js.map +1 -0
  41. package/dist/adapters/utils.d.ts +10 -0
  42. package/dist/adapters/utils.d.ts.map +1 -0
  43. package/dist/adapters/utils.js +14 -0
  44. package/dist/adapters/utils.js.map +1 -0
  45. package/dist/agent-auth-jwt.d.ts +14 -0
  46. package/dist/agent-auth-jwt.d.ts.map +1 -0
  47. package/dist/agent-auth-jwt.js +117 -0
  48. package/dist/agent-auth-jwt.js.map +1 -0
  49. package/dist/app.d.ts +20 -0
  50. package/dist/app.d.ts.map +1 -0
  51. package/dist/app.js +127 -0
  52. package/dist/app.js.map +1 -0
  53. package/dist/auth/better-auth.d.ts +23 -0
  54. package/dist/auth/better-auth.d.ts.map +1 -0
  55. package/dist/auth/better-auth.js +80 -0
  56. package/dist/auth/better-auth.js.map +1 -0
  57. package/dist/board-claim.d.ts +23 -0
  58. package/dist/board-claim.d.ts.map +1 -0
  59. package/dist/board-claim.js +115 -0
  60. package/dist/board-claim.js.map +1 -0
  61. package/dist/config-file.d.ts +3 -0
  62. package/dist/config-file.d.ts.map +1 -0
  63. package/dist/config-file.js +16 -0
  64. package/dist/config-file.js.map +1 -0
  65. package/dist/config.d.ts +33 -0
  66. package/dist/config.d.ts.map +1 -0
  67. package/dist/config.js +114 -0
  68. package/dist/config.js.map +1 -0
  69. package/dist/errors.d.ts +12 -0
  70. package/dist/errors.d.ts.map +1 -0
  71. package/dist/errors.js +28 -0
  72. package/dist/errors.js.map +1 -0
  73. package/dist/home-paths.d.ts +11 -0
  74. package/dist/home-paths.d.ts.map +1 -0
  75. package/dist/home-paths.js +54 -0
  76. package/dist/home-paths.js.map +1 -0
  77. package/dist/index.d.ts +2 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +439 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/middleware/auth.d.ts +12 -0
  82. package/dist/middleware/auth.d.ts.map +1 -0
  83. package/dist/middleware/auth.js +124 -0
  84. package/dist/middleware/auth.js.map +1 -0
  85. package/dist/middleware/board-mutation-guard.d.ts +3 -0
  86. package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
  87. package/dist/middleware/board-mutation-guard.js +60 -0
  88. package/dist/middleware/board-mutation-guard.js.map +1 -0
  89. package/dist/middleware/error-handler.d.ts +3 -0
  90. package/dist/middleware/error-handler.d.ts.map +1 -0
  91. package/dist/middleware/error-handler.js +22 -0
  92. package/dist/middleware/error-handler.js.map +1 -0
  93. package/dist/middleware/index.d.ts +4 -0
  94. package/dist/middleware/index.d.ts.map +1 -0
  95. package/dist/middleware/index.js +4 -0
  96. package/dist/middleware/index.js.map +1 -0
  97. package/dist/middleware/logger.d.ts +4 -0
  98. package/dist/middleware/logger.d.ts.map +1 -0
  99. package/dist/middleware/logger.js +37 -0
  100. package/dist/middleware/logger.js.map +1 -0
  101. package/dist/middleware/private-hostname-guard.d.ts +11 -0
  102. package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
  103. package/dist/middleware/private-hostname-guard.js +78 -0
  104. package/dist/middleware/private-hostname-guard.js.map +1 -0
  105. package/dist/middleware/validate.d.ts +4 -0
  106. package/dist/middleware/validate.d.ts.map +1 -0
  107. package/dist/middleware/validate.js +7 -0
  108. package/dist/middleware/validate.js.map +1 -0
  109. package/dist/paths.d.ts +3 -0
  110. package/dist/paths.d.ts.map +1 -0
  111. package/dist/paths.js +31 -0
  112. package/dist/paths.js.map +1 -0
  113. package/dist/realtime/live-events-ws.d.ts +10 -0
  114. package/dist/realtime/live-events-ws.d.ts.map +1 -0
  115. package/dist/realtime/live-events-ws.js +185 -0
  116. package/dist/realtime/live-events-ws.js.map +1 -0
  117. package/dist/redaction.d.ts +4 -0
  118. package/dist/redaction.d.ts.map +1 -0
  119. package/dist/redaction.js +63 -0
  120. package/dist/redaction.js.map +1 -0
  121. package/dist/routes/access.d.ts +9 -0
  122. package/dist/routes/access.d.ts.map +1 -0
  123. package/dist/routes/access.js +887 -0
  124. package/dist/routes/access.js.map +1 -0
  125. package/dist/routes/activity.d.ts +3 -0
  126. package/dist/routes/activity.d.ts.map +1 -0
  127. package/dist/routes/activity.js +87 -0
  128. package/dist/routes/activity.js.map +1 -0
  129. package/dist/routes/agents.d.ts +3 -0
  130. package/dist/routes/agents.d.ts.map +1 -0
  131. package/dist/routes/agents.js +1132 -0
  132. package/dist/routes/agents.js.map +1 -0
  133. package/dist/routes/approvals.d.ts +3 -0
  134. package/dist/routes/approvals.d.ts.map +1 -0
  135. package/dist/routes/approvals.js +271 -0
  136. package/dist/routes/approvals.js.map +1 -0
  137. package/dist/routes/assets.d.ts +4 -0
  138. package/dist/routes/assets.d.ts.map +1 -0
  139. package/dist/routes/assets.js +138 -0
  140. package/dist/routes/assets.js.map +1 -0
  141. package/dist/routes/authz.d.ts +15 -0
  142. package/dist/routes/authz.d.ts.map +1 -0
  143. package/dist/routes/authz.js +40 -0
  144. package/dist/routes/authz.js.map +1 -0
  145. package/dist/routes/companies.d.ts +3 -0
  146. package/dist/routes/companies.d.ts.map +1 -0
  147. package/dist/routes/companies.js +159 -0
  148. package/dist/routes/companies.js.map +1 -0
  149. package/dist/routes/costs.d.ts +3 -0
  150. package/dist/routes/costs.d.ts.map +1 -0
  151. package/dist/routes/costs.js +113 -0
  152. package/dist/routes/costs.js.map +1 -0
  153. package/dist/routes/dashboard.d.ts +3 -0
  154. package/dist/routes/dashboard.d.ts.map +1 -0
  155. package/dist/routes/dashboard.js +15 -0
  156. package/dist/routes/dashboard.js.map +1 -0
  157. package/dist/routes/goals.d.ts +3 -0
  158. package/dist/routes/goals.d.ts.map +1 -0
  159. package/dist/routes/goals.js +95 -0
  160. package/dist/routes/goals.js.map +1 -0
  161. package/dist/routes/health.d.ts +9 -0
  162. package/dist/routes/health.d.ts.map +1 -0
  163. package/dist/routes/health.js +38 -0
  164. package/dist/routes/health.js.map +1 -0
  165. package/dist/routes/index.d.ts +15 -0
  166. package/dist/routes/index.d.ts.map +1 -0
  167. package/dist/routes/index.js +15 -0
  168. package/dist/routes/index.js.map +1 -0
  169. package/dist/routes/issues.d.ts +4 -0
  170. package/dist/routes/issues.d.ts.map +1 -0
  171. package/dist/routes/issues.js +973 -0
  172. package/dist/routes/issues.js.map +1 -0
  173. package/dist/routes/llms.d.ts +3 -0
  174. package/dist/routes/llms.d.ts.map +1 -0
  175. package/dist/routes/llms.js +78 -0
  176. package/dist/routes/llms.js.map +1 -0
  177. package/dist/routes/projects.d.ts +3 -0
  178. package/dist/routes/projects.d.ts.map +1 -0
  179. package/dist/routes/projects.js +253 -0
  180. package/dist/routes/projects.js.map +1 -0
  181. package/dist/routes/secrets.d.ts +3 -0
  182. package/dist/routes/secrets.d.ts.map +1 -0
  183. package/dist/routes/secrets.js +128 -0
  184. package/dist/routes/secrets.js.map +1 -0
  185. package/dist/routes/sidebar-badges.d.ts +3 -0
  186. package/dist/routes/sidebar-badges.d.ts.map +1 -0
  187. package/dist/routes/sidebar-badges.js +47 -0
  188. package/dist/routes/sidebar-badges.js.map +1 -0
  189. package/dist/secrets/external-stub-providers.d.ts +5 -0
  190. package/dist/secrets/external-stub-providers.d.ts.map +1 -0
  191. package/dist/secrets/external-stub-providers.js +21 -0
  192. package/dist/secrets/external-stub-providers.js.map +1 -0
  193. package/dist/secrets/local-encrypted-provider.d.ts +3 -0
  194. package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
  195. package/dist/secrets/local-encrypted-provider.js +116 -0
  196. package/dist/secrets/local-encrypted-provider.js.map +1 -0
  197. package/dist/secrets/provider-registry.d.ts +5 -0
  198. package/dist/secrets/provider-registry.d.ts.map +1 -0
  199. package/dist/secrets/provider-registry.js +20 -0
  200. package/dist/secrets/provider-registry.js.map +1 -0
  201. package/dist/secrets/types.d.ts +21 -0
  202. package/dist/secrets/types.d.ts.map +1 -0
  203. package/dist/secrets/types.js +2 -0
  204. package/dist/secrets/types.js.map +1 -0
  205. package/dist/services/access.d.ts +81 -0
  206. package/dist/services/access.d.ts.map +1 -0
  207. package/dist/services/access.js +187 -0
  208. package/dist/services/access.js.map +1 -0
  209. package/dist/services/activity-log.d.ts +14 -0
  210. package/dist/services/activity-log.d.ts.map +1 -0
  211. package/dist/services/activity-log.js +32 -0
  212. package/dist/services/activity-log.js.map +1 -0
  213. package/dist/services/activity.d.ts +764 -0
  214. package/dist/services/activity.d.ts.map +1 -0
  215. package/dist/services/activity.js +105 -0
  216. package/dist/services/activity.js.map +1 -0
  217. package/dist/services/agent-permissions.d.ts +6 -0
  218. package/dist/services/agent-permissions.d.ts.map +1 -0
  219. package/dist/services/agent-permissions.js +18 -0
  220. package/dist/services/agent-permissions.js.map +1 -0
  221. package/dist/services/agents.d.ts +1494 -0
  222. package/dist/services/agents.d.ts.map +1 -0
  223. package/dist/services/agents.js +454 -0
  224. package/dist/services/agents.js.map +1 -0
  225. package/dist/services/approvals.d.ts +540 -0
  226. package/dist/services/approvals.d.ts.map +1 -0
  227. package/dist/services/approvals.js +173 -0
  228. package/dist/services/approvals.js.map +1 -0
  229. package/dist/services/assets.d.ts +33 -0
  230. package/dist/services/assets.d.ts.map +1 -0
  231. package/dist/services/assets.js +17 -0
  232. package/dist/services/assets.js.map +1 -0
  233. package/dist/services/companies.d.ts +503 -0
  234. package/dist/services/companies.d.ts.map +1 -0
  235. package/dist/services/companies.js +120 -0
  236. package/dist/services/companies.js.map +1 -0
  237. package/dist/services/company-portability.d.ts +8 -0
  238. package/dist/services/company-portability.d.ts.map +1 -0
  239. package/dist/services/company-portability.js +851 -0
  240. package/dist/services/company-portability.js.map +1 -0
  241. package/dist/services/costs.d.ts +50 -0
  242. package/dist/services/costs.d.ts.map +1 -0
  243. package/dist/services/costs.js +166 -0
  244. package/dist/services/costs.js.map +1 -0
  245. package/dist/services/dashboard.d.ts +21 -0
  246. package/dist/services/dashboard.d.ts.map +1 -0
  247. package/dist/services/dashboard.js +96 -0
  248. package/dist/services/dashboard.js.map +1 -0
  249. package/dist/services/goals.d.ts +407 -0
  250. package/dist/services/goals.d.ts.map +1 -0
  251. package/dist/services/goals.js +29 -0
  252. package/dist/services/goals.js.map +1 -0
  253. package/dist/services/heartbeat.d.ts +1666 -0
  254. package/dist/services/heartbeat.d.ts.map +1 -0
  255. package/dist/services/heartbeat.js +1752 -0
  256. package/dist/services/heartbeat.js.map +1 -0
  257. package/dist/services/index.d.ts +20 -0
  258. package/dist/services/index.d.ts.map +1 -0
  259. package/dist/services/index.js +20 -0
  260. package/dist/services/index.js.map +1 -0
  261. package/dist/services/issue-approvals.d.ts +56 -0
  262. package/dist/services/issue-approvals.d.ts.map +1 -0
  263. package/dist/services/issue-approvals.js +153 -0
  264. package/dist/services/issue-approvals.js.map +1 -0
  265. package/dist/services/issues.d.ts +756 -0
  266. package/dist/services/issues.d.ts.map +1 -0
  267. package/dist/services/issues.js +917 -0
  268. package/dist/services/issues.js.map +1 -0
  269. package/dist/services/live-events.d.ts +12 -0
  270. package/dist/services/live-events.d.ts.map +1 -0
  271. package/dist/services/live-events.js +24 -0
  272. package/dist/services/live-events.js.map +1 -0
  273. package/dist/services/projects.d.ts +66 -0
  274. package/dist/services/projects.d.ts.map +1 -0
  275. package/dist/services/projects.js +472 -0
  276. package/dist/services/projects.js.map +1 -0
  277. package/dist/services/run-log-store.d.ts +34 -0
  278. package/dist/services/run-log-store.d.ts.map +1 -0
  279. package/dist/services/run-log-store.js +112 -0
  280. package/dist/services/run-log-store.js.map +1 -0
  281. package/dist/services/secrets.d.ts +506 -0
  282. package/dist/services/secrets.d.ts.map +1 -0
  283. package/dist/services/secrets.js +284 -0
  284. package/dist/services/secrets.js.map +1 -0
  285. package/dist/services/sidebar-badges.d.ts +9 -0
  286. package/dist/services/sidebar-badges.d.ts.map +1 -0
  287. package/dist/services/sidebar-badges.js +33 -0
  288. package/dist/services/sidebar-badges.js.map +1 -0
  289. package/dist/startup-banner.d.ts +27 -0
  290. package/dist/startup-banner.d.ts.map +1 -0
  291. package/dist/startup-banner.js +112 -0
  292. package/dist/startup-banner.js.map +1 -0
  293. package/dist/storage/index.d.ts +6 -0
  294. package/dist/storage/index.d.ts.map +1 -0
  295. package/dist/storage/index.js +29 -0
  296. package/dist/storage/index.js.map +1 -0
  297. package/dist/storage/local-disk-provider.d.ts +3 -0
  298. package/dist/storage/local-disk-provider.d.ts.map +1 -0
  299. package/dist/storage/local-disk-provider.js +79 -0
  300. package/dist/storage/local-disk-provider.js.map +1 -0
  301. package/dist/storage/provider-registry.d.ts +4 -0
  302. package/dist/storage/provider-registry.d.ts.map +1 -0
  303. package/dist/storage/provider-registry.js +15 -0
  304. package/dist/storage/provider-registry.js.map +1 -0
  305. package/dist/storage/s3-provider.d.ts +11 -0
  306. package/dist/storage/s3-provider.d.ts.map +1 -0
  307. package/dist/storage/s3-provider.js +123 -0
  308. package/dist/storage/s3-provider.js.map +1 -0
  309. package/dist/storage/service.d.ts +3 -0
  310. package/dist/storage/service.d.ts.map +1 -0
  311. package/dist/storage/service.js +120 -0
  312. package/dist/storage/service.js.map +1 -0
  313. package/dist/storage/types.d.ts +55 -0
  314. package/dist/storage/types.d.ts.map +1 -0
  315. package/dist/storage/types.js +2 -0
  316. package/dist/storage/types.js.map +1 -0
  317. package/package.json +62 -0
package/dist/index.js ADDED
@@ -0,0 +1,439 @@
1
+ /// <reference path="./types/express.d.ts" />
2
+ import { existsSync, readFileSync, rmSync } from "node:fs";
3
+ import { createServer } from "node:http";
4
+ import { resolve } from "node:path";
5
+ import { createInterface } from "node:readline/promises";
6
+ import { stdin, stdout } from "node:process";
7
+ import { and, eq } from "drizzle-orm";
8
+ import { createDb, ensurePostgresDatabase, inspectMigrations, applyPendingMigrations, reconcilePendingMigrationHistory, authUsers, companies, companyMemberships, instanceUserRoles, } from "@paperclipai/db";
9
+ import detectPort from "detect-port";
10
+ import { createApp } from "./app.js";
11
+ import { loadConfig } from "./config.js";
12
+ import { logger } from "./middleware/logger.js";
13
+ import { setupLiveEventsWebSocketServer } from "./realtime/live-events-ws.js";
14
+ import { heartbeatService } from "./services/index.js";
15
+ import { createStorageServiceFromConfig } from "./storage/index.js";
16
+ import { printStartupBanner } from "./startup-banner.js";
17
+ import { getBoardClaimWarningUrl, initializeBoardClaimChallenge } from "./board-claim.js";
18
+ import { createBetterAuthHandler, createBetterAuthInstance, resolveBetterAuthSession, resolveBetterAuthSessionFromHeaders, } from "./auth/better-auth.js";
19
+ const config = loadConfig();
20
+ if (process.env.PAPERCLIP_SECRETS_PROVIDER === undefined) {
21
+ process.env.PAPERCLIP_SECRETS_PROVIDER = config.secretsProvider;
22
+ }
23
+ if (process.env.PAPERCLIP_SECRETS_STRICT_MODE === undefined) {
24
+ process.env.PAPERCLIP_SECRETS_STRICT_MODE = config.secretsStrictMode ? "true" : "false";
25
+ }
26
+ if (process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE === undefined) {
27
+ process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE = config.secretsMasterKeyFilePath;
28
+ }
29
+ function formatPendingMigrationSummary(migrations) {
30
+ if (migrations.length === 0)
31
+ return "none";
32
+ return migrations.length > 3
33
+ ? `${migrations.slice(0, 3).join(", ")} (+${migrations.length - 3} more)`
34
+ : migrations.join(", ");
35
+ }
36
+ async function promptApplyMigrations(migrations) {
37
+ if (process.env.PAPERCLIP_MIGRATION_PROMPT === "never")
38
+ return false;
39
+ if (process.env.PAPERCLIP_MIGRATION_AUTO_APPLY === "true")
40
+ return true;
41
+ if (!stdin.isTTY || !stdout.isTTY)
42
+ return true;
43
+ const prompt = createInterface({ input: stdin, output: stdout });
44
+ try {
45
+ const answer = (await prompt.question(`Apply pending migrations (${formatPendingMigrationSummary(migrations)}) now? (y/N): `)).trim().toLowerCase();
46
+ return answer === "y" || answer === "yes";
47
+ }
48
+ finally {
49
+ prompt.close();
50
+ }
51
+ }
52
+ async function ensureMigrations(connectionString, label, opts) {
53
+ const autoApply = opts?.autoApply === true;
54
+ let state = await inspectMigrations(connectionString);
55
+ if (state.status === "needsMigrations" && state.reason === "pending-migrations") {
56
+ const repair = await reconcilePendingMigrationHistory(connectionString);
57
+ if (repair.repairedMigrations.length > 0) {
58
+ logger.warn({ repairedMigrations: repair.repairedMigrations }, `${label} had drifted migration history; repaired migration journal entries from existing schema state.`);
59
+ state = await inspectMigrations(connectionString);
60
+ if (state.status === "upToDate")
61
+ return "already applied";
62
+ }
63
+ }
64
+ if (state.status === "upToDate")
65
+ return "already applied";
66
+ if (state.status === "needsMigrations" && state.reason === "no-migration-journal-non-empty-db") {
67
+ logger.warn({ tableCount: state.tableCount }, `${label} has existing tables but no migration journal. Run migrations manually to sync schema.`);
68
+ const apply = autoApply ? true : await promptApplyMigrations(state.pendingMigrations);
69
+ if (!apply) {
70
+ logger.warn({ pendingMigrations: state.pendingMigrations }, `${label} has pending migrations; continuing without applying. Run pnpm db:migrate to apply before startup.`);
71
+ return "pending migrations skipped";
72
+ }
73
+ logger.info({ pendingMigrations: state.pendingMigrations }, `Applying ${state.pendingMigrations.length} pending migrations for ${label}`);
74
+ await applyPendingMigrations(connectionString);
75
+ return "applied (pending migrations)";
76
+ }
77
+ const apply = autoApply ? true : await promptApplyMigrations(state.pendingMigrations);
78
+ if (!apply) {
79
+ logger.warn({ pendingMigrations: state.pendingMigrations }, `${label} has pending migrations; continuing without applying. Run pnpm db:migrate to apply before startup.`);
80
+ return "pending migrations skipped";
81
+ }
82
+ logger.info({ pendingMigrations: state.pendingMigrations }, `Applying ${state.pendingMigrations.length} pending migrations for ${label}`);
83
+ await applyPendingMigrations(connectionString);
84
+ return "applied (pending migrations)";
85
+ }
86
+ function isLoopbackHost(host) {
87
+ const normalized = host.trim().toLowerCase();
88
+ return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1";
89
+ }
90
+ const LOCAL_BOARD_USER_ID = "local-board";
91
+ const LOCAL_BOARD_USER_EMAIL = "local@paperclip.local";
92
+ const LOCAL_BOARD_USER_NAME = "Board";
93
+ async function ensureLocalTrustedBoardPrincipal(db) {
94
+ const now = new Date();
95
+ const existingUser = await db
96
+ .select({ id: authUsers.id })
97
+ .from(authUsers)
98
+ .where(eq(authUsers.id, LOCAL_BOARD_USER_ID))
99
+ .then((rows) => rows[0] ?? null);
100
+ if (!existingUser) {
101
+ await db.insert(authUsers).values({
102
+ id: LOCAL_BOARD_USER_ID,
103
+ name: LOCAL_BOARD_USER_NAME,
104
+ email: LOCAL_BOARD_USER_EMAIL,
105
+ emailVerified: true,
106
+ image: null,
107
+ createdAt: now,
108
+ updatedAt: now,
109
+ });
110
+ }
111
+ const role = await db
112
+ .select({ id: instanceUserRoles.id })
113
+ .from(instanceUserRoles)
114
+ .where(and(eq(instanceUserRoles.userId, LOCAL_BOARD_USER_ID), eq(instanceUserRoles.role, "instance_admin")))
115
+ .then((rows) => rows[0] ?? null);
116
+ if (!role) {
117
+ await db.insert(instanceUserRoles).values({
118
+ userId: LOCAL_BOARD_USER_ID,
119
+ role: "instance_admin",
120
+ });
121
+ }
122
+ const companyRows = await db.select({ id: companies.id }).from(companies);
123
+ for (const company of companyRows) {
124
+ const membership = await db
125
+ .select({ id: companyMemberships.id })
126
+ .from(companyMemberships)
127
+ .where(and(eq(companyMemberships.companyId, company.id), eq(companyMemberships.principalType, "user"), eq(companyMemberships.principalId, LOCAL_BOARD_USER_ID)))
128
+ .then((rows) => rows[0] ?? null);
129
+ if (membership)
130
+ continue;
131
+ await db.insert(companyMemberships).values({
132
+ companyId: company.id,
133
+ principalType: "user",
134
+ principalId: LOCAL_BOARD_USER_ID,
135
+ status: "active",
136
+ membershipRole: "owner",
137
+ });
138
+ }
139
+ }
140
+ let db;
141
+ let embeddedPostgres = null;
142
+ let embeddedPostgresStartedByThisProcess = false;
143
+ let migrationSummary = "skipped";
144
+ let startupDbInfo;
145
+ if (config.databaseUrl) {
146
+ migrationSummary = await ensureMigrations(config.databaseUrl, "PostgreSQL");
147
+ db = createDb(config.databaseUrl);
148
+ logger.info("Using external PostgreSQL via DATABASE_URL/config");
149
+ startupDbInfo = { mode: "external-postgres", connectionString: config.databaseUrl };
150
+ }
151
+ else {
152
+ const moduleName = "embedded-postgres";
153
+ let EmbeddedPostgres;
154
+ try {
155
+ const mod = await import(moduleName);
156
+ EmbeddedPostgres = mod.default;
157
+ }
158
+ catch {
159
+ throw new Error("Embedded PostgreSQL mode requires optional dependency `embedded-postgres`. Install optional dependencies or set DATABASE_URL for external Postgres.");
160
+ }
161
+ const dataDir = resolve(config.embeddedPostgresDataDir);
162
+ const configuredPort = config.embeddedPostgresPort;
163
+ let port = configuredPort;
164
+ const embeddedPostgresLogBuffer = [];
165
+ const EMBEDDED_POSTGRES_LOG_BUFFER_LIMIT = 120;
166
+ const verboseEmbeddedPostgresLogs = process.env.PAPERCLIP_EMBEDDED_POSTGRES_VERBOSE === "true";
167
+ const appendEmbeddedPostgresLog = (message) => {
168
+ const text = typeof message === "string" ? message : message instanceof Error ? message.message : String(message ?? "");
169
+ for (const lineRaw of text.split(/\r?\n/)) {
170
+ const line = lineRaw.trim();
171
+ if (!line)
172
+ continue;
173
+ embeddedPostgresLogBuffer.push(line);
174
+ if (embeddedPostgresLogBuffer.length > EMBEDDED_POSTGRES_LOG_BUFFER_LIMIT) {
175
+ embeddedPostgresLogBuffer.splice(0, embeddedPostgresLogBuffer.length - EMBEDDED_POSTGRES_LOG_BUFFER_LIMIT);
176
+ }
177
+ if (verboseEmbeddedPostgresLogs) {
178
+ logger.info({ embeddedPostgresLog: line }, "embedded-postgres");
179
+ }
180
+ }
181
+ };
182
+ const logEmbeddedPostgresFailure = (phase, err) => {
183
+ if (embeddedPostgresLogBuffer.length > 0) {
184
+ logger.error({
185
+ phase,
186
+ recentLogs: embeddedPostgresLogBuffer,
187
+ err,
188
+ }, "Embedded PostgreSQL failed; showing buffered startup logs");
189
+ }
190
+ };
191
+ if (config.databaseMode === "postgres") {
192
+ logger.warn("Database mode is postgres but no connection string was set; falling back to embedded PostgreSQL");
193
+ }
194
+ const clusterVersionFile = resolve(dataDir, "PG_VERSION");
195
+ const clusterAlreadyInitialized = existsSync(clusterVersionFile);
196
+ const postmasterPidFile = resolve(dataDir, "postmaster.pid");
197
+ const isPidRunning = (pid) => {
198
+ try {
199
+ process.kill(pid, 0);
200
+ return true;
201
+ }
202
+ catch {
203
+ return false;
204
+ }
205
+ };
206
+ const getRunningPid = () => {
207
+ if (!existsSync(postmasterPidFile))
208
+ return null;
209
+ try {
210
+ const pidLine = readFileSync(postmasterPidFile, "utf8").split("\n")[0]?.trim();
211
+ const pid = Number(pidLine);
212
+ if (!Number.isInteger(pid) || pid <= 0)
213
+ return null;
214
+ if (!isPidRunning(pid))
215
+ return null;
216
+ return pid;
217
+ }
218
+ catch {
219
+ return null;
220
+ }
221
+ };
222
+ const runningPid = getRunningPid();
223
+ if (runningPid) {
224
+ logger.warn(`Embedded PostgreSQL already running; reusing existing process (pid=${runningPid}, port=${port})`);
225
+ }
226
+ else {
227
+ const detectedPort = await detectPort(configuredPort);
228
+ if (detectedPort !== configuredPort) {
229
+ logger.warn(`Embedded PostgreSQL port is in use; using next free port (requestedPort=${configuredPort}, selectedPort=${detectedPort})`);
230
+ }
231
+ port = detectedPort;
232
+ logger.info(`Using embedded PostgreSQL because no DATABASE_URL set (dataDir=${dataDir}, port=${port})`);
233
+ embeddedPostgres = new EmbeddedPostgres({
234
+ databaseDir: dataDir,
235
+ user: "paperclip",
236
+ password: "paperclip",
237
+ port,
238
+ persistent: true,
239
+ onLog: appendEmbeddedPostgresLog,
240
+ onError: appendEmbeddedPostgresLog,
241
+ });
242
+ if (!clusterAlreadyInitialized) {
243
+ try {
244
+ await embeddedPostgres.initialise();
245
+ }
246
+ catch (err) {
247
+ logEmbeddedPostgresFailure("initialise", err);
248
+ throw err;
249
+ }
250
+ }
251
+ else {
252
+ logger.info(`Embedded PostgreSQL cluster already exists (${clusterVersionFile}); skipping init`);
253
+ }
254
+ if (existsSync(postmasterPidFile)) {
255
+ logger.warn("Removing stale embedded PostgreSQL lock file");
256
+ rmSync(postmasterPidFile, { force: true });
257
+ }
258
+ try {
259
+ await embeddedPostgres.start();
260
+ }
261
+ catch (err) {
262
+ logEmbeddedPostgresFailure("start", err);
263
+ throw err;
264
+ }
265
+ embeddedPostgresStartedByThisProcess = true;
266
+ }
267
+ const embeddedAdminConnectionString = `postgres://paperclip:paperclip@127.0.0.1:${port}/postgres`;
268
+ const dbStatus = await ensurePostgresDatabase(embeddedAdminConnectionString, "paperclip");
269
+ if (dbStatus === "created") {
270
+ logger.info("Created embedded PostgreSQL database: paperclip");
271
+ }
272
+ const embeddedConnectionString = `postgres://paperclip:paperclip@127.0.0.1:${port}/paperclip`;
273
+ const shouldAutoApplyFirstRunMigrations = !clusterAlreadyInitialized || dbStatus === "created";
274
+ if (shouldAutoApplyFirstRunMigrations) {
275
+ logger.info("Detected first-run embedded PostgreSQL setup; applying pending migrations automatically");
276
+ }
277
+ migrationSummary = await ensureMigrations(embeddedConnectionString, "Embedded PostgreSQL", {
278
+ autoApply: shouldAutoApplyFirstRunMigrations,
279
+ });
280
+ db = createDb(embeddedConnectionString);
281
+ logger.info("Embedded PostgreSQL ready");
282
+ startupDbInfo = { mode: "embedded-postgres", dataDir, port };
283
+ }
284
+ if (config.deploymentMode === "local_trusted" && !isLoopbackHost(config.host)) {
285
+ throw new Error(`local_trusted mode requires loopback host binding (received: ${config.host}). ` +
286
+ "Use authenticated mode for non-loopback deployments.");
287
+ }
288
+ if (config.deploymentMode === "local_trusted" && config.deploymentExposure !== "private") {
289
+ throw new Error("local_trusted mode only supports private exposure");
290
+ }
291
+ if (config.deploymentMode === "authenticated") {
292
+ if (config.authBaseUrlMode === "explicit" && !config.authPublicBaseUrl) {
293
+ throw new Error("auth.baseUrlMode=explicit requires auth.publicBaseUrl");
294
+ }
295
+ if (config.deploymentExposure === "public") {
296
+ if (config.authBaseUrlMode !== "explicit") {
297
+ throw new Error("authenticated public exposure requires auth.baseUrlMode=explicit");
298
+ }
299
+ if (!config.authPublicBaseUrl) {
300
+ throw new Error("authenticated public exposure requires auth.publicBaseUrl");
301
+ }
302
+ }
303
+ }
304
+ let authReady = config.deploymentMode === "local_trusted";
305
+ let betterAuthHandler;
306
+ let resolveSession;
307
+ let resolveSessionFromHeaders;
308
+ if (config.deploymentMode === "local_trusted") {
309
+ await ensureLocalTrustedBoardPrincipal(db);
310
+ }
311
+ if (config.deploymentMode === "authenticated") {
312
+ const betterAuthSecret = process.env.BETTER_AUTH_SECRET?.trim() ?? process.env.PAPERCLIP_AGENT_JWT_SECRET?.trim();
313
+ if (!betterAuthSecret) {
314
+ throw new Error("authenticated mode requires BETTER_AUTH_SECRET (or PAPERCLIP_AGENT_JWT_SECRET) to be set");
315
+ }
316
+ const auth = createBetterAuthInstance(db, config);
317
+ betterAuthHandler = createBetterAuthHandler(auth);
318
+ resolveSession = (req) => resolveBetterAuthSession(auth, req);
319
+ resolveSessionFromHeaders = (headers) => resolveBetterAuthSessionFromHeaders(auth, headers);
320
+ await initializeBoardClaimChallenge(db, { deploymentMode: config.deploymentMode });
321
+ authReady = true;
322
+ }
323
+ const uiMode = config.uiDevMiddleware ? "vite-dev" : config.serveUi ? "static" : "none";
324
+ const storageService = createStorageServiceFromConfig(config);
325
+ const app = await createApp(db, {
326
+ uiMode,
327
+ storageService,
328
+ deploymentMode: config.deploymentMode,
329
+ deploymentExposure: config.deploymentExposure,
330
+ allowedHostnames: config.allowedHostnames,
331
+ bindHost: config.host,
332
+ authReady,
333
+ companyDeletionEnabled: config.companyDeletionEnabled,
334
+ betterAuthHandler,
335
+ resolveSession,
336
+ });
337
+ const server = createServer(app);
338
+ const listenPort = await detectPort(config.port);
339
+ if (listenPort !== config.port) {
340
+ logger.warn(`Requested port is busy; using next free port (requestedPort=${config.port}, selectedPort=${listenPort})`);
341
+ }
342
+ const runtimeListenHost = config.host;
343
+ const runtimeApiHost = runtimeListenHost === "0.0.0.0" || runtimeListenHost === "::"
344
+ ? "localhost"
345
+ : runtimeListenHost;
346
+ process.env.PAPERCLIP_LISTEN_HOST = runtimeListenHost;
347
+ process.env.PAPERCLIP_LISTEN_PORT = String(listenPort);
348
+ process.env.PAPERCLIP_API_URL = `http://${runtimeApiHost}:${listenPort}`;
349
+ setupLiveEventsWebSocketServer(server, db, {
350
+ deploymentMode: config.deploymentMode,
351
+ resolveSessionFromHeaders,
352
+ });
353
+ if (config.heartbeatSchedulerEnabled) {
354
+ const heartbeat = heartbeatService(db);
355
+ // Reap orphaned runs at startup (no threshold -- runningProcesses is empty)
356
+ void heartbeat.reapOrphanedRuns().catch((err) => {
357
+ logger.error({ err }, "startup reap of orphaned heartbeat runs failed");
358
+ });
359
+ setInterval(() => {
360
+ void heartbeat
361
+ .tickTimers(new Date())
362
+ .then((result) => {
363
+ if (result.enqueued > 0) {
364
+ logger.info({ ...result }, "heartbeat timer tick enqueued runs");
365
+ }
366
+ })
367
+ .catch((err) => {
368
+ logger.error({ err }, "heartbeat timer tick failed");
369
+ });
370
+ // Periodically reap orphaned runs (5-min staleness threshold)
371
+ void heartbeat
372
+ .reapOrphanedRuns({ staleThresholdMs: 5 * 60 * 1000 })
373
+ .catch((err) => {
374
+ logger.error({ err }, "periodic reap of orphaned heartbeat runs failed");
375
+ });
376
+ }, config.heartbeatSchedulerIntervalMs);
377
+ }
378
+ server.listen(listenPort, config.host, () => {
379
+ logger.info(`Server listening on ${config.host}:${listenPort}`);
380
+ if (process.env.PAPERCLIP_OPEN_ON_LISTEN === "true") {
381
+ const openHost = config.host === "0.0.0.0" || config.host === "::" ? "127.0.0.1" : config.host;
382
+ const url = `http://${openHost}:${listenPort}`;
383
+ void import("open")
384
+ .then((mod) => mod.default(url))
385
+ .then(() => {
386
+ logger.info(`Opened browser at ${url}`);
387
+ })
388
+ .catch((err) => {
389
+ logger.warn({ err, url }, "Failed to open browser on startup");
390
+ });
391
+ }
392
+ printStartupBanner({
393
+ host: config.host,
394
+ deploymentMode: config.deploymentMode,
395
+ deploymentExposure: config.deploymentExposure,
396
+ authReady,
397
+ requestedPort: config.port,
398
+ listenPort,
399
+ uiMode,
400
+ db: startupDbInfo,
401
+ migrationSummary,
402
+ heartbeatSchedulerEnabled: config.heartbeatSchedulerEnabled,
403
+ heartbeatSchedulerIntervalMs: config.heartbeatSchedulerIntervalMs,
404
+ });
405
+ const boardClaimUrl = getBoardClaimWarningUrl(config.host, listenPort);
406
+ if (boardClaimUrl) {
407
+ const red = "\x1b[41m\x1b[30m";
408
+ const yellow = "\x1b[33m";
409
+ const reset = "\x1b[0m";
410
+ console.log([
411
+ `${red} BOARD CLAIM REQUIRED ${reset}`,
412
+ `${yellow}This instance was previously local_trusted and still has local-board as the only admin.${reset}`,
413
+ `${yellow}Sign in with a real user and open this one-time URL to claim ownership:${reset}`,
414
+ `${yellow}${boardClaimUrl}${reset}`,
415
+ `${yellow}If you are connecting over Tailscale, replace the host in this URL with your Tailscale IP/MagicDNS name.${reset}`,
416
+ ].join("\n"));
417
+ }
418
+ });
419
+ if (embeddedPostgres && embeddedPostgresStartedByThisProcess) {
420
+ const shutdown = async (signal) => {
421
+ logger.info({ signal }, "Stopping embedded PostgreSQL");
422
+ try {
423
+ await embeddedPostgres?.stop();
424
+ }
425
+ catch (err) {
426
+ logger.error({ err }, "Failed to stop embedded PostgreSQL cleanly");
427
+ }
428
+ finally {
429
+ process.exit(0);
430
+ }
431
+ };
432
+ process.once("SIGINT", () => {
433
+ void shutdown("SIGINT");
434
+ });
435
+ process.once("SIGTERM", () => {
436
+ void shutdown("SIGTERM");
437
+ });
438
+ }
439
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Request, RequestHandler } from "express";
2
+ import type { Db } from "@paperclipai/db";
3
+ import type { DeploymentMode } from "@paperclipai/shared";
4
+ import type { BetterAuthSessionResult } from "../auth/better-auth.js";
5
+ interface ActorMiddlewareOptions {
6
+ deploymentMode: DeploymentMode;
7
+ resolveSession?: (req: Request) => Promise<BetterAuthSessionResult | null>;
8
+ }
9
+ export declare function actorMiddleware(db: Db, opts: ActorMiddlewareOptions): RequestHandler;
10
+ export declare function requireBoard(req: Express.Request): boolean;
11
+ export {};
12
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEvD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAG1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAOtE,UAAU,sBAAsB;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;CAC5E;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,sBAAsB,GAAG,cAAc,CAoIpF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,WAEhD"}
@@ -0,0 +1,124 @@
1
+ import { createHash } from "node:crypto";
2
+ import { and, eq, isNull } from "drizzle-orm";
3
+ import { agentApiKeys, agents, companyMemberships, instanceUserRoles } from "@paperclipai/db";
4
+ import { verifyLocalAgentJwt } from "../agent-auth-jwt.js";
5
+ import { logger } from "./logger.js";
6
+ function hashToken(token) {
7
+ return createHash("sha256").update(token).digest("hex");
8
+ }
9
+ export function actorMiddleware(db, opts) {
10
+ return async (req, _res, next) => {
11
+ req.actor =
12
+ opts.deploymentMode === "local_trusted"
13
+ ? { type: "board", userId: "local-board", isInstanceAdmin: true, source: "local_implicit" }
14
+ : { type: "none", source: "none" };
15
+ const runIdHeader = req.header("x-paperclip-run-id");
16
+ const authHeader = req.header("authorization");
17
+ if (!authHeader?.toLowerCase().startsWith("bearer ")) {
18
+ if (opts.deploymentMode === "authenticated" && opts.resolveSession) {
19
+ let session = null;
20
+ try {
21
+ session = await opts.resolveSession(req);
22
+ }
23
+ catch (err) {
24
+ logger.warn({ err, method: req.method, url: req.originalUrl }, "Failed to resolve auth session from request headers");
25
+ }
26
+ if (session?.user?.id) {
27
+ const userId = session.user.id;
28
+ const [roleRow, memberships] = await Promise.all([
29
+ db
30
+ .select({ id: instanceUserRoles.id })
31
+ .from(instanceUserRoles)
32
+ .where(and(eq(instanceUserRoles.userId, userId), eq(instanceUserRoles.role, "instance_admin")))
33
+ .then((rows) => rows[0] ?? null),
34
+ db
35
+ .select({ companyId: companyMemberships.companyId })
36
+ .from(companyMemberships)
37
+ .where(and(eq(companyMemberships.principalType, "user"), eq(companyMemberships.principalId, userId), eq(companyMemberships.status, "active"))),
38
+ ]);
39
+ req.actor = {
40
+ type: "board",
41
+ userId,
42
+ companyIds: memberships.map((row) => row.companyId),
43
+ isInstanceAdmin: Boolean(roleRow),
44
+ runId: runIdHeader ?? undefined,
45
+ source: "session",
46
+ };
47
+ next();
48
+ return;
49
+ }
50
+ }
51
+ if (runIdHeader)
52
+ req.actor.runId = runIdHeader;
53
+ next();
54
+ return;
55
+ }
56
+ const token = authHeader.slice("bearer ".length).trim();
57
+ if (!token) {
58
+ next();
59
+ return;
60
+ }
61
+ const tokenHash = hashToken(token);
62
+ const key = await db
63
+ .select()
64
+ .from(agentApiKeys)
65
+ .where(and(eq(agentApiKeys.keyHash, tokenHash), isNull(agentApiKeys.revokedAt)))
66
+ .then((rows) => rows[0] ?? null);
67
+ if (!key) {
68
+ const claims = verifyLocalAgentJwt(token);
69
+ if (!claims) {
70
+ next();
71
+ return;
72
+ }
73
+ const agentRecord = await db
74
+ .select()
75
+ .from(agents)
76
+ .where(eq(agents.id, claims.sub))
77
+ .then((rows) => rows[0] ?? null);
78
+ if (!agentRecord || agentRecord.companyId !== claims.company_id) {
79
+ next();
80
+ return;
81
+ }
82
+ if (agentRecord.status === "terminated" || agentRecord.status === "pending_approval") {
83
+ next();
84
+ return;
85
+ }
86
+ req.actor = {
87
+ type: "agent",
88
+ agentId: claims.sub,
89
+ companyId: claims.company_id,
90
+ keyId: undefined,
91
+ runId: runIdHeader || claims.run_id || undefined,
92
+ source: "agent_jwt",
93
+ };
94
+ next();
95
+ return;
96
+ }
97
+ await db
98
+ .update(agentApiKeys)
99
+ .set({ lastUsedAt: new Date() })
100
+ .where(eq(agentApiKeys.id, key.id));
101
+ const agentRecord = await db
102
+ .select()
103
+ .from(agents)
104
+ .where(eq(agents.id, key.agentId))
105
+ .then((rows) => rows[0] ?? null);
106
+ if (!agentRecord || agentRecord.status === "terminated" || agentRecord.status === "pending_approval") {
107
+ next();
108
+ return;
109
+ }
110
+ req.actor = {
111
+ type: "agent",
112
+ agentId: key.agentId,
113
+ companyId: key.companyId,
114
+ keyId: key.id,
115
+ runId: runIdHeader || undefined,
116
+ source: "agent_key",
117
+ };
118
+ next();
119
+ };
120
+ }
121
+ export function requireBoard(req) {
122
+ return req.actor.type === "board";
123
+ }
124
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RequestHandler } from "express";
2
+ export declare function boardMutationGuard(): RequestHandler;
3
+ //# sourceMappingURL=board-mutation-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-mutation-guard.d.ts","sourceRoot":"","sources":["../../src/middleware/board-mutation-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,cAAc,EAAE,MAAM,SAAS,CAAC;AAuCvD,wBAAgB,kBAAkB,IAAI,cAAc,CA2BnD"}