@knpkv/codecommit-core 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/dist/AwsClient/AwsClientGated.d.ts +30 -0
  2. package/dist/AwsClient/AwsClientGated.d.ts.map +1 -0
  3. package/dist/AwsClient/AwsClientGated.js +111 -0
  4. package/dist/AwsClient/AwsClientGated.js.map +1 -0
  5. package/dist/AwsClient/createApprovalRule.d.ts +4 -0
  6. package/dist/AwsClient/createApprovalRule.d.ts.map +1 -0
  7. package/dist/AwsClient/createApprovalRule.js +17 -0
  8. package/dist/AwsClient/createApprovalRule.js.map +1 -0
  9. package/dist/AwsClient/deleteApprovalRule.d.ts +4 -0
  10. package/dist/AwsClient/deleteApprovalRule.d.ts.map +1 -0
  11. package/dist/AwsClient/deleteApprovalRule.js +16 -0
  12. package/dist/AwsClient/deleteApprovalRule.js.map +1 -0
  13. package/dist/AwsClient/getPullRequest.d.ts.map +1 -1
  14. package/dist/AwsClient/getPullRequest.js +34 -7
  15. package/dist/AwsClient/getPullRequest.js.map +1 -1
  16. package/dist/AwsClient/getPullRequests.d.ts +81 -1
  17. package/dist/AwsClient/getPullRequests.d.ts.map +1 -1
  18. package/dist/AwsClient/getPullRequests.js +123 -17
  19. package/dist/AwsClient/getPullRequests.js.map +1 -1
  20. package/dist/AwsClient/index.d.ts +13 -1
  21. package/dist/AwsClient/index.d.ts.map +1 -1
  22. package/dist/AwsClient/index.js +16 -1
  23. package/dist/AwsClient/index.js.map +1 -1
  24. package/dist/AwsClient/internal.d.ts +63 -1
  25. package/dist/AwsClient/internal.d.ts.map +1 -1
  26. package/dist/AwsClient/internal.js +37 -3
  27. package/dist/AwsClient/internal.js.map +1 -1
  28. package/dist/AwsClient/updateApprovalRule.d.ts +4 -0
  29. package/dist/AwsClient/updateApprovalRule.d.ts.map +1 -0
  30. package/dist/AwsClient/updateApprovalRule.js +17 -0
  31. package/dist/AwsClient/updateApprovalRule.js.map +1 -0
  32. package/dist/CacheService/Database.d.ts +4 -0
  33. package/dist/CacheService/Database.d.ts.map +1 -1
  34. package/dist/CacheService/Database.js +15 -1
  35. package/dist/CacheService/Database.js.map +1 -1
  36. package/dist/CacheService/EventsHub.d.ts +44 -4
  37. package/dist/CacheService/EventsHub.d.ts.map +1 -1
  38. package/dist/CacheService/EventsHub.js.map +1 -1
  39. package/dist/CacheService/diff.d.ts +17 -1
  40. package/dist/CacheService/diff.d.ts.map +1 -1
  41. package/dist/CacheService/diff.js +34 -0
  42. package/dist/CacheService/diff.js.map +1 -1
  43. package/dist/CacheService/index.d.ts +5 -1
  44. package/dist/CacheService/index.d.ts.map +1 -1
  45. package/dist/CacheService/index.js +5 -1
  46. package/dist/CacheService/index.js.map +1 -1
  47. package/dist/CacheService/migrations/0011_audit_log.d.ts +5 -0
  48. package/dist/CacheService/migrations/0011_audit_log.d.ts.map +1 -0
  49. package/dist/CacheService/migrations/0011_audit_log.js +19 -0
  50. package/dist/CacheService/migrations/0011_audit_log.js.map +1 -0
  51. package/dist/CacheService/migrations/0012_audit_log_indexes.d.ts +5 -0
  52. package/dist/CacheService/migrations/0012_audit_log_indexes.d.ts.map +1 -0
  53. package/dist/CacheService/migrations/0012_audit_log_indexes.js +7 -0
  54. package/dist/CacheService/migrations/0012_audit_log_indexes.js.map +1 -0
  55. package/dist/CacheService/migrations/0013_approval_rules.d.ts +5 -0
  56. package/dist/CacheService/migrations/0013_approval_rules.d.ts.map +1 -0
  57. package/dist/CacheService/migrations/0013_approval_rules.js +4 -0
  58. package/dist/CacheService/migrations/0013_approval_rules.js.map +1 -0
  59. package/dist/CacheService/migrations/0014_approved_by_arns.d.ts +5 -0
  60. package/dist/CacheService/migrations/0014_approved_by_arns.d.ts.map +1 -0
  61. package/dist/CacheService/migrations/0014_approved_by_arns.js +4 -0
  62. package/dist/CacheService/migrations/0014_approved_by_arns.js.map +1 -0
  63. package/dist/CacheService/migrations/0015_repo_account_id.d.ts +5 -0
  64. package/dist/CacheService/migrations/0015_repo_account_id.d.ts.map +1 -0
  65. package/dist/CacheService/migrations/0015_repo_account_id.js +4 -0
  66. package/dist/CacheService/migrations/0015_repo_account_id.js.map +1 -0
  67. package/dist/CacheService/repos/NotificationRepo.d.ts.map +1 -1
  68. package/dist/CacheService/repos/NotificationRepo.js +2 -2
  69. package/dist/CacheService/repos/NotificationRepo.js.map +1 -1
  70. package/dist/CacheService/repos/PullRequestRepo/index.d.ts +10 -0
  71. package/dist/CacheService/repos/PullRequestRepo/index.d.ts.map +1 -1
  72. package/dist/CacheService/repos/PullRequestRepo/internal.d.ts +15 -0
  73. package/dist/CacheService/repos/PullRequestRepo/internal.d.ts.map +1 -1
  74. package/dist/CacheService/repos/PullRequestRepo/internal.js +30 -4
  75. package/dist/CacheService/repos/PullRequestRepo/internal.js.map +1 -1
  76. package/dist/CacheService/repos/PullRequestRepo/mutations.d.ts +12 -2
  77. package/dist/CacheService/repos/PullRequestRepo/mutations.d.ts.map +1 -1
  78. package/dist/CacheService/repos/PullRequestRepo/mutations.js +21 -5
  79. package/dist/CacheService/repos/PullRequestRepo/mutations.js.map +1 -1
  80. package/dist/CacheService/repos/PullRequestRepo/queries.d.ts +9 -0
  81. package/dist/CacheService/repos/PullRequestRepo/queries.d.ts.map +1 -1
  82. package/dist/CacheService/repos/StatsRepo/internal.d.ts.map +1 -1
  83. package/dist/CacheService/repos/StatsRepo/internal.js +5 -4
  84. package/dist/CacheService/repos/StatsRepo/internal.js.map +1 -1
  85. package/dist/Domain.d.ts +106 -7
  86. package/dist/Domain.d.ts.map +1 -1
  87. package/dist/Domain.js +66 -6
  88. package/dist/Domain.js.map +1 -1
  89. package/dist/Errors.d.ts +14 -1
  90. package/dist/Errors.d.ts.map +1 -1
  91. package/dist/Errors.js +10 -0
  92. package/dist/Errors.js.map +1 -1
  93. package/dist/PRService/internal.d.ts +23 -0
  94. package/dist/PRService/internal.d.ts.map +1 -1
  95. package/dist/PRService/internal.js +20 -5
  96. package/dist/PRService/internal.js.map +1 -1
  97. package/dist/PRService/refreshFetch.d.ts +5 -1
  98. package/dist/PRService/refreshFetch.d.ts.map +1 -1
  99. package/dist/PRService/refreshFetch.js +15 -4
  100. package/dist/PRService/refreshFetch.js.map +1 -1
  101. package/dist/PRService/refreshSinglePR.d.ts +7 -0
  102. package/dist/PRService/refreshSinglePR.d.ts.map +1 -1
  103. package/dist/PRService/refreshSinglePR.js +16 -3
  104. package/dist/PRService/refreshSinglePR.js.map +1 -1
  105. package/dist/PermissionService/AuditLog.d.ts +63 -0
  106. package/dist/PermissionService/AuditLog.d.ts.map +1 -0
  107. package/dist/PermissionService/AuditLog.js +127 -0
  108. package/dist/PermissionService/AuditLog.js.map +1 -0
  109. package/dist/PermissionService/PermissionGate.d.ts +47 -0
  110. package/dist/PermissionService/PermissionGate.d.ts.map +1 -0
  111. package/dist/PermissionService/PermissionGate.js +14 -0
  112. package/dist/PermissionService/PermissionGate.js.map +1 -0
  113. package/dist/PermissionService/PermissionGateLive.d.ts +41 -0
  114. package/dist/PermissionService/PermissionGateLive.d.ts.map +1 -0
  115. package/dist/PermissionService/PermissionGateLive.js +83 -0
  116. package/dist/PermissionService/PermissionGateLive.js.map +1 -0
  117. package/dist/PermissionService/index.d.ts +39 -0
  118. package/dist/PermissionService/index.d.ts.map +1 -0
  119. package/dist/PermissionService/index.js +87 -0
  120. package/dist/PermissionService/index.js.map +1 -0
  121. package/dist/PermissionService/operations.d.ts +53 -0
  122. package/dist/PermissionService/operations.d.ts.map +1 -0
  123. package/dist/PermissionService/operations.js +51 -0
  124. package/dist/PermissionService/operations.js.map +1 -0
  125. package/dist/index.d.ts +1 -0
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +1 -0
  128. package/dist/index.js.map +1 -1
  129. package/package.json +1 -1
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @title AuditLogRepo — records every AWS API call
3
+ *
4
+ * Every call through the permission gate gets recorded — allowed, denied,
5
+ * or timed out.
6
+ *
7
+ * Design constraints:
8
+ * - MUST never block API calls (catchAll on write failures at call site)
9
+ * - MUST handle high volume (~17 ops per refresh × every 5min)
10
+ * - MUST auto-prune (150k entries/month without pruning)
11
+ * - MUST support filtered queries (for the audit log UI page)
12
+ *
13
+ * `durationMs` is null when the API call was denied/timed out (never ran).
14
+ * When present, it reflects actual AWS API latency — not permission prompt wait.
15
+ *
16
+ * @module
17
+ */
18
+ import * as SqlClient from "@effect/sql/SqlClient";
19
+ import { Effect, Schema } from "effect";
20
+ import { CacheError } from "../CacheService/CacheError.js";
21
+ export declare const AuditLogEntry: Schema.Struct<{
22
+ id: typeof Schema.Number;
23
+ timestamp: typeof Schema.String;
24
+ operation: typeof Schema.String;
25
+ accountProfile: typeof Schema.String;
26
+ region: typeof Schema.String;
27
+ permissionState: Schema.Literal<["allowed", "always_allowed", "denied", "timed_out"]>;
28
+ context: typeof Schema.String;
29
+ durationMs: Schema.NullOr<typeof Schema.Number>;
30
+ }>;
31
+ export type AuditLogEntry = typeof AuditLogEntry.Type;
32
+ export type NewAuditLogEntry = Omit<AuditLogEntry, "id">;
33
+ export interface PaginatedAuditLog {
34
+ readonly items: ReadonlyArray<AuditLogEntry>;
35
+ readonly total: number;
36
+ readonly nextCursor?: number;
37
+ }
38
+ declare const AuditLogRepo_base: Effect.Service.Class<AuditLogRepo, "AuditLogRepo", {
39
+ readonly dependencies: readonly [import("effect/Layer").Layer<SqlClient.SqlClient | import("@effect/sql-libsql/LibsqlClient").LibsqlClient, import("@effect/sql/SqlError").SqlError | import("effect/ConfigError").ConfigError | import("@effect/sql/Migrator").MigrationError, import("@effect/platform/FileSystem").FileSystem>];
40
+ readonly effect: Effect.Effect<{
41
+ log: (entry: NewAuditLogEntry) => Effect.Effect<void, CacheError, never>;
42
+ findAll: (opts?: {
43
+ readonly limit?: number | undefined;
44
+ readonly offset?: number | undefined;
45
+ readonly operation?: string | undefined;
46
+ readonly accountProfile?: string | undefined;
47
+ readonly permissionState?: string | undefined;
48
+ readonly from?: string | undefined;
49
+ readonly to?: string | undefined;
50
+ readonly search?: string | undefined;
51
+ }) => Effect.Effect<PaginatedAuditLog, CacheError>;
52
+ prune: (retentionDays: number) => Effect.Effect<number, CacheError>;
53
+ clearAll: () => Effect.Effect<number, CacheError>;
54
+ exportAll: (opts?: {
55
+ readonly from?: string | undefined;
56
+ readonly to?: string | undefined;
57
+ }) => Effect.Effect<ReadonlyArray<AuditLogEntry>, CacheError>;
58
+ }, never, SqlClient.SqlClient>;
59
+ }>;
60
+ export declare class AuditLogRepo extends AuditLogRepo_base {
61
+ }
62
+ export {};
63
+ //# sourceMappingURL=AuditLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuditLog.d.ts","sourceRoot":"","sources":["../../src/PermissionService/AuditLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAG1D,eAAO,MAAM,aAAa;;;;;;;;;EASxB,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAA;AAErD,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAA;AAExD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;;;;qBAmCkB,gBAAgB;yBAQZ;YACf,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YACvC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YAC5C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YAC7C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SACrC,KAAG,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,UAAU,CAAC;+BAmDzB,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;wBAWnD,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;2BAO5B;YACjB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SACjC,KAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,UAAU,CAAC;;;AApHjE,qBAAa,YAAa,SAAQ,iBAmIhC;CAAG"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @title AuditLogRepo — records every AWS API call
3
+ *
4
+ * Every call through the permission gate gets recorded — allowed, denied,
5
+ * or timed out.
6
+ *
7
+ * Design constraints:
8
+ * - MUST never block API calls (catchAll on write failures at call site)
9
+ * - MUST handle high volume (~17 ops per refresh × every 5min)
10
+ * - MUST auto-prune (150k entries/month without pruning)
11
+ * - MUST support filtered queries (for the audit log UI page)
12
+ *
13
+ * `durationMs` is null when the API call was denied/timed out (never ran).
14
+ * When present, it reflects actual AWS API latency — not permission prompt wait.
15
+ *
16
+ * @module
17
+ */
18
+ import * as SqlClient from "@effect/sql/SqlClient";
19
+ import * as SqlSchema from "@effect/sql/SqlSchema";
20
+ import * as Statement from "@effect/sql/Statement";
21
+ import { Effect, Schema } from "effect";
22
+ import { CacheError } from "../CacheService/CacheError.js";
23
+ import { DatabaseLive } from "../CacheService/Database.js";
24
+ export const AuditLogEntry = Schema.Struct({
25
+ id: Schema.Number,
26
+ timestamp: Schema.String,
27
+ operation: Schema.String,
28
+ accountProfile: Schema.String,
29
+ region: Schema.String,
30
+ permissionState: Schema.Literal("allowed", "always_allowed", "denied", "timed_out"),
31
+ context: Schema.String,
32
+ durationMs: Schema.NullOr(Schema.Number)
33
+ });
34
+ const cacheError = (op) => (effect) => effect.pipe(Effect.mapError((cause) => new CacheError({ operation: `AuditLogRepo.${op}`, cause })), Effect.withSpan(`AuditLogRepo.${op}`, { captureStackTrace: false }));
35
+ export class AuditLogRepo extends Effect.Service()("AuditLogRepo", {
36
+ dependencies: [DatabaseLive],
37
+ effect: Effect.gen(function* () {
38
+ const sql = yield* SqlClient.SqlClient;
39
+ const findAll_ = SqlSchema.findAll({
40
+ Result: AuditLogEntry,
41
+ Request: Schema.Struct({
42
+ limit: Schema.Number,
43
+ offset: Schema.Number
44
+ }),
45
+ execute: (req) => sql `SELECT * FROM audit_log ORDER BY id DESC LIMIT ${req.limit} OFFSET ${req.offset}`
46
+ });
47
+ const countAll = SqlSchema.single({
48
+ Result: Schema.Struct({ count: Schema.Number }),
49
+ Request: Schema.Void,
50
+ execute: () => sql `SELECT count(*) as count FROM audit_log`
51
+ });
52
+ const exportAllQuery = SqlSchema.findAll({
53
+ Result: AuditLogEntry,
54
+ Request: Schema.Void,
55
+ execute: () => sql `SELECT * FROM audit_log ORDER BY id DESC`
56
+ });
57
+ return {
58
+ log: (entry) => sql `INSERT INTO audit_log (timestamp, operation, account_profile, region, permission_state, context, duration_ms)
59
+ VALUES (${entry.timestamp}, ${entry.operation}, ${entry.accountProfile}, ${entry.region}, ${entry.permissionState}, ${entry.context}, ${entry.durationMs})`
60
+ .pipe(Effect.asVoid, cacheError("log")),
61
+ findAll: (opts) => {
62
+ // Clamp numeric params
63
+ const limit = Math.max(1, Math.min(200, Math.floor(opts?.limit ?? 50)));
64
+ const offset = Math.max(0, Math.floor(opts?.offset ?? 0));
65
+ // Compose parameterized WHERE using Statement.and
66
+ const hasFilter = opts?.operation || opts?.accountProfile || opts?.permissionState
67
+ || opts?.from || opts?.to || opts?.search;
68
+ if (hasFilter) {
69
+ const conditions = [];
70
+ if (opts?.operation)
71
+ conditions.push(sql `operation = ${opts.operation}`);
72
+ if (opts?.accountProfile)
73
+ conditions.push(sql `account_profile = ${opts.accountProfile}`);
74
+ if (opts?.permissionState)
75
+ conditions.push(sql `permission_state = ${opts.permissionState}`);
76
+ if (opts?.from)
77
+ conditions.push(sql `timestamp >= ${opts.from}`);
78
+ if (opts?.to)
79
+ conditions.push(sql `timestamp <= ${opts.to}`);
80
+ if (opts?.search) {
81
+ const pattern = `%${opts.search}%`;
82
+ conditions.push(sql `(operation LIKE ${pattern} OR context LIKE ${pattern})`);
83
+ }
84
+ const where = Statement.and(conditions);
85
+ return Effect.all([
86
+ sql `SELECT * FROM audit_log WHERE ${where} ORDER BY id DESC LIMIT ${limit} OFFSET ${offset}`.pipe(Effect.map((rows) => rows.map((r) => Schema.decodeUnknownSync(AuditLogEntry)(r)))),
87
+ sql `SELECT count(*) as count FROM audit_log WHERE ${where}`.pipe(Effect.map((rows) => rows[0]?.count ?? 0))
88
+ ]).pipe(Effect.map(([items, total]) => ({
89
+ items,
90
+ total,
91
+ ...(items.length === limit ? { nextCursor: offset + limit } : {})
92
+ })), cacheError("findAll"));
93
+ }
94
+ return Effect.all([
95
+ findAll_({ limit, offset }),
96
+ countAll(undefined)
97
+ ]).pipe(Effect.map(([items, { count }]) => ({
98
+ items,
99
+ total: count,
100
+ ...(items.length === limit ? { nextCursor: offset + limit } : {})
101
+ })), cacheError("findAll"));
102
+ },
103
+ prune: (retentionDays) => {
104
+ const days = Math.max(1, Math.floor(retentionDays));
105
+ const modifier = `-${days} days`;
106
+ return sql `DELETE FROM audit_log WHERE timestamp < datetime('now', ${modifier})`.pipe(
107
+ // DELETE returns no rows — use changes() to get actual deleted count
108
+ Effect.flatMap(() => sql `SELECT changes() as n`), Effect.map((rows) => rows[0]?.n ?? 0), cacheError("prune"));
109
+ },
110
+ clearAll: () => sql `DELETE FROM audit_log`.pipe(Effect.flatMap(() => sql `SELECT changes() as n`), Effect.map((rows) => rows[0]?.n ?? 0), cacheError("clearAll")),
111
+ exportAll: (opts) => {
112
+ if (opts?.from && opts?.to) {
113
+ const exportFiltered = SqlSchema.findAll({
114
+ Result: AuditLogEntry,
115
+ Request: Schema.Void,
116
+ execute: () => sql `SELECT * FROM audit_log WHERE timestamp >= ${opts.from} AND timestamp <= ${opts
117
+ .to} ORDER BY id DESC`
118
+ });
119
+ return exportFiltered(undefined).pipe(cacheError("exportAll"));
120
+ }
121
+ return exportAllQuery(undefined).pipe(cacheError("exportAll"));
122
+ }
123
+ };
124
+ })
125
+ }) {
126
+ }
127
+ //# sourceMappingURL=AuditLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuditLog.js","sourceRoot":"","sources":["../../src/PermissionService/AuditLog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @title PermissionGate — abstract "ask the user" interface
3
+ *
4
+ * Context.Tag (not Effect.Service) so different environments can
5
+ * provide different implementations:
6
+ * - Web: Deferred + SSE push (PermissionGateLive.ts)
7
+ * - TUI: stdin prompt (future)
8
+ * - Test: auto-allow Layer
9
+ *
10
+ * Only exposes `request` — the caller's view. The concrete implementation
11
+ * (PermissionGateLive) adds `resolve` and `getFirstPending` for the
12
+ * HTTP handler and SSE builder.
13
+ *
14
+ * @module
15
+ */
16
+ import type { Effect } from "effect";
17
+ import { Context, Schema } from "effect";
18
+ import type { PermissionDeniedError } from "../Errors.js";
19
+ declare const PermissionPrompt_base: Schema.Class<PermissionPrompt, {
20
+ id: typeof Schema.String;
21
+ operation: typeof Schema.String;
22
+ category: Schema.Literal<["read", "write"]>;
23
+ context: typeof Schema.String;
24
+ }, Schema.Struct.Encoded<{
25
+ id: typeof Schema.String;
26
+ operation: typeof Schema.String;
27
+ category: Schema.Literal<["read", "write"]>;
28
+ context: typeof Schema.String;
29
+ }>, never, {
30
+ readonly id: string;
31
+ } & {
32
+ readonly operation: string;
33
+ } & {
34
+ readonly context: string;
35
+ } & {
36
+ readonly category: "read" | "write";
37
+ }, {}, {}>;
38
+ export declare class PermissionPrompt extends PermissionPrompt_base {
39
+ }
40
+ export type PermissionResponse = "allow_once" | "always_allow" | "deny";
41
+ declare const PermissionGate_base: Context.TagClass<PermissionGate, "@knpkv/codecommit-core/PermissionGate", {
42
+ readonly request: (prompt: PermissionPrompt) => Effect.Effect<PermissionResponse, PermissionDeniedError>;
43
+ }>;
44
+ export declare class PermissionGate extends PermissionGate_base {
45
+ }
46
+ export {};
47
+ //# sourceMappingURL=PermissionGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionGate.d.ts","sourceRoot":"","sources":["../../src/PermissionService/PermissionGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;;;;;;;;;;;;;;;;;;;;AAGzD,qBAAa,gBAAiB,SAAQ,qBAKpC;CAAG;AAEL,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,cAAc,GAAG,MAAM,CAAA;;sBAOjD,CAAC,MAAM,EAAE,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC;;AAH5G,qBAAa,cAAe,SAAQ,mBAKjC;CAAG"}
@@ -0,0 +1,14 @@
1
+ import { Context, Schema } from "effect";
2
+ // UUID correlates the SSE prompt → client modal → POST response
3
+ export class PermissionPrompt extends Schema.Class("PermissionPrompt")({
4
+ id: Schema.String,
5
+ operation: Schema.String,
6
+ category: Schema.Literal("read", "write"),
7
+ context: Schema.String
8
+ }) {
9
+ }
10
+ // Blocks the calling fiber until user responds or 30s timeout.
11
+ // Returns the response, or fails with PermissionDeniedError.
12
+ export class PermissionGate extends Context.Tag("@knpkv/codecommit-core/PermissionGate")() {
13
+ }
14
+ //# sourceMappingURL=PermissionGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionGate.js","sourceRoot":"","sources":["../../src/PermissionService/PermissionGate.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGxC,gEAAgE;AAChE,MAAM,OAAO,gBAAiB,SAAQ,MAAM,CAAC,KAAK,CAAmB,kBAAkB,CAAC,CAAC;IACvF,EAAE,EAAE,MAAM,CAAC,MAAM;IACjB,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CAAC;CAAG;AAIL,+DAA+D;AAC/D,6DAA6D;AAC7D,MAAM,OAAO,cAAe,SAAQ,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,EAKrF;CAAG"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @title PermissionGateLive — Deferred-based prompt flow
3
+ *
4
+ * One `Deferred<PermissionResponse>` per prompt.
5
+ *
6
+ * Flow:
7
+ * 1. API call fiber creates Deferred, stores in pending Map
8
+ * 2. Publishes PermissionRequired → SSE rebuilds payload with prompt
9
+ * 3. Fiber blocks on Deferred.await (up to 30s)
10
+ * 4. User clicks modal → POST /api/permissions/respond
11
+ * 5. HTTP handler calls resolve() → Deferred.succeed → fiber unblocks
12
+ * 6. Publishes PermissionResolved → SSE removes prompt from payload
13
+ *
14
+ * Multi-tab: Deferred.succeed is idempotent — first responder wins,
15
+ * second tab's POST is a no-op. Both see prompt disappear via SSE.
16
+ *
17
+ * Separate Effect.Service tag (not just PermissionGate) because the
18
+ * HTTP handler and SSE builder need `resolve` and `getFirstPending`
19
+ * which the abstract interface doesn't expose.
20
+ *
21
+ * @module
22
+ */
23
+ import { Effect, Layer } from "effect";
24
+ import { EventsHub } from "../CacheService/EventsHub.js";
25
+ import { PermissionDeniedError } from "../Errors.js";
26
+ import { PermissionGate, type PermissionPrompt, type PermissionResponse } from "./PermissionGate.js";
27
+ export interface PermissionGateLive {
28
+ readonly request: (prompt: PermissionPrompt) => Effect.Effect<PermissionResponse, PermissionDeniedError>;
29
+ readonly resolve: (promptId: string, response: PermissionResponse) => Effect.Effect<void>;
30
+ readonly getFirstPending: () => Effect.Effect<PermissionPrompt | undefined>;
31
+ }
32
+ export declare const PermissionGateLiveTag: Effect.Service.Class<PermissionGateLive, "PermissionGateLive", {
33
+ readonly dependencies: readonly [Layer.Layer<EventsHub, never, never>];
34
+ readonly effect: Effect.Effect<{
35
+ request: (prompt: PermissionPrompt) => Effect.Effect<PermissionResponse, PermissionDeniedError>;
36
+ resolve: (promptId: string, response: PermissionResponse) => Effect.Effect<void>;
37
+ getFirstPending: () => Effect.Effect<PermissionPrompt | undefined>;
38
+ }, never, EventsHub>;
39
+ }>;
40
+ export declare const PermissionGateLiveLayer: Layer.Layer<PermissionGate, never, PermissionGateLive>;
41
+ //# sourceMappingURL=PermissionGateLive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionGateLive.d.ts","sourceRoot":"","sources":["../../src/PermissionService/PermissionGateLive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAY,MAAM,EAAE,KAAK,EAAO,MAAM,QAAQ,CAAA;AACrD,OAAO,EAAE,SAAS,EAAc,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAOpG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAA;IACxG,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACzF,QAAQ,CAAC,eAAe,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAA;CAC5E;AAED,eAAO,MAAM,qBAAqB;;;0BAWL,gBAAgB,KAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC;4BAqCzE,MAAM,YAAY,kBAAkB,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;+BAUzD,MAAM,CAAC,MAAM,CAAC,gBAAgB,GAAG,SAAS,CAAC;;EAUzE,CAAA;AAKF,eAAO,MAAM,uBAAuB,wDAGnC,CAAA"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @title PermissionGateLive — Deferred-based prompt flow
3
+ *
4
+ * One `Deferred<PermissionResponse>` per prompt.
5
+ *
6
+ * Flow:
7
+ * 1. API call fiber creates Deferred, stores in pending Map
8
+ * 2. Publishes PermissionRequired → SSE rebuilds payload with prompt
9
+ * 3. Fiber blocks on Deferred.await (up to 30s)
10
+ * 4. User clicks modal → POST /api/permissions/respond
11
+ * 5. HTTP handler calls resolve() → Deferred.succeed → fiber unblocks
12
+ * 6. Publishes PermissionResolved → SSE removes prompt from payload
13
+ *
14
+ * Multi-tab: Deferred.succeed is idempotent — first responder wins,
15
+ * second tab's POST is a no-op. Both see prompt disappear via SSE.
16
+ *
17
+ * Separate Effect.Service tag (not just PermissionGate) because the
18
+ * HTTP handler and SSE builder need `resolve` and `getFirstPending`
19
+ * which the abstract interface doesn't expose.
20
+ *
21
+ * @module
22
+ */
23
+ import { Deferred, Effect, Layer, Ref } from "effect";
24
+ import { EventsHub, RepoChange } from "../CacheService/EventsHub.js";
25
+ import { PermissionDeniedError } from "../Errors.js";
26
+ import { PermissionGate } from "./PermissionGate.js";
27
+ export const PermissionGateLiveTag = Effect.Service()("PermissionGateLive", {
28
+ // EventsHub needed to publish PermissionRequired/Resolved events
29
+ // that trigger SSE payload rebuilds
30
+ dependencies: [EventsHub.Default],
31
+ effect: Effect.gen(function* () {
32
+ const hub = yield* EventsHub;
33
+ // Map<promptId, { deferred, prompt }>. Concurrent-safe via Ref.
34
+ // Multiple prompts can be pending simultaneously (e.g. initial
35
+ // refresh triggers getCallerIdentity + listRepositories at once).
36
+ const pending = yield* Ref.make(new Map());
37
+ const request = (prompt) => Effect.gen(function* () {
38
+ const deferred = yield* Deferred.make();
39
+ yield* Ref.update(pending, (m) => new Map(m).set(prompt.id, { deferred, prompt }));
40
+ yield* hub.publish(RepoChange.PermissionRequired());
41
+ const response = yield* Deferred.await(deferred).pipe(Effect.timeout("30 seconds"), Effect.catchTag("TimeoutException", () => {
42
+ return Effect.gen(function* () {
43
+ yield* Ref.update(pending, (m) => {
44
+ const n = new Map(m);
45
+ n.delete(prompt.id);
46
+ return n;
47
+ });
48
+ yield* hub.publish(RepoChange.PermissionResolved());
49
+ return yield* new PermissionDeniedError({ operation: prompt.operation, reason: "timeout" });
50
+ });
51
+ }));
52
+ yield* Ref.update(pending, (m) => {
53
+ const n = new Map(m);
54
+ n.delete(prompt.id);
55
+ return n;
56
+ });
57
+ yield* hub.publish(RepoChange.PermissionResolved());
58
+ if (response === "deny") {
59
+ return yield* new PermissionDeniedError({ operation: prompt.operation, reason: "denied" });
60
+ }
61
+ return response;
62
+ });
63
+ // Called by POST /api/permissions/respond handler.
64
+ // Deferred.succeed is idempotent — second call is a no-op.
65
+ // This is how multi-tab "first responder wins" works.
66
+ const resolve = (promptId, response) => Ref.get(pending).pipe(Effect.flatMap((m) => {
67
+ const entry = m.get(promptId);
68
+ return entry ? Deferred.succeed(entry.deferred, response) : Effect.void;
69
+ }));
70
+ // For SSE payload builder — shows one prompt at a time (FIFO).
71
+ // Remaining prompts queue behind; they'll surface as each resolves.
72
+ const getFirstPending = () => Ref.get(pending).pipe(Effect.map((m) => {
73
+ const first = m.values().next();
74
+ return first.done ? undefined : first.value.prompt;
75
+ }));
76
+ return { request, resolve, getFirstPending };
77
+ })
78
+ });
79
+ // Bridge: concrete service → abstract Context.Tag.
80
+ // Handlers use PermissionGateLiveTag (for resolve/getFirstPending),
81
+ // AwsClientGated uses PermissionGate (for request only).
82
+ export const PermissionGateLiveLayer = Layer.effect(PermissionGate, Effect.map(PermissionGateLiveTag, (live) => ({ request: live.request })));
83
+ //# sourceMappingURL=PermissionGateLive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionGateLive.js","sourceRoot":"","sources":["../../src/PermissionService/PermissionGateLive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @title PermissionService — permission state management
3
+ *
4
+ * Ref<Config> backed by `~/.codecommit/permissions.json`.
5
+ *
6
+ * On construction (Layer build time), reads the file
7
+ * into a Ref. All subsequent `check()` calls are O(1) Ref lookups — no disk
8
+ * I/O. Only `set()` mutates the Ref AND writes to disk (atomic: tmp → rename).
9
+ *
10
+ * Key invariant: an operation missing from the file defaults to `"allow"`,
11
+ * which means "prompt the user". A fresh install with empty permissions.json
12
+ * prompts for every API call — zero-trust by default.
13
+ *
14
+ * @module
15
+ */
16
+ import { FileSystem } from "@effect/platform";
17
+ import { Effect, Schema } from "effect";
18
+ import { allOperations, getOperationMeta, type OperationName, registerOperation } from "./operations.js";
19
+ export type { BuiltinOperation, OperationMeta, OperationName } from "./operations.js";
20
+ export { allOperations, getOperationMeta, registerOperation };
21
+ export declare const PermissionState: Schema.Literal<["always_allow", "allow", "deny"]>;
22
+ export type PermissionState = typeof PermissionState.Type;
23
+ declare const PermissionService_base: Effect.Service.Class<PermissionService, "PermissionService", {
24
+ readonly effect: Effect.Effect<{
25
+ check: (operation: OperationName) => Effect.Effect<PermissionState>;
26
+ set: (operation: OperationName, state: PermissionState) => Effect.Effect<void>;
27
+ getAll: () => Effect.Effect<Record<string, PermissionState>>;
28
+ resetAll: () => Effect.Effect<void>;
29
+ isAuditEnabled: () => Effect.Effect<boolean>;
30
+ getAuditRetention: () => Effect.Effect<number>;
31
+ setAudit: (opts: {
32
+ enabled?: boolean | undefined;
33
+ retentionDays?: number | undefined;
34
+ }) => Effect.Effect<void>;
35
+ }, never, FileSystem.FileSystem>;
36
+ }>;
37
+ export declare class PermissionService extends PermissionService_base {
38
+ }
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/PermissionService/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAU,MAAM,EAAO,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExG,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACrF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,CAAA;AAK7D,eAAO,MAAM,eAAe,mDAAkD,CAAA;AAC9E,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;;;2BA6D3B,aAAa,KAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;yBAGhD,aAAa,SAAS,eAAe,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;sBAShE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;wBAG5C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;8BAMb,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;iCAEnB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;yBAI3C;YAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,KAC1E,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;;;AAzC1B,qBAAa,iBAAkB,SAAQ,sBAuDrC;CAAG"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @title PermissionService — permission state management
3
+ *
4
+ * Ref<Config> backed by `~/.codecommit/permissions.json`.
5
+ *
6
+ * On construction (Layer build time), reads the file
7
+ * into a Ref. All subsequent `check()` calls are O(1) Ref lookups — no disk
8
+ * I/O. Only `set()` mutates the Ref AND writes to disk (atomic: tmp → rename).
9
+ *
10
+ * Key invariant: an operation missing from the file defaults to `"allow"`,
11
+ * which means "prompt the user". A fresh install with empty permissions.json
12
+ * prompts for every API call — zero-trust by default.
13
+ *
14
+ * @module
15
+ */
16
+ import { FileSystem } from "@effect/platform";
17
+ import { Config, Effect, Ref, Schema } from "effect";
18
+ import { allOperations, getOperationMeta, registerOperation } from "./operations.js";
19
+ export { allOperations, getOperationMeta, registerOperation };
20
+ // On-disk format. Schema.decodeUnknownSync with defaults means
21
+ // corrupt or missing files gracefully degrade to empty state (everything prompts).
22
+ export const PermissionState = Schema.Literal("always_allow", "allow", "deny");
23
+ const AuditConfig = Schema.Struct({
24
+ enabled: Schema.Boolean.pipe(Schema.optionalWith({ default: () => false })),
25
+ retentionDays: Schema.Number.pipe(Schema.optionalWith({ default: () => 30 }))
26
+ });
27
+ const PermissionsConfig = Schema.Struct({
28
+ permissions: Schema.Record({ key: Schema.String, value: PermissionState }).pipe(Schema.optionalWith({ default: () => ({}) })),
29
+ audit: AuditConfig.pipe(Schema.optionalWith({ default: () => Schema.decodeSync(AuditConfig)({}) }))
30
+ });
31
+ const decodeConfig = Schema.decodeUnknownSync(PermissionsConfig);
32
+ // Uses @effect/platform FileSystem — works in Bun, Node, tests.
33
+ // Atomic write: write to .tmp, then rename. Prevents corruption on crash.
34
+ const resolvePermissionsPath = Config.string("HOME").pipe(Config.orElse(() => Config.string("USERPROFILE")), Config.map((h) => `${h}/.codecommit/permissions.json`));
35
+ const loadFromDisk = (fs, path) => fs.readFileString(path).pipe(Effect.map((content) => decodeConfig(JSON.parse(content))),
36
+ // Any failure → empty config → everything prompts
37
+ Effect.catchAll(() => Effect.succeed(decodeConfig({}))));
38
+ const saveToDisk = (fs, path, config) => Effect.gen(function* () {
39
+ const dir = path.replace(/\/[^/]+$/, "");
40
+ yield* fs.makeDirectory(dir, { recursive: true }).pipe(Effect.catchAll(() => Effect.void));
41
+ const tmpPath = `${path}.tmp`;
42
+ yield* fs.writeFileString(tmpPath, JSON.stringify(config, null, 2));
43
+ yield* fs.rename(tmpPath, path);
44
+ }).pipe(Effect.catchAll(() => Effect.void));
45
+ // Effect.Service (not Context.Tag) — auto-generates `.Default` layer.
46
+ // The effect block runs once at Layer construction: reads file, creates Ref.
47
+ // FileSystem comes from the providing layer (PlatformLive in Server.ts).
48
+ export class PermissionService extends Effect.Service()("PermissionService", {
49
+ effect: Effect.gen(function* () {
50
+ const fs = yield* FileSystem.FileSystem;
51
+ const permPath = yield* Effect.configProviderWith((p) => p.load(resolvePermissionsPath)).pipe(Effect.catchAll(() => Effect.succeed("/tmp/.codecommit/permissions.json")));
52
+ // In-memory state. All check() calls read from here.
53
+ // Only set() mutates it AND writes to disk.
54
+ const initial = yield* loadFromDisk(fs, permPath);
55
+ const configRef = yield* Ref.make(initial);
56
+ // O(1) — Ref.get + property lookup. The "allow" default is the key invariant:
57
+ // missing operation → prompt the user.
58
+ const check = (operation) => Ref.get(configRef).pipe(Effect.map((c) => c.permissions[operation] ?? "allow"));
59
+ const set = (operation, state) => Effect.gen(function* () {
60
+ yield* Ref.update(configRef, (c) => ({
61
+ ...c,
62
+ permissions: { ...c.permissions, [operation]: state }
63
+ }));
64
+ yield* saveToDisk(fs, permPath, yield* Ref.get(configRef));
65
+ });
66
+ const getAll = () => Ref.get(configRef).pipe(Effect.map((c) => c.permissions));
67
+ const resetAll = () => Effect.gen(function* () {
68
+ yield* Ref.update(configRef, (c) => ({ ...c, permissions: {} }));
69
+ yield* saveToDisk(fs, permPath, yield* Ref.get(configRef));
70
+ });
71
+ const isAuditEnabled = () => Ref.get(configRef).pipe(Effect.map((c) => c.audit.enabled));
72
+ const getAuditRetention = () => Ref.get(configRef).pipe(Effect.map((c) => c.audit.retentionDays));
73
+ const setAudit = (opts) => Effect.gen(function* () {
74
+ yield* Ref.update(configRef, (c) => ({
75
+ ...c,
76
+ audit: {
77
+ enabled: opts.enabled ?? c.audit.enabled,
78
+ retentionDays: opts.retentionDays ?? c.audit.retentionDays
79
+ }
80
+ }));
81
+ yield* saveToDisk(fs, permPath, yield* Ref.get(configRef));
82
+ });
83
+ return { check, set, getAll, resetAll, isAuditEnabled, getAuditRetention, setAudit };
84
+ })
85
+ }) {
86
+ }
87
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/PermissionService/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @title Operation registry — maps operation names to metadata
3
+ *
4
+ * Every AWS API call has a named operation with a category (read/write)
5
+ * and human-readable description. The gate uses the category for UI
6
+ * badge color; the description appears in the permission prompt modal.
7
+ *
8
+ * `OperationName` is a union of known builtin operations + `(string & {})`
9
+ * for runtime extensions. This gives autocomplete for known ops while
10
+ * allowing {@link registerOperation} to extend at runtime.
11
+ *
12
+ * Builtin operations cover reads (getPullRequests, listBranches, etc.)
13
+ * and writes (createPullRequest, updatePullRequestTitle, and approval
14
+ * rule CRUD: createApprovalRule, updateApprovalRule, deleteApprovalRule).
15
+ *
16
+ * **Common tasks**
17
+ *
18
+ * - Get operation metadata: {@link getOperationMeta}
19
+ * - List all operations: {@link allOperations}
20
+ * - Register new operation: {@link registerOperation}
21
+ *
22
+ * @internal
23
+ */
24
+ export interface OperationMeta {
25
+ readonly category: "read" | "write";
26
+ readonly description: string;
27
+ }
28
+ declare const BuiltinOperations: {
29
+ readonly getCallerIdentity: OperationMeta;
30
+ readonly listRepositories: OperationMeta;
31
+ readonly listPullRequests: OperationMeta;
32
+ readonly getPullRequests: OperationMeta;
33
+ readonly getPullRequest: OperationMeta;
34
+ readonly evaluatePullRequestApprovalRules: OperationMeta;
35
+ readonly getPullRequestApprovalStates: OperationMeta;
36
+ readonly getMergeConflicts: OperationMeta;
37
+ readonly getCommentsForPullRequest: OperationMeta;
38
+ readonly listBranches: OperationMeta;
39
+ readonly getDifferences: OperationMeta;
40
+ readonly createPullRequest: OperationMeta;
41
+ readonly updatePullRequestTitle: OperationMeta;
42
+ readonly updatePullRequestDescription: OperationMeta;
43
+ readonly createApprovalRule: OperationMeta;
44
+ readonly updateApprovalRule: OperationMeta;
45
+ readonly deleteApprovalRule: OperationMeta;
46
+ };
47
+ export type BuiltinOperation = keyof typeof BuiltinOperations;
48
+ export type OperationName = BuiltinOperation | (string & {});
49
+ export declare const getOperationMeta: (name: OperationName) => OperationMeta;
50
+ export declare const allOperations: () => ReadonlyArray<readonly [string, OperationMeta]>;
51
+ export declare const registerOperation: (name: string, meta: OperationMeta) => void;
52
+ export {};
53
+ //# sourceMappingURL=operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/PermissionService/operations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAID,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;CAkB2B,CAAA;AAElD,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,iBAAiB,CAAA;AAG7D,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAM5D,eAAO,MAAM,gBAAgB,GAAI,MAAM,aAAa,KAAG,aAAuD,CAAA;AAE9G,eAAO,MAAM,aAAa,QAAO,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC,CAA8B,CAAA;AAE7G,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,EAAE,MAAM,aAAa,KAAG,IAErE,CAAA"}