teamcopilot 0.0.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 (209) hide show
  1. package/.env.example +10 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +131 -0
  4. package/bin/teamcopilot.js +281 -0
  5. package/dist/auth/index.js +189 -0
  6. package/dist/change-user-role.js +77 -0
  7. package/dist/chat/index.js +849 -0
  8. package/dist/constants.js +2 -0
  9. package/dist/create-user.js +98 -0
  10. package/dist/cronjob/index.js +16 -0
  11. package/dist/cronjob/resource-reconciliation.js +33 -0
  12. package/dist/delete-user.js +66 -0
  13. package/dist/frontend/assets/abap-CRCWOmpq.js +1 -0
  14. package/dist/frontend/assets/apex-DnsZk_dE.js +1 -0
  15. package/dist/frontend/assets/azcli-1IWB1ccx.js +1 -0
  16. package/dist/frontend/assets/bat-DPkNLes8.js +1 -0
  17. package/dist/frontend/assets/bicep-Corcdgou.js +2 -0
  18. package/dist/frontend/assets/cameligo-CGrWLZr3.js +1 -0
  19. package/dist/frontend/assets/clojure-D9WOWImG.js +1 -0
  20. package/dist/frontend/assets/codicon-DCmgc-ay.ttf +0 -0
  21. package/dist/frontend/assets/coffee-B7EJu28W.js +1 -0
  22. package/dist/frontend/assets/cpp-SEyurbux.js +1 -0
  23. package/dist/frontend/assets/csharp-BoL64M5l.js +1 -0
  24. package/dist/frontend/assets/csp-C46ZqvIl.js +1 -0
  25. package/dist/frontend/assets/css-DQU6DXDx.js +3 -0
  26. package/dist/frontend/assets/cssMode-BDT3WbVs.js +4 -0
  27. package/dist/frontend/assets/cypher-D84EuPTj.js +1 -0
  28. package/dist/frontend/assets/dart-D8lhlL1r.js +1 -0
  29. package/dist/frontend/assets/dockerfile-DLk6rpji.js +1 -0
  30. package/dist/frontend/assets/ecl-BO6FnfXk.js +1 -0
  31. package/dist/frontend/assets/editor.worker-B4pQIWZD.js +12 -0
  32. package/dist/frontend/assets/elixir-BRjLKONM.js +1 -0
  33. package/dist/frontend/assets/flow9-Cac8vKd7.js +1 -0
  34. package/dist/frontend/assets/freemarker2-C7-hEgID.js +3 -0
  35. package/dist/frontend/assets/fsharp-fd1GTHhf.js +1 -0
  36. package/dist/frontend/assets/go-O9LJTZXk.js +1 -0
  37. package/dist/frontend/assets/graphql-LQdxqEYJ.js +1 -0
  38. package/dist/frontend/assets/handlebars-4cwTkPir.js +1 -0
  39. package/dist/frontend/assets/hcl-DxDQ3s82.js +1 -0
  40. package/dist/frontend/assets/html-YNfE1Q0A.js +1 -0
  41. package/dist/frontend/assets/htmlMode-opTQ1HoB.js +4 -0
  42. package/dist/frontend/assets/index-DWyaVa1h.js +782 -0
  43. package/dist/frontend/assets/index-lXrsgeTF.css +1 -0
  44. package/dist/frontend/assets/ini-BvajGCUy.js +1 -0
  45. package/dist/frontend/assets/java-SYsfObOQ.js +1 -0
  46. package/dist/frontend/assets/javascript-BEwGzk7T.js +1 -0
  47. package/dist/frontend/assets/jsonMode-CGhIS5Al.js +10 -0
  48. package/dist/frontend/assets/julia-DQXNmw_w.js +1 -0
  49. package/dist/frontend/assets/kotlin-qQ0MG-9I.js +1 -0
  50. package/dist/frontend/assets/less-GGFNNJHn.js +2 -0
  51. package/dist/frontend/assets/lexon-Canl7DCW.js +1 -0
  52. package/dist/frontend/assets/liquid-QekTGCGJ.js +1 -0
  53. package/dist/frontend/assets/lua-D28Ae8-K.js +1 -0
  54. package/dist/frontend/assets/m3-DPitgjJI.js +1 -0
  55. package/dist/frontend/assets/markdown-B811l8j2.js +1 -0
  56. package/dist/frontend/assets/mdx-BAVDaB7v.js +1 -0
  57. package/dist/frontend/assets/mips-CdjsipkG.js +1 -0
  58. package/dist/frontend/assets/msdax-CYqgjx_P.js +1 -0
  59. package/dist/frontend/assets/mysql-BHd6q0vd.js +1 -0
  60. package/dist/frontend/assets/objective-c-B1aVtJYH.js +1 -0
  61. package/dist/frontend/assets/pascal-BhNW15KB.js +1 -0
  62. package/dist/frontend/assets/pascaligo-5jv8CcQD.js +1 -0
  63. package/dist/frontend/assets/perl-DlYyT36c.js +1 -0
  64. package/dist/frontend/assets/pgsql-Dy0bjov7.js +1 -0
  65. package/dist/frontend/assets/php-120yhfDK.js +1 -0
  66. package/dist/frontend/assets/pla-CjnFlu4u.js +1 -0
  67. package/dist/frontend/assets/postiats-CQpG440k.js +1 -0
  68. package/dist/frontend/assets/powerquery-DdJtto1Z.js +1 -0
  69. package/dist/frontend/assets/powershell-Bu_VLpJB.js +1 -0
  70. package/dist/frontend/assets/protobuf-IBS6jZEB.js +2 -0
  71. package/dist/frontend/assets/pug-kFxLfcjb.js +1 -0
  72. package/dist/frontend/assets/python-BQlHw7XO.js +1 -0
  73. package/dist/frontend/assets/qsharp-q7JyzKFN.js +1 -0
  74. package/dist/frontend/assets/r-BIFz-_sK.js +1 -0
  75. package/dist/frontend/assets/razor-Be3Wwc2E.js +1 -0
  76. package/dist/frontend/assets/redis-CHOsPHWR.js +1 -0
  77. package/dist/frontend/assets/redshift-CBifECDb.js +1 -0
  78. package/dist/frontend/assets/restructuredtext-CghPJEOS.js +1 -0
  79. package/dist/frontend/assets/ruby-CYWGW-b1.js +1 -0
  80. package/dist/frontend/assets/rust-DMDD0SHb.js +1 -0
  81. package/dist/frontend/assets/sb-BYAiYHFx.js +1 -0
  82. package/dist/frontend/assets/scala-Bqvq8jcR.js +1 -0
  83. package/dist/frontend/assets/scheme-Dhb-2j9p.js +1 -0
  84. package/dist/frontend/assets/scss-CTwUZ5N7.js +3 -0
  85. package/dist/frontend/assets/shell-CsDZo4DB.js +1 -0
  86. package/dist/frontend/assets/solidity-CME5AdoB.js +1 -0
  87. package/dist/frontend/assets/sophia-RYC1BQQz.js +1 -0
  88. package/dist/frontend/assets/sparql-KEyrF7De.js +1 -0
  89. package/dist/frontend/assets/sql-BdTr02Mf.js +1 -0
  90. package/dist/frontend/assets/st-C7iG7M4S.js +1 -0
  91. package/dist/frontend/assets/swift-D7IUmUK8.js +1 -0
  92. package/dist/frontend/assets/systemverilog-DgMryOEJ.js +1 -0
  93. package/dist/frontend/assets/tcl-PloMZuKG.js +1 -0
  94. package/dist/frontend/assets/tsMode-CIBFoN3z.js +11 -0
  95. package/dist/frontend/assets/twig-BfRIq3la.js +1 -0
  96. package/dist/frontend/assets/typescript-BuV9wEIE.js +1 -0
  97. package/dist/frontend/assets/typespec-CzxlYoT_.js +1 -0
  98. package/dist/frontend/assets/vb-BwAE3J76.js +1 -0
  99. package/dist/frontend/assets/wgsl-B_1kOXbF.js +298 -0
  100. package/dist/frontend/assets/xml-DcDKYaM4.js +1 -0
  101. package/dist/frontend/assets/yaml-CuBNmOuI.js +1 -0
  102. package/dist/frontend/index.html +14 -0
  103. package/dist/frontend/logo.svg +50 -0
  104. package/dist/index.js +169 -0
  105. package/dist/logging.js +30 -0
  106. package/dist/opencode-auth/index.js +122 -0
  107. package/dist/opencode-server.js +91 -0
  108. package/dist/prisma/client.js +38 -0
  109. package/dist/reset-password.js +73 -0
  110. package/dist/rotate-jwt-secret.js +20 -0
  111. package/dist/scripts/prisma-workspace.js +34 -0
  112. package/dist/skills/index.js +311 -0
  113. package/dist/types/permissions.js +2 -0
  114. package/dist/types/shared/permissions.js +17 -0
  115. package/dist/types/shared/skill.js +17 -0
  116. package/dist/types/shared/workflow-files.js +17 -0
  117. package/dist/types/shared/workflow.js +17 -0
  118. package/dist/types/skill.js +2 -0
  119. package/dist/types/workflow-files.js +2 -0
  120. package/dist/types/workflow.js +2 -0
  121. package/dist/users/index.js +22 -0
  122. package/dist/utils/approval-snapshot-common.js +596 -0
  123. package/dist/utils/assert.js +20 -0
  124. package/dist/utils/chat-session.js +44 -0
  125. package/dist/utils/cli-bootstrap.js +26 -0
  126. package/dist/utils/index.js +95 -0
  127. package/dist/utils/jwt-secret.js +63 -0
  128. package/dist/utils/opencode-auth.js +126 -0
  129. package/dist/utils/opencode-client.js +109 -0
  130. package/dist/utils/password-policy.js +12 -0
  131. package/dist/utils/permission-common.js +280 -0
  132. package/dist/utils/redact.js +108 -0
  133. package/dist/utils/resource-access.js +37 -0
  134. package/dist/utils/resource-file-routes.js +115 -0
  135. package/dist/utils/resource-files.js +572 -0
  136. package/dist/utils/runtime-paths.js +61 -0
  137. package/dist/utils/session-abort.js +52 -0
  138. package/dist/utils/skill-approval-snapshot.js +39 -0
  139. package/dist/utils/skill-files.js +17 -0
  140. package/dist/utils/skill-permissions.js +15 -0
  141. package/dist/utils/skill.js +217 -0
  142. package/dist/utils/user-role.js +14 -0
  143. package/dist/utils/workflow-approval-snapshot.js +38 -0
  144. package/dist/utils/workflow-files.js +17 -0
  145. package/dist/utils/workflow-interruption.js +50 -0
  146. package/dist/utils/workflow-permissions.js +27 -0
  147. package/dist/utils/workflow-runner.js +414 -0
  148. package/dist/utils/workflow.js +158 -0
  149. package/dist/utils/workspace-sync.js +204 -0
  150. package/dist/workflows/index.js +751 -0
  151. package/dist/workspace_files/.opencode/opencode.json +17 -0
  152. package/dist/workspace_files/.opencode/package.json +14 -0
  153. package/dist/workspace_files/.opencode/plugins/createSkill.ts +339 -0
  154. package/dist/workspace_files/.opencode/plugins/createWorkflow.ts +345 -0
  155. package/dist/workspace_files/.opencode/plugins/findSimilarWorkflow.ts +173 -0
  156. package/dist/workspace_files/.opencode/plugins/findSkill.ts +211 -0
  157. package/dist/workspace_files/.opencode/plugins/getSkillContent.ts +135 -0
  158. package/dist/workspace_files/.opencode/plugins/honeytoken-protection.ts +64 -0
  159. package/dist/workspace_files/.opencode/plugins/listAvailableSkills.ts +93 -0
  160. package/dist/workspace_files/.opencode/plugins/listAvailableWorkflows.ts +93 -0
  161. package/dist/workspace_files/.opencode/plugins/python-protection.ts +184 -0
  162. package/dist/workspace_files/.opencode/plugins/runWorkflow.ts +168 -0
  163. package/dist/workspace_files/.opencode/tsconfig.json +16 -0
  164. package/dist/workspace_files/AGENTS.md +483 -0
  165. package/dist/workspace_files/package-lock.json +167 -0
  166. package/dist/workspace_files/package.json +5 -0
  167. package/package.json +86 -0
  168. package/prisma/migrations/20260203040755_init/migration.sql +20 -0
  169. package/prisma/migrations/20260204034845_replace_google_auth_with_email_password/migration.sql +25 -0
  170. package/prisma/migrations/20260207022226_add_user_role/migration.sql +25 -0
  171. package/prisma/migrations/20260210161254_add_workflow_runs/migration.sql +16 -0
  172. package/prisma/migrations/20260211050606_adds_workflow_table/migration.sql +40 -0
  173. package/prisma/migrations/20260211050750_adds_fkey_constraint/migration.sql +21 -0
  174. package/prisma/migrations/20260211051912_removes_workflow_table/migration.sql +34 -0
  175. package/prisma/migrations/20260211052238_changes_workflow_id_to_slug/migration.sql +27 -0
  176. package/prisma/migrations/20260212051912_add_output_to_workflow_runs/migration.sql +2 -0
  177. package/prisma/migrations/20260213073006_add_chat_sessions/migration.sql +13 -0
  178. package/prisma/migrations/20260216053202_add_chat_sessions_opencode_session_id_idx/migration.sql +2 -0
  179. package/prisma/migrations/20260216053237_drop_redundant_chat_sessions_opencode_idx/migration.sql +2 -0
  180. package/prisma/migrations/20260219060705_makes/migration.sql +24 -0
  181. package/prisma/migrations/20260222040542_add_workflow_execution_permissions/migration.sql +18 -0
  182. package/prisma/migrations/20260222040815_remove_workflow_execution_permissions/migration.sql +10 -0
  183. package/prisma/migrations/20260222041348_add_workflow_execution_permissions_final/migration.sql +17 -0
  184. package/prisma/migrations/20260222041741_rename_to_tool_execution_permissions/migration.sql +30 -0
  185. package/prisma/migrations/20260222041826_simplify_tool_execution_permissions/migration.sql +29 -0
  186. package/prisma/migrations/20260222041950_add_fields_for_standalone_permissions/migration.sql +32 -0
  187. package/prisma/migrations/20260222042954_simplify_tool_permissions_table/migration.sql +27 -0
  188. package/prisma/migrations/20260223073902_add_workflow_run_permissions_tables/migration.sql +23 -0
  189. package/prisma/migrations/20260225025151_add_workflow_metadata/migration.sql +16 -0
  190. package/prisma/migrations/20260225031035_merge_workflow_permissions_into_metadata/migration.sql +44 -0
  191. package/prisma/migrations/20260225031752_removes_default_for_run_permission_mode/migration.sql +20 -0
  192. package/prisma/migrations/20260225033603_remove_workflow_metadata_user_fkeys/migration.sql +18 -0
  193. package/prisma/migrations/20260225043032_restore_workflow_metadata_user_fkeys/migration.sql +20 -0
  194. package/prisma/migrations/20260225091423_add_workflow_approved_snapshots/migration.sql +28 -0
  195. package/prisma/migrations/20260226032121_add_is_approved_to_workflow_metadata/migration.sql +21 -0
  196. package/prisma/migrations/20260226032444_undoes_last_db_change/migration.sql +26 -0
  197. package/prisma/migrations/20260227120000_remove_snapshot_hash_from_approved_snapshots/migration.sql +16 -0
  198. package/prisma/migrations/20260228071125_adds_workspace_path_to_snapshot_table/migration.sql +22 -0
  199. package/prisma/migrations/20260228071217_modifies_index_and_removes_default_value/migration.sql +22 -0
  200. package/prisma/migrations/20260228071710_undoes_previous/migration.sql +27 -0
  201. package/prisma/migrations/20260228105022_add_must_change_password_first_login/migration.sql +20 -0
  202. package/prisma/migrations/20260301115439_add_workflow_run_log_refs/migration.sql +8 -0
  203. package/prisma/migrations/20260301122557_add_workflow_aborted_sessions/migration.sql +5 -0
  204. package/prisma/migrations/20260302045545_move_workflow_run_log_refs_into_workflow_runs/migration.sql +17 -0
  205. package/prisma/migrations/20260303040318_add_skill_tables/migration.sql +61 -0
  206. package/prisma/migrations/20260303051533_unify_resource_permissions/migration.sql +97 -0
  207. package/prisma/migrations/20260303064255_unify_resource_metadata_and_snapshots/migration.sql +179 -0
  208. package/prisma/migrations/migration_lock.toml +3 -0
  209. package/prisma/schema.prisma +147 -0
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.maskValue = maskValue;
4
+ exports.isLikelySensitiveKey = isLikelySensitiveKey;
5
+ exports.sanitizeStringContent = sanitizeStringContent;
6
+ exports.sanitizeForClient = sanitizeForClient;
7
+ const SENSITIVE_KEY_PATTERN = /(token|secret|password|passwd|api[_-]?key|auth|credential)/i;
8
+ function maskValue(value) {
9
+ if (value.startsWith("***")) {
10
+ return value;
11
+ }
12
+ const suffixLength = value.length <= 3 ? 1 : 3;
13
+ const tail = value.slice(-suffixLength);
14
+ return `***${tail}`;
15
+ }
16
+ function isLikelySensitiveKey(key) {
17
+ return SENSITIVE_KEY_PATTERN.test(key);
18
+ }
19
+ function sanitizeStringContent(input) {
20
+ let text = input;
21
+ // Redact Authorization header bearer tokens before generic key/value masking so
22
+ // "Authorization: Bearer <token>" doesn't get partially masked as "***rer".
23
+ text = text.replace(/(\bAuthorization\s*[:=]\s*)(Bearer\s+)([A-Za-z0-9._~+/=-]{8,})/gi, (_full, prefix, bearer, token) => `${prefix}${bearer}${maskValue(token)}`);
24
+ // Redact sensitive markdown list/label items such as:
25
+ // - **password**: value
26
+ // - **password** = value
27
+ // > __token__ : "value"
28
+ text = text.replace(/(^|[\r\n])([ \t>]*(?:[-*+][ \t]+)?)(\*\*|__)[ \t]*([A-Za-z_][A-Za-z0-9_-]*)[ \t]*(\3)([ \t]*(?::|=)[ \t]*)(?:"([^"\n]*)"|'([^'\n]*)'|([^\s"'#;,)\]}]+))/gm, (full, lineLead, prefix, openMarker, key, closeMarker, separator, doubleQuoted, singleQuoted, bare) => {
29
+ if (!isLikelySensitiveKey(key)) {
30
+ return full;
31
+ }
32
+ const rawValue = doubleQuoted ?? singleQuoted ?? bare ?? "";
33
+ if (!rawValue) {
34
+ return full;
35
+ }
36
+ const masked = maskValue(rawValue);
37
+ if (doubleQuoted !== undefined) {
38
+ return `${lineLead}${prefix}${openMarker}${key}${closeMarker}${separator}"${masked}"`;
39
+ }
40
+ if (singleQuoted !== undefined) {
41
+ return `${lineLead}${prefix}${openMarker}${key}${closeMarker}${separator}'${masked}'`;
42
+ }
43
+ return `${lineLead}${prefix}${openMarker}${key}${closeMarker}${separator}${masked}`;
44
+ });
45
+ // Redact sensitive env-style assignments anywhere in text, including multiple
46
+ // assignments per line and text prefixes.
47
+ text = text.replace(/(^|[^A-Za-z0-9_])((?:export[ \t]+)?([A-Za-z_][A-Za-z0-9_-]*)[ \t]*(?:=|:)[ \t]*)(?:"([^"\n]*)"|'([^'\n]*)'|([^\s"'#;,)\]}]+))/gm, (full, lead, assignmentPrefix, key, doubleQuoted, singleQuoted, bare) => {
48
+ if (!isLikelySensitiveKey(key)) {
49
+ return full;
50
+ }
51
+ const rawValue = doubleQuoted ?? singleQuoted ?? bare ?? "";
52
+ if (!rawValue) {
53
+ return full;
54
+ }
55
+ if (key.toLowerCase() === "authorization" && /^bearer$/i.test(rawValue)) {
56
+ return full;
57
+ }
58
+ const authorizationMatch = rawValue.match(/^([Bb]earer\s+)([^\s"']+)$/);
59
+ if (key.toLowerCase() === "authorization" && authorizationMatch) {
60
+ const bearerPrefix = authorizationMatch[1];
61
+ const bearerToken = authorizationMatch[2];
62
+ const maskedBearer = `${bearerPrefix}${maskValue(bearerToken)}`;
63
+ if (doubleQuoted !== undefined) {
64
+ return `${lead}${assignmentPrefix}"${maskedBearer}"`;
65
+ }
66
+ if (singleQuoted !== undefined) {
67
+ return `${lead}${assignmentPrefix}'${maskedBearer}'`;
68
+ }
69
+ return `${lead}${assignmentPrefix}${maskedBearer}`;
70
+ }
71
+ const masked = maskValue(rawValue);
72
+ if (doubleQuoted !== undefined) {
73
+ return `${lead}${assignmentPrefix}"${masked}"`;
74
+ }
75
+ if (singleQuoted !== undefined) {
76
+ return `${lead}${assignmentPrefix}'${masked}'`;
77
+ }
78
+ return `${lead}${assignmentPrefix}${masked}`;
79
+ });
80
+ // Redact common bearer and provider token forms.
81
+ text = text.replace(/\b(Bearer\s+)([A-Za-z0-9._~+/=-]{8,})\b/gi, (_full, prefix, token) => `${prefix}${maskValue(token)}`);
82
+ text = text.replace(/\b(sk-[A-Za-z0-9_-]{8,})\b/g, (token) => maskValue(token));
83
+ text = text.replace(/\b(ghp_[A-Za-z0-9]{8,})\b/g, (token) => maskValue(token));
84
+ return text;
85
+ }
86
+ function sanitizeObjectRecord(input) {
87
+ const output = {};
88
+ for (const [key, value] of Object.entries(input)) {
89
+ if (typeof value === "string" && isLikelySensitiveKey(key)) {
90
+ output[key] = maskValue(value);
91
+ continue;
92
+ }
93
+ output[key] = sanitizeForClient(value);
94
+ }
95
+ return output;
96
+ }
97
+ function sanitizeForClient(input) {
98
+ if (typeof input === "string") {
99
+ return sanitizeStringContent(input);
100
+ }
101
+ if (Array.isArray(input)) {
102
+ return input.map((item) => sanitizeForClient(item));
103
+ }
104
+ if (input && typeof input === "object") {
105
+ return sanitizeObjectRecord(input);
106
+ }
107
+ return input;
108
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getResourceAccessSummary = getResourceAccessSummary;
4
+ const permission_common_1 = require("./permission-common");
5
+ const user_role_1 = require("./user-role");
6
+ const skill_approval_snapshot_1 = require("./skill-approval-snapshot");
7
+ const workflow_approval_snapshot_1 = require("./workflow-approval-snapshot");
8
+ const skill_1 = require("./skill");
9
+ const workflow_1 = require("./workflow");
10
+ async function getResourceAccessSummary(resourceType, slug, userId) {
11
+ if (resourceType === "workflow") {
12
+ await (0, workflow_1.readWorkflowManifestAndEnsurePermissions)(slug);
13
+ }
14
+ else {
15
+ await (0, skill_1.readSkillManifestAndEnsurePermissions)(slug);
16
+ }
17
+ const permission = await (0, permission_common_1.getResourcePermissionWithUsers)(resourceType, slug, resourceType === "workflow" ? "Workflow run" : "Skill access");
18
+ const mode = (0, permission_common_1.assertCommonPermissionMode)(permission.permission_mode, resourceType === "workflow" ? "workflow run" : "skill access");
19
+ const allowedUserIds = permission.allowedUsers.map((row) => row.user_id);
20
+ const canCurrentUserUse = mode === "everyone" || allowedUserIds.includes(userId);
21
+ const isLockedDueToMissingUsers = mode === "restricted" && allowedUserIds.length === 0;
22
+ const approvalState = resourceType === "workflow"
23
+ ? await (0, workflow_approval_snapshot_1.getWorkflowSnapshotApprovalState)(slug)
24
+ : await (0, skill_approval_snapshot_1.getSkillSnapshotApprovalState)(slug);
25
+ const isEngineer = await (0, user_role_1.isEngineerUser)(userId);
26
+ const canEdit = approvalState.is_current_code_approved
27
+ ? canCurrentUserUse
28
+ : (isEngineer || canCurrentUserUse);
29
+ const canView = canEdit;
30
+ return {
31
+ permission_mode: mode,
32
+ is_locked_due_to_missing_users: isLockedDueToMissingUsers,
33
+ is_approved: approvalState.is_current_code_approved,
34
+ can_view: canView,
35
+ can_edit: canEdit,
36
+ };
37
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerResourceFileRoutes = registerResourceFileRoutes;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const index_1 = require("./index");
9
+ function registerResourceFileRoutes(options) {
10
+ const { router, uploadMiddleware, ensureResourceExists, assertCanView, getEditorAccess, assertCanEdit, listDirectory, readFileContent, saveFileContent, createFileOrFolder, uploadFileFromTempPath, renamePath, deletePath, skipResponseSanitizationForFileContentRead = true, } = options;
11
+ router.get("/:slug/files/access", (0, index_1.apiHandler)(async (req, res) => {
12
+ const slug = req.params.slug;
13
+ const authReq = req;
14
+ const access = await getEditorAccess(slug, authReq.userId);
15
+ res.json(access);
16
+ }, true));
17
+ router.get("/:slug/files/tree", (0, index_1.apiHandler)(async (req, res) => {
18
+ const slug = req.params.slug;
19
+ const authReq = req;
20
+ await assertCanView(slug, authReq.userId);
21
+ await ensureResourceExists(slug);
22
+ const rawPath = typeof req.query.path === "string" ? req.query.path : undefined;
23
+ const tree = listDirectory(slug, rawPath);
24
+ res.json(tree);
25
+ }, true));
26
+ router.get("/:slug/files/content", (0, index_1.apiHandler)(async (req, res) => {
27
+ const slug = req.params.slug;
28
+ const authReq = req;
29
+ await assertCanView(slug, authReq.userId);
30
+ await ensureResourceExists(slug);
31
+ const rawPath = typeof req.query.path === "string" ? req.query.path : undefined;
32
+ const content = readFileContent(slug, rawPath);
33
+ if (skipResponseSanitizationForFileContentRead) {
34
+ res.locals.skipResponseSanitization = true;
35
+ }
36
+ res.json(content);
37
+ }, true));
38
+ router.put("/:slug/files/content", (0, index_1.apiHandler)(async (req, res) => {
39
+ const slug = req.params.slug;
40
+ const authReq = req;
41
+ await assertCanEdit(slug, authReq.userId);
42
+ const { path, content, base_etag } = req.body;
43
+ if (typeof path !== "string" || typeof content !== "string" || typeof base_etag !== "string") {
44
+ throw {
45
+ status: 400,
46
+ message: "path, content, and base_etag are required"
47
+ };
48
+ }
49
+ const result = saveFileContent(slug, { path, content, base_etag });
50
+ res.json(result);
51
+ }, true));
52
+ router.post("/:slug/files", (0, index_1.apiHandler)(async (req, res) => {
53
+ const slug = req.params.slug;
54
+ const authReq = req;
55
+ await assertCanEdit(slug, authReq.userId);
56
+ const { parent_path, name, kind } = req.body;
57
+ if (typeof name !== "string" || (kind !== "file" && kind !== "directory")) {
58
+ throw {
59
+ status: 400,
60
+ message: 'name and kind ("file" or "directory") are required'
61
+ };
62
+ }
63
+ const node = createFileOrFolder(slug, typeof parent_path === "string" ? parent_path : "", name, kind);
64
+ res.json({ node });
65
+ }, true));
66
+ router.post("/:slug/files/upload", uploadMiddleware, (0, index_1.apiHandler)(async (req, res) => {
67
+ const slug = req.params.slug;
68
+ const authReq = req;
69
+ await assertCanEdit(slug, authReq.userId);
70
+ const { parent_path, name } = req.body;
71
+ if (typeof name !== "string") {
72
+ throw {
73
+ status: 400,
74
+ message: "name is required"
75
+ };
76
+ }
77
+ if (!authReq.file?.path) {
78
+ throw {
79
+ status: 400,
80
+ message: "file is required"
81
+ };
82
+ }
83
+ try {
84
+ const node = uploadFileFromTempPath(slug, typeof parent_path === "string" ? parent_path : "", name, authReq.file.path);
85
+ res.json({ node });
86
+ }
87
+ finally {
88
+ if (fs_1.default.existsSync(authReq.file.path)) {
89
+ fs_1.default.unlinkSync(authReq.file.path);
90
+ }
91
+ }
92
+ }, true));
93
+ router.patch("/:slug/files/rename", (0, index_1.apiHandler)(async (req, res) => {
94
+ const slug = req.params.slug;
95
+ const authReq = req;
96
+ await assertCanEdit(slug, authReq.userId);
97
+ const { path, new_name } = req.body;
98
+ if (typeof path !== "string" || typeof new_name !== "string") {
99
+ throw {
100
+ status: 400,
101
+ message: "path and new_name are required"
102
+ };
103
+ }
104
+ const result = renamePath(slug, path, new_name);
105
+ res.json(result);
106
+ }, true));
107
+ router.delete("/:slug/files", (0, index_1.apiHandler)(async (req, res) => {
108
+ const slug = req.params.slug;
109
+ const authReq = req;
110
+ await assertCanEdit(slug, authReq.userId);
111
+ const rawPath = typeof req.query.path === "string" ? req.query.path : undefined;
112
+ deletePath(slug, rawPath);
113
+ res.json({ success: true });
114
+ }, true));
115
+ }