declastruct-github 1.0.7 → 1.1.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 (70) hide show
  1. package/dist/access/daos/DeclaredGithubAppDao.d.ts +8 -0
  2. package/dist/access/daos/DeclaredGithubAppDao.js +32 -0
  3. package/dist/access/daos/DeclaredGithubAppDao.js.map +1 -0
  4. package/dist/access/daos/DeclaredGithubAppInstallationDao.d.ts +9 -0
  5. package/dist/access/daos/DeclaredGithubAppInstallationDao.js +33 -0
  6. package/dist/access/daos/DeclaredGithubAppInstallationDao.js.map +1 -0
  7. package/dist/access/daos/DeclaredGithubBranchDao.js +4 -4
  8. package/dist/access/daos/DeclaredGithubBranchDao.js.map +1 -1
  9. package/dist/access/daos/DeclaredGithubBranchProtectionDao.js +4 -4
  10. package/dist/access/daos/DeclaredGithubBranchProtectionDao.js.map +1 -1
  11. package/dist/access/daos/DeclaredGithubRepoConfigDao.js +4 -4
  12. package/dist/access/daos/DeclaredGithubRepoConfigDao.js.map +1 -1
  13. package/dist/access/daos/DeclaredGithubRepoDao.js +4 -4
  14. package/dist/access/daos/DeclaredGithubRepoDao.js.map +1 -1
  15. package/dist/contract/sdks/index.d.ts +4 -0
  16. package/dist/contract/sdks/index.js +9 -3
  17. package/dist/contract/sdks/index.js.map +1 -1
  18. package/dist/domain.objects/DeclaredGithubApp.d.ts +75 -0
  19. package/dist/domain.objects/DeclaredGithubApp.js +16 -0
  20. package/dist/domain.objects/DeclaredGithubApp.js.map +1 -0
  21. package/dist/domain.objects/DeclaredGithubAppInstallation.d.ts +61 -0
  22. package/dist/domain.objects/DeclaredGithubAppInstallation.js +16 -0
  23. package/dist/domain.objects/DeclaredGithubAppInstallation.js.map +1 -0
  24. package/dist/domain.objects/DeclaredGithubAppPermissions.d.ts +126 -0
  25. package/dist/domain.objects/DeclaredGithubAppPermissions.js +12 -0
  26. package/dist/domain.objects/DeclaredGithubAppPermissions.js.map +1 -0
  27. package/dist/domain.objects/DeclaredGithubOwner.d.ts +17 -0
  28. package/dist/domain.objects/DeclaredGithubOwner.js +8 -0
  29. package/dist/domain.objects/DeclaredGithubOwner.js.map +1 -0
  30. package/dist/domain.objects/DeclaredGithubRepoConfig.d.ts +0 -4
  31. package/dist/domain.objects/DeclaredGithubRepoConfig.js.map +1 -1
  32. package/dist/domain.objects/DeclastructGithubProvider.d.ts +4 -0
  33. package/dist/domain.operations/app/castToDeclaredGithubApp.d.ts +12 -0
  34. package/dist/domain.operations/app/castToDeclaredGithubApp.js +133 -0
  35. package/dist/domain.operations/app/castToDeclaredGithubApp.js.map +1 -0
  36. package/dist/domain.operations/app/getOneApp.d.ts +15 -0
  37. package/dist/domain.operations/app/getOneApp.js +67 -0
  38. package/dist/domain.operations/app/getOneApp.js.map +1 -0
  39. package/dist/domain.operations/app/setApp.d.ts +13 -0
  40. package/dist/domain.operations/app/setApp.js +77 -0
  41. package/dist/domain.operations/app/setApp.js.map +1 -0
  42. package/dist/domain.operations/appInstallation/castToDeclaredGithubAppInstallation.d.ts +19 -0
  43. package/dist/domain.operations/appInstallation/castToDeclaredGithubAppInstallation.js +61 -0
  44. package/dist/domain.operations/appInstallation/castToDeclaredGithubAppInstallation.js.map +1 -0
  45. package/dist/domain.operations/appInstallation/deleteAppInstallation.d.ts +11 -0
  46. package/dist/domain.operations/appInstallation/deleteAppInstallation.js +30 -0
  47. package/dist/domain.operations/appInstallation/deleteAppInstallation.js.map +1 -0
  48. package/dist/domain.operations/appInstallation/getOneAppInstallation.d.ts +15 -0
  49. package/dist/domain.operations/appInstallation/getOneAppInstallation.js +92 -0
  50. package/dist/domain.operations/appInstallation/getOneAppInstallation.js.map +1 -0
  51. package/dist/domain.operations/appInstallation/setAppInstallation.d.ts +13 -0
  52. package/dist/domain.operations/appInstallation/setAppInstallation.js +131 -0
  53. package/dist/domain.operations/appInstallation/setAppInstallation.js.map +1 -0
  54. package/dist/domain.operations/branch/setBranch.js +19 -10
  55. package/dist/domain.operations/branch/setBranch.js.map +1 -1
  56. package/dist/domain.operations/context/hasContextWithAppToken.d.ts +6 -0
  57. package/dist/domain.operations/context/hasContextWithAppToken.js +15 -0
  58. package/dist/domain.operations/context/hasContextWithAppToken.js.map +1 -0
  59. package/dist/domain.operations/context/hasContextWithPatToken.d.ts +6 -0
  60. package/dist/domain.operations/context/hasContextWithPatToken.js +17 -0
  61. package/dist/domain.operations/context/hasContextWithPatToken.js.map +1 -0
  62. package/dist/domain.operations/provider/getDeclastructGithubProvider.js +4 -0
  63. package/dist/domain.operations/provider/getDeclastructGithubProvider.js.map +1 -1
  64. package/dist/domain.operations/repo/getRepos.js +22 -5
  65. package/dist/domain.operations/repo/getRepos.js.map +1 -1
  66. package/dist/domain.operations/repoConfig/castToDeclaredGithubRepoConfig.js +0 -1
  67. package/dist/domain.operations/repoConfig/castToDeclaredGithubRepoConfig.js.map +1 -1
  68. package/dist/domain.operations/repoConfig/setRepoConfig.js +0 -1
  69. package/dist/domain.operations/repoConfig/setRepoConfig.js.map +1 -1
  70. package/package.json +5 -5
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeclaredGithubOwner = void 0;
4
+ const domain_objects_1 = require("domain-objects");
5
+ class DeclaredGithubOwner extends domain_objects_1.DomainLiteral {
6
+ }
7
+ exports.DeclaredGithubOwner = DeclaredGithubOwner;
8
+ //# sourceMappingURL=DeclaredGithubOwner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeclaredGithubOwner.js","sourceRoot":"","sources":["../../src/domain.objects/DeclaredGithubOwner.ts"],"names":[],"mappings":";;;AAAA,mDAA+C;AAkB/C,MAAa,mBACX,SAAQ,8BAAkC;CACT;AAFnC,kDAEmC"}
@@ -27,10 +27,6 @@ export interface DeclaredGithubRepoConfig {
27
27
  * .what = whether wiki is enabled
28
28
  */
29
29
  hasWiki?: boolean;
30
- /**
31
- * .what = whether downloads are enabled
32
- */
33
- hasDownloads?: boolean;
34
30
  /**
35
31
  * .what = whether this is a template repository
36
32
  */
@@ -1 +1 @@
1
- {"version":3,"file":"DeclaredGithubRepoConfig.js","sourceRoot":"","sources":["../../src/domain.objects/DeclaredGithubRepoConfig.ts"],"names":[],"mappings":";;;AAAA,mDAA2D;AA8G3D,MAAa,wBACX,SAAQ,6BAAsC;;AADhD,4DAQC;AAJe,+BAAM,GAAG,CAAC,MAAM,CAAU,CAAC;AAC3B,+BAAM,GAAG;IACrB,IAAI,EAAE,CAAA,4BAAsC,CAAA;CAC7C,CAAC"}
1
+ {"version":3,"file":"DeclaredGithubRepoConfig.js","sourceRoot":"","sources":["../../src/domain.objects/DeclaredGithubRepoConfig.ts"],"names":[],"mappings":";;;AAAA,mDAA2D;AAyG3D,MAAa,wBACX,SAAQ,6BAAsC;;AADhD,4DAQC;AAJe,+BAAM,GAAG,CAAC,MAAM,CAAU,CAAC;AAC3B,+BAAM,GAAG;IACrB,IAAI,EAAE,CAAA,4BAAsC,CAAA;CAC7C,CAAC"}
@@ -1,6 +1,8 @@
1
1
  import type { DeclastructDao, DeclastructProvider } from 'declastruct';
2
2
  import type { ContextLogTrail } from 'simple-log-methods';
3
3
  import type { ContextGithubApi } from './ContextGithubApi';
4
+ import type { DeclaredGithubApp } from './DeclaredGithubApp';
5
+ import type { DeclaredGithubAppInstallation } from './DeclaredGithubAppInstallation';
4
6
  import type { DeclaredGithubBranch } from './DeclaredGithubBranch';
5
7
  import type { DeclaredGithubBranchProtection } from './DeclaredGithubBranchProtection';
6
8
  import type { DeclaredGithubRepo } from './DeclaredGithubRepo';
@@ -14,4 +16,6 @@ export type DeclastructGithubProvider = DeclastructProvider<{
14
16
  DeclaredGithubBranch: DeclastructDao<typeof DeclaredGithubBranch, ContextGithubApi & ContextLogTrail>;
15
17
  DeclaredGithubRepoConfig: DeclastructDao<typeof DeclaredGithubRepoConfig, ContextGithubApi & ContextLogTrail>;
16
18
  DeclaredGithubBranchProtection: DeclastructDao<typeof DeclaredGithubBranchProtection, ContextGithubApi & ContextLogTrail>;
19
+ DeclaredGithubApp: DeclastructDao<typeof DeclaredGithubApp, ContextGithubApi & ContextLogTrail>;
20
+ DeclaredGithubAppInstallation: DeclastructDao<typeof DeclaredGithubAppInstallation, ContextGithubApi & ContextLogTrail>;
17
21
  }, ContextGithubApi & ContextLogTrail>;
@@ -0,0 +1,12 @@
1
+ import type { Endpoints } from '@octokit/types';
2
+ import type { HasMetadata } from 'type-fns';
3
+ import { DeclaredGithubApp } from '../../domain.objects/DeclaredGithubApp';
4
+ type GithubAppResponse = Endpoints['GET /apps/{app_slug}']['response']['data'];
5
+ /**
6
+ * .what = casts GitHub API app response to DeclaredGithubApp
7
+ * .why = transforms external API shape to our domain model with type safety and validation
8
+ */
9
+ export declare const castToDeclaredGithubApp: (input: GithubAppResponse, options?: {
10
+ inferredPublic?: boolean;
11
+ }) => HasMetadata<DeclaredGithubApp>;
12
+ export {};
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.castToDeclaredGithubApp = void 0;
4
+ const uni_time_1 = require("@ehmpathy/uni-time");
5
+ const helpful_errors_1 = require("helpful-errors");
6
+ const DeclaredGithubApp_1 = require("../../domain.objects/DeclaredGithubApp");
7
+ const DeclaredGithubAppPermissions_1 = require("../../domain.objects/DeclaredGithubAppPermissions");
8
+ const DeclaredGithubOwner_1 = require("../../domain.objects/DeclaredGithubOwner");
9
+ /**
10
+ * .what = casts GitHub API app response to DeclaredGithubApp
11
+ * .why = transforms external API shape to our domain model with type safety and validation
12
+ */
13
+ const castToDeclaredGithubApp = (input, options) => {
14
+ // fail fast if input is null
15
+ if (!input) {
16
+ helpful_errors_1.UnexpectedCodePathError.throw('app response is null', { input });
17
+ }
18
+ // extract owner from owner object
19
+ const ownerData = input.owner;
20
+ if (!ownerData) {
21
+ helpful_errors_1.UnexpectedCodePathError.throw('owner not found on app response', { input });
22
+ }
23
+ const ownerLogin = 'login' in ownerData ? ownerData.login : null;
24
+ const ownerType = 'type' in ownerData ? ownerData.type : null;
25
+ if (!ownerLogin || !ownerType) {
26
+ helpful_errors_1.UnexpectedCodePathError.throw('owner login/type not found on app response', {
27
+ input,
28
+ ownerData,
29
+ });
30
+ }
31
+ const owner = new DeclaredGithubOwner_1.DeclaredGithubOwner({
32
+ type: ownerType.toLowerCase(),
33
+ slug: ownerLogin,
34
+ });
35
+ // extract required fields
36
+ const id = input.id;
37
+ const slug = input.slug;
38
+ if (!slug) {
39
+ helpful_errors_1.UnexpectedCodePathError.throw('slug not found on app response', { input });
40
+ }
41
+ // cast permissions from snake_case to camelCase with nested structure
42
+ const permissions = castPermissions(input.permissions ?? {});
43
+ return DeclaredGithubApp_1.DeclaredGithubApp.as({
44
+ id,
45
+ slug,
46
+ owner,
47
+ name: input.name ?? null,
48
+ description: input.description
49
+ ? input.description
50
+ .split('\n')
51
+ .map((line) => line.trimEnd()) // normalize trailing whitespace per line
52
+ .join('\n')
53
+ .trim() // normalize leading/trailing whitespace
54
+ : null,
55
+ public: (() => {
56
+ // use API response if available
57
+ if ('public' in input)
58
+ return Boolean(input.public);
59
+ // use inferred value if provided
60
+ if (options?.inferredPublic !== undefined)
61
+ return options.inferredPublic;
62
+ // fail fast - never default
63
+ throw new helpful_errors_1.UnexpectedCodePathError('public field not in API response and no inference provided', { input });
64
+ })(),
65
+ permissions,
66
+ events: input.events ?? [],
67
+ homepageUrl: input.external_url ?? null,
68
+ webhookUrl: null, // not exposed in public API response
69
+ createdAt: input.created_at ? (0, uni_time_1.asUniDateTime)(input.created_at) : undefined,
70
+ updatedAt: input.updated_at ? (0, uni_time_1.asUniDateTime)(input.updated_at) : undefined,
71
+ });
72
+ };
73
+ exports.castToDeclaredGithubApp = castToDeclaredGithubApp;
74
+ /**
75
+ * .what = casts GitHub API permissions object to DeclaredGithubAppPermissions
76
+ * .why = transforms snake_case API keys to camelCase domain model with nested repository/organization structure
77
+ */
78
+ const castPermissions = (input) => {
79
+ // map snake_case keys to camelCase for repository permissions
80
+ const repositoryKeyMap = {
81
+ contents: 'contents',
82
+ pull_requests: 'pullRequests',
83
+ issues: 'issues',
84
+ actions: 'actions',
85
+ administration: 'administration',
86
+ metadata: 'metadata',
87
+ deployments: 'deployments',
88
+ checks: 'checks',
89
+ code_scanning: 'codeScanning',
90
+ secrets: 'secrets',
91
+ workflows: 'workflows',
92
+ environments: 'environments',
93
+ pages: 'pages',
94
+ packages: 'packages',
95
+ repository_hooks: 'hooks',
96
+ };
97
+ // map snake_case keys to camelCase for organization permissions
98
+ const organizationKeyMap = {
99
+ organization_administration: 'administration',
100
+ members: 'members',
101
+ organization_custom_properties: 'customProperties',
102
+ organization_user_blocking: 'userBlocking',
103
+ organization_hooks: 'hooks',
104
+ organization_secrets: 'secrets',
105
+ organization_projects: 'projects',
106
+ organization_self_hosted_runners: 'selfHostedRunners',
107
+ };
108
+ // build the repository permissions object
109
+ const repository = {};
110
+ for (const [snakeKey, value] of Object.entries(input)) {
111
+ const camelKey = repositoryKeyMap[snakeKey];
112
+ if (camelKey && value) {
113
+ repository[camelKey] = value;
114
+ }
115
+ }
116
+ // build the organization permissions object
117
+ const organization = {};
118
+ for (const [snakeKey, value] of Object.entries(input)) {
119
+ const camelKey = organizationKeyMap[snakeKey];
120
+ if (camelKey && value) {
121
+ organization[camelKey] = value;
122
+ }
123
+ }
124
+ return new DeclaredGithubAppPermissions_1.DeclaredGithubAppPermissions({
125
+ repository: Object.keys(repository).length > 0
126
+ ? repository
127
+ : null,
128
+ organization: Object.keys(organization).length > 0
129
+ ? organization
130
+ : null,
131
+ });
132
+ };
133
+ //# sourceMappingURL=castToDeclaredGithubApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"castToDeclaredGithubApp.js","sourceRoot":"","sources":["../../../src/domain.operations/app/castToDeclaredGithubApp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { RefByUnique } from 'domain-objects';
2
+ import type { HasMetadata, PickOne } from 'type-fns';
3
+ import type { VisualogicContext } from 'visualogic';
4
+ import type { ContextGithubApi } from '../../domain.objects/ContextGithubApi';
5
+ import type { DeclaredGithubApp } from '../../domain.objects/DeclaredGithubApp';
6
+ /**
7
+ * .what = gets a GitHub App by unique key
8
+ * .why = retrieves current state of an app from GitHub API for declarative management
9
+ * .note = by.primary not supported - GitHub API requires app slug or JWT auth to lookup apps
10
+ */
11
+ export declare const getOneApp: (input: {
12
+ by: PickOne<{
13
+ unique: RefByUnique<typeof DeclaredGithubApp>;
14
+ }>;
15
+ }, context: ContextGithubApi & VisualogicContext) => Promise<HasMetadata<DeclaredGithubApp> | null>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOneApp = void 0;
4
+ const rest_1 = require("@octokit/rest");
5
+ const as_procedure_1 = require("as-procedure");
6
+ const helpful_errors_1 = require("helpful-errors");
7
+ const getGithubClient_1 = require("../../access/sdks/getGithubClient");
8
+ const hasContextWithAppToken_1 = require("../context/hasContextWithAppToken");
9
+ const hasContextWithPatToken_1 = require("../context/hasContextWithPatToken");
10
+ const castToDeclaredGithubApp_1 = require("./castToDeclaredGithubApp");
11
+ /**
12
+ * .what = checks if a GitHub App is publicly accessible via unauthenticated request
13
+ * .why = determines public status when API response doesn't include it
14
+ */
15
+ const checkIfAppIsPublic = async (slug) => {
16
+ const unauthenticatedClient = new rest_1.Octokit();
17
+ try {
18
+ await unauthenticatedClient.apps.getBySlug({ app_slug: slug });
19
+ return true; // accessible without auth = public
20
+ }
21
+ catch {
22
+ return false; // not accessible without auth = private
23
+ }
24
+ };
25
+ /**
26
+ * .what = gets a GitHub App by unique key
27
+ * .why = retrieves current state of an app from GitHub API for declarative management
28
+ * .note = by.primary not supported - GitHub API requires app slug or JWT auth to lookup apps
29
+ */
30
+ exports.getOneApp = (0, as_procedure_1.asProcedure)(async (input, context) => {
31
+ // get cached GitHub client
32
+ const github = (0, getGithubClient_1.getGithubClient)({}, context);
33
+ // determine app slug from input
34
+ if (!input.by.unique)
35
+ helpful_errors_1.UnexpectedCodePathError.throw('not referenced by unique. how not?', {
36
+ input,
37
+ });
38
+ const { slug } = input.by.unique;
39
+ // detect token type for inferring public field
40
+ const isAppToken = (0, hasContextWithAppToken_1.hasContextWithAppToken)(null, context);
41
+ const isPat = (0, hasContextWithPatToken_1.hasContextWithPatToken)(null, context);
42
+ // execute the GitHub API call
43
+ try {
44
+ const response = await github.apps.getBySlug({ app_slug: slug });
45
+ // infer public status based on token type
46
+ // - app token: if we got a response, app must be public (private apps 404 for other apps' tokens)
47
+ // - PAT: check via unauthenticated request (PAT can see private apps the user owns)
48
+ const inferredPublic = await (async () => {
49
+ if (isAppToken)
50
+ return true;
51
+ if (isPat)
52
+ return checkIfAppIsPublic(slug);
53
+ throw new helpful_errors_1.UnexpectedCodePathError('unsupported token type for inferring public status', { tokenPrefix: context.github.token.slice(0, 10) + '...' });
54
+ })();
55
+ return (0, castToDeclaredGithubApp_1.castToDeclaredGithubApp)(response.data, { inferredPublic });
56
+ }
57
+ catch (error) {
58
+ if (!(error instanceof Error))
59
+ throw error;
60
+ // return null for 404/not found
61
+ if (error.message.includes('Not Found'))
62
+ return null;
63
+ // throw helpful error for all other failures
64
+ throw new helpful_errors_1.HelpfulError('github.getOneApp error', { cause: error });
65
+ }
66
+ });
67
+ //# sourceMappingURL=getOneApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getOneApp.js","sourceRoot":"","sources":["../../../src/domain.operations/app/getOneApp.ts"],"names":[],"mappings":";;;AAAA,wCAAwC;AACxC,+CAA2C;AAE3C,mDAAuE;AAIvE,uEAAoE;AAGpE,8EAA2E;AAC3E,8EAA2E;AAC3E,uEAAoE;AAEpE;;;GAGG;AACH,MAAM,kBAAkB,GAAG,KAAK,EAAE,IAAY,EAAoB,EAAE;IAClE,MAAM,qBAAqB,GAAG,IAAI,cAAO,EAAE,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,CAAC,mCAAmC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,CAAC,wCAAwC;IACxD,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACU,QAAA,SAAS,GAAG,IAAA,0BAAW,EAClC,KAAK,EACH,KAIC,EACD,OAA6C,EACG,EAAE;IAClD,2BAA2B;IAC3B,MAAM,MAAM,GAAG,IAAA,iCAAe,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAE5C,gCAAgC;IAChC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM;QAClB,wCAAuB,CAAC,KAAK,CAAC,oCAAoC,EAAE;YAClE,KAAK;SACN,CAAC,CAAC;IACL,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;IAEjC,+CAA+C;IAC/C,MAAM,UAAU,GAAG,IAAA,+CAAsB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,IAAA,+CAAsB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEpD,8BAA8B;IAC9B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjE,0CAA0C;QAC1C,kGAAkG;QAClG,oFAAoF;QACpF,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE;YACvC,IAAI,UAAU;gBAAE,OAAO,IAAI,CAAC;YAC5B,IAAI,KAAK;gBAAE,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,IAAI,wCAAuB,CAC/B,oDAAoD,EACpD,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAC3D,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,IAAA,iDAAuB,EAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;YAAE,MAAM,KAAK,CAAC;QAE3C,gCAAgC;QAChC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC;QAErD,6CAA6C;QAC7C,MAAM,IAAI,6BAAY,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;AACH,CAAC,CACF,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { HasMetadata, PickOne } from 'type-fns';
2
+ import type { VisualogicContext } from 'visualogic';
3
+ import type { ContextGithubApi } from '../../domain.objects/ContextGithubApi';
4
+ import type { DeclaredGithubApp } from '../../domain.objects/DeclaredGithubApp';
5
+ /**
6
+ * .what = sets a GitHub App: finsert or upsert
7
+ * .why = provides declarative interface with helpful errors since apps cannot be created/updated via API
8
+ * .note = GitHub Apps must be created via web UI or manifest flow; this function throws HelpfulError with actionable URLs
9
+ */
10
+ export declare const setApp: (input: PickOne<{
11
+ finsert: DeclaredGithubApp;
12
+ upsert: DeclaredGithubApp;
13
+ }>, context: ContextGithubApi & VisualogicContext) => Promise<HasMetadata<DeclaredGithubApp>>;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setApp = void 0;
4
+ const as_procedure_1 = require("as-procedure");
5
+ const helpful_errors_1 = require("helpful-errors");
6
+ const getOneApp_1 = require("./getOneApp");
7
+ /**
8
+ * .what = sets a GitHub App: finsert or upsert
9
+ * .why = provides declarative interface with helpful errors since apps cannot be created/updated via API
10
+ * .note = GitHub Apps must be created via web UI or manifest flow; this function throws HelpfulError with actionable URLs
11
+ */
12
+ exports.setApp = (0, as_procedure_1.asProcedure)(async (input, context) => {
13
+ const desired = input.finsert ??
14
+ input.upsert ??
15
+ helpful_errors_1.UnexpectedCodePathError.throw('no app provided to setApp', { input });
16
+ // validate that name will cast to expected slug
17
+ // (GitHub auto-generates slug from name during registration)
18
+ const name = desired.name ?? desired.slug;
19
+ const expectedSlug = castNameToSlug(name);
20
+ if (expectedSlug !== desired.slug)
21
+ throw new helpful_errors_1.HelpfulError(`App name "${name}" will generate slug "${expectedSlug}", but expected slug "${desired.slug}".`, {
22
+ suggestion: `Either change the name to "${desired.slug}" or change the slug to "${expectedSlug}"`,
23
+ name,
24
+ expectedSlug,
25
+ desiredSlug: desired.slug,
26
+ });
27
+ // check whether it already exists
28
+ const foundBefore = await (0, getOneApp_1.getOneApp)({
29
+ by: {
30
+ unique: {
31
+ owner: desired.owner,
32
+ slug: desired.slug,
33
+ },
34
+ },
35
+ }, context);
36
+ // if it's a finsert and exists, return the found app
37
+ if (foundBefore && input.finsert)
38
+ return foundBefore;
39
+ // if it's an upsert and exists, throw HelpfulError with settings URL
40
+ if (foundBefore && input.upsert) {
41
+ const settingsUrl = desired.owner.type === 'organization'
42
+ ? `https://github.com/organizations/${desired.owner.slug}/settings/apps/${desired.slug}`
43
+ : `https://github.com/settings/apps/${desired.slug}`;
44
+ throw new helpful_errors_1.HelpfulError('GitHub Apps cannot be updated via API. Please update the app settings manually.', {
45
+ url: settingsUrl,
46
+ instructions: [
47
+ 'Navigate to the settings URL above',
48
+ 'Update the app permissions, events, or other settings (See the plan diff for which changes to make)',
49
+ 'Save your changes',
50
+ ],
51
+ });
52
+ }
53
+ // app doesn't exist - provide manual creation instructions
54
+ const registrationUrl = desired.owner.type === 'organization'
55
+ ? `https://github.com/organizations/${desired.owner.slug}/settings/apps/new`
56
+ : `https://github.com/settings/apps/new`;
57
+ throw new helpful_errors_1.HelpfulError('GitHub Apps cannot be created via API. Please create the app manually.', {
58
+ registrationUrl,
59
+ instructions: [
60
+ `1. Navigate to: ${registrationUrl}`,
61
+ `2. Set the app name to: "${desired.name ?? desired.slug}"`,
62
+ '3. Configure permissions and events as shown in the manifest below',
63
+ '4. Save and generate a private key',
64
+ ],
65
+ desired,
66
+ });
67
+ });
68
+ /**
69
+ * .what = casts an app name to the slug GitHub will generate
70
+ * .why = GitHub auto-generates slugs from names during app registration
71
+ * .how = lowercase, replace non-alphanumeric with hyphens, collapse consecutive hyphens, trim hyphens
72
+ */
73
+ const castNameToSlug = (name) => name
74
+ .toLowerCase()
75
+ .replace(/[^a-z0-9]+/g, '-') // replace non-alphanumeric sequences with single hyphen
76
+ .replace(/^-+|-+$/g, ''); // trim leading/trailing hyphens
77
+ //# sourceMappingURL=setApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setApp.js","sourceRoot":"","sources":["../../../src/domain.operations/app/setApp.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAC3C,mDAAuE;AAMvE,2CAAwC;AAExC;;;;GAIG;AACU,QAAA,MAAM,GAAG,IAAA,0BAAW,EAC/B,KAAK,EACH,KAGE,EACF,OAA6C,EACJ,EAAE;IAC3C,MAAM,OAAO,GACX,KAAK,CAAC,OAAO;QACb,KAAK,CAAC,MAAM;QACZ,wCAAuB,CAAC,KAAK,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAExE,gDAAgD;IAChD,6DAA6D;IAC7D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAC1C,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,YAAY,KAAK,OAAO,CAAC,IAAI;QAC/B,MAAM,IAAI,6BAAY,CACpB,aAAa,IAAI,yBAAyB,YAAY,yBAAyB,OAAO,CAAC,IAAI,IAAI,EAC/F;YACE,UAAU,EAAE,8BAA8B,OAAO,CAAC,IAAI,4BAA4B,YAAY,GAAG;YACjG,IAAI;YACJ,YAAY;YACZ,WAAW,EAAE,OAAO,CAAC,IAAI;SAC1B,CACF,CAAC;IAEJ,kCAAkC;IAClC,MAAM,WAAW,GAAG,MAAM,IAAA,qBAAS,EACjC;QACE,EAAE,EAAE;YACF,MAAM,EAAE;gBACN,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,IAAI,EAAE,OAAO,CAAC,IAAI;aACnB;SACF;KACF,EACD,OAAO,CACR,CAAC;IAEF,qDAAqD;IACrD,IAAI,WAAW,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,WAAW,CAAC;IAErD,qEAAqE;IACrE,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,WAAW,GACf,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc;YACnC,CAAC,CAAC,oCAAoC,OAAO,CAAC,KAAK,CAAC,IAAI,kBAAkB,OAAO,CAAC,IAAI,EAAE;YACxF,CAAC,CAAC,oCAAoC,OAAO,CAAC,IAAI,EAAE,CAAC;QACzD,MAAM,IAAI,6BAAY,CACpB,iFAAiF,EACjF;YACE,GAAG,EAAE,WAAW;YAChB,YAAY,EAAE;gBACZ,oCAAoC;gBACpC,qGAAqG;gBACrG,mBAAmB;aACpB;SACF,CACF,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,MAAM,eAAe,GACnB,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc;QACnC,CAAC,CAAC,oCAAoC,OAAO,CAAC,KAAK,CAAC,IAAI,oBAAoB;QAC5E,CAAC,CAAC,sCAAsC,CAAC;IAE7C,MAAM,IAAI,6BAAY,CACpB,wEAAwE,EACxE;QACE,eAAe;QACf,YAAY,EAAE;YACZ,mBAAmB,eAAe,EAAE;YACpC,4BAA4B,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,GAAG;YAC3D,oEAAoE;YACpE,oCAAoC;SACrC;QACD,OAAO;KACR,CACF,CAAC;AACJ,CAAC,CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,cAAc,GAAG,CAAC,IAAY,EAAU,EAAE,CAC9C,IAAI;KACD,WAAW,EAAE;KACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,wDAAwD;KACpF,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,gCAAgC"}
@@ -0,0 +1,19 @@
1
+ import type { Endpoints } from '@octokit/types';
2
+ import type { HasMetadata } from 'type-fns';
3
+ import { DeclaredGithubAppInstallation } from '../../domain.objects/DeclaredGithubAppInstallation';
4
+ import { DeclaredGithubOwner } from '../../domain.objects/DeclaredGithubOwner';
5
+ type GithubInstallationResponse = Endpoints['GET /orgs/{org}/installation']['response']['data'] | Endpoints['GET /users/{username}/installation']['response']['data'] | Endpoints['GET /repos/{owner}/{repo}/installation']['response']['data'] | Endpoints['GET /app/installations/{installation_id}']['response']['data'];
6
+ /**
7
+ * .what = casts GitHub API installation response to DeclaredGithubAppInstallation
8
+ * .why = transforms external API shape to our domain model with type safety and validation
9
+ * .note = requires app reference to be passed in since installation response doesn't include app owner
10
+ */
11
+ export declare const castToDeclaredGithubAppInstallation: (input: {
12
+ installation: GithubInstallationResponse;
13
+ app: {
14
+ owner: DeclaredGithubOwner;
15
+ slug: string;
16
+ };
17
+ repositories: string[] | null;
18
+ }) => HasMetadata<DeclaredGithubAppInstallation>;
19
+ export {};
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.castToDeclaredGithubAppInstallation = void 0;
4
+ const uni_time_1 = require("@ehmpathy/uni-time");
5
+ const domain_objects_1 = require("domain-objects");
6
+ const helpful_errors_1 = require("helpful-errors");
7
+ const DeclaredGithubApp_1 = require("../../domain.objects/DeclaredGithubApp");
8
+ const DeclaredGithubAppInstallation_1 = require("../../domain.objects/DeclaredGithubAppInstallation");
9
+ const DeclaredGithubOwner_1 = require("../../domain.objects/DeclaredGithubOwner");
10
+ /**
11
+ * .what = casts GitHub API installation response to DeclaredGithubAppInstallation
12
+ * .why = transforms external API shape to our domain model with type safety and validation
13
+ * .note = requires app reference to be passed in since installation response doesn't include app owner
14
+ */
15
+ const castToDeclaredGithubAppInstallation = (input) => {
16
+ const { installation, app } = input;
17
+ // extract account info
18
+ const account = installation.account;
19
+ if (!account)
20
+ helpful_errors_1.UnexpectedCodePathError.throw('installation account not found', {
21
+ installation,
22
+ });
23
+ // extract login from account (type narrowing)
24
+ const targetSlug = 'login' in account ? account.login : undefined;
25
+ if (!targetSlug)
26
+ helpful_errors_1.UnexpectedCodePathError.throw('installation account login not found', {
27
+ installation,
28
+ account,
29
+ });
30
+ // extract target type
31
+ const targetType = installation.target_type;
32
+ if (!targetType)
33
+ helpful_errors_1.UnexpectedCodePathError.throw('installation target_type not found', {
34
+ installation,
35
+ });
36
+ // compose target object
37
+ const target = new DeclaredGithubOwner_1.DeclaredGithubOwner({
38
+ type: targetType.toLowerCase(),
39
+ slug: targetSlug,
40
+ });
41
+ // extract repository selection
42
+ const repositorySelection = (installation.repository_selection ?? 'all');
43
+ return DeclaredGithubAppInstallation_1.DeclaredGithubAppInstallation.as({
44
+ id: installation.id,
45
+ app: app instanceof DeclaredGithubApp_1.DeclaredGithubApp
46
+ ? (0, domain_objects_1.refByUnique)(app)
47
+ : app,
48
+ target,
49
+ repositorySelection,
50
+ repositories: input.repositories,
51
+ suspended: installation.suspended_at !== null,
52
+ createdAt: installation.created_at
53
+ ? (0, uni_time_1.asUniDateTime)(installation.created_at)
54
+ : undefined,
55
+ updatedAt: installation.updated_at
56
+ ? (0, uni_time_1.asUniDateTime)(installation.updated_at)
57
+ : undefined,
58
+ });
59
+ };
60
+ exports.castToDeclaredGithubAppInstallation = castToDeclaredGithubAppInstallation;
61
+ //# sourceMappingURL=castToDeclaredGithubAppInstallation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"castToDeclaredGithubAppInstallation.js","sourceRoot":"","sources":["../../../src/domain.operations/appInstallation/castToDeclaredGithubAppInstallation.ts"],"names":[],"mappings":";;;AAAA,iDAAmD;AAEnD,mDAA6C;AAC7C,mDAAyD;AAGzD,8EAA2E;AAC3E,sGAAmG;AACnG,kFAA+E;AAQ/E;;;;GAIG;AACI,MAAM,mCAAmC,GAAG,CAAC,KAInD,EAA8C,EAAE;IAC/C,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IAEpC,uBAAuB;IACvB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;IACrC,IAAI,CAAC,OAAO;QACV,wCAAuB,CAAC,KAAK,CAAC,gCAAgC,EAAE;YAC9D,YAAY;SACb,CAAC,CAAC;IAEL,8CAA8C;IAC9C,MAAM,UAAU,GAAG,OAAO,IAAI,OAAO,CAAC,CAAC,CAAE,OAAO,CAAC,KAAgB,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9E,IAAI,CAAC,UAAU;QACb,wCAAuB,CAAC,KAAK,CAAC,sCAAsC,EAAE;YACpE,YAAY;YACZ,OAAO;SACR,CAAC,CAAC;IAEL,sBAAsB;IACtB,MAAM,UAAU,GAAG,YAAY,CAAC,WAAW,CAAC;IAC5C,IAAI,CAAC,UAAU;QACb,wCAAuB,CAAC,KAAK,CAAC,oCAAoC,EAAE;YAClE,YAAY;SACb,CAAC,CAAC;IAEL,wBAAwB;IACxB,MAAM,MAAM,GAAG,IAAI,yCAAmB,CAAC;QACrC,IAAI,EAAE,UAAU,CAAC,WAAW,EAA6B;QACzD,IAAI,EAAE,UAAU;KACjB,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,mBAAmB,GAAG,CAAC,YAAY,CAAC,oBAAoB,IAAI,KAAK,CAEzD,CAAC;IAEf,OAAO,6DAA6B,CAAC,EAAE,CAAC;QACtC,EAAE,EAAE,YAAY,CAAC,EAAE;QACnB,GAAG,EACD,GAAG,YAAY,qCAAiB;YAC9B,CAAC,CAAC,IAAA,4BAAW,EAA2B,GAAG,CAAC;YAC5C,CAAC,CAAC,GAAG;QACT,MAAM;QACN,mBAAmB;QACnB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,SAAS,EAAE,YAAY,CAAC,YAAY,KAAK,IAAI;QAC7C,SAAS,EAAE,YAAY,CAAC,UAAU;YAChC,CAAC,CAAC,IAAA,wBAAa,EAAC,YAAY,CAAC,UAAU,CAAC;YACxC,CAAC,CAAC,SAAS;QACb,SAAS,EAAE,YAAY,CAAC,UAAU;YAChC,CAAC,CAAC,IAAA,wBAAa,EAAC,YAAY,CAAC,UAAU,CAAC;YACxC,CAAC,CAAC,SAAS;KACd,CAA+C,CAAC;AACnD,CAAC,CAAC;AAzDW,QAAA,mCAAmC,uCAyD9C"}
@@ -0,0 +1,11 @@
1
+ import type { VisualogicContext } from 'visualogic';
2
+ import type { ContextGithubApi } from '../../domain.objects/ContextGithubApi';
3
+ import type { DeclaredGithubAppInstallation } from '../../domain.objects/DeclaredGithubAppInstallation';
4
+ /**
5
+ * .what = deletes a GitHub App installation
6
+ * .why = provides declarative interface with helpful error since deletion requires App JWT
7
+ * .note = DELETE /app/installations/{id} requires App JWT which is out of scope; throws HelpfulError with uninstall URL
8
+ */
9
+ export declare const deleteAppInstallation: (input: {
10
+ installation: DeclaredGithubAppInstallation;
11
+ }, _context: ContextGithubApi & VisualogicContext) => Promise<never>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteAppInstallation = void 0;
4
+ const as_procedure_1 = require("as-procedure");
5
+ const helpful_errors_1 = require("helpful-errors");
6
+ /**
7
+ * .what = deletes a GitHub App installation
8
+ * .why = provides declarative interface with helpful error since deletion requires App JWT
9
+ * .note = DELETE /app/installations/{id} requires App JWT which is out of scope; throws HelpfulError with uninstall URL
10
+ */
11
+ exports.deleteAppInstallation = (0, as_procedure_1.asProcedure)(async (input, _context) => {
12
+ const { installation } = input;
13
+ // construct the uninstall URL based on target type
14
+ const uninstallUrl = installation.target.type === 'organization'
15
+ ? `https://github.com/organizations/${installation.target.slug}/settings/installations`
16
+ : `https://github.com/settings/installations`;
17
+ throw new helpful_errors_1.HelpfulError('GitHub App installations cannot be deleted via API with a user token. Please uninstall the app manually.', {
18
+ uninstallUrl,
19
+ instructions: [
20
+ `1. Navigate to: ${uninstallUrl}`,
21
+ `2. Find the installation for app "${installation.app.slug}"`,
22
+ '3. Click "Configure" next to the installation',
23
+ '4. Scroll to the "Danger zone" section',
24
+ '5. Click "Uninstall" to remove the installation',
25
+ ],
26
+ note: 'Deletion via API requires an App JWT (authentication as the GitHub App itself), which is out of scope for this SDK.',
27
+ installation,
28
+ });
29
+ });
30
+ //# sourceMappingURL=deleteAppInstallation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deleteAppInstallation.js","sourceRoot":"","sources":["../../../src/domain.operations/appInstallation/deleteAppInstallation.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAC3C,mDAA8C;AAM9C;;;;GAIG;AACU,QAAA,qBAAqB,GAAG,IAAA,0BAAW,EAC9C,KAAK,EACH,KAEC,EACD,QAA8C,EAC9B,EAAE;IAClB,MAAM,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;IAE/B,mDAAmD;IACnD,MAAM,YAAY,GAChB,YAAY,CAAC,MAAM,CAAC,IAAI,KAAK,cAAc;QACzC,CAAC,CAAC,oCAAoC,YAAY,CAAC,MAAM,CAAC,IAAI,yBAAyB;QACvF,CAAC,CAAC,2CAA2C,CAAC;IAElD,MAAM,IAAI,6BAAY,CACpB,0GAA0G,EAC1G;QACE,YAAY;QACZ,YAAY,EAAE;YACZ,mBAAmB,YAAY,EAAE;YACjC,qCAAqC,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG;YAC7D,+CAA+C;YAC/C,wCAAwC;YACxC,iDAAiD;SAClD;QACD,IAAI,EAAE,qHAAqH;QAC3H,YAAY;KACb,CACF,CAAC;AACJ,CAAC,CACF,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { RefByUnique } from 'domain-objects';
2
+ import type { HasMetadata } from 'type-fns';
3
+ import type { VisualogicContext } from 'visualogic';
4
+ import type { ContextGithubApi } from '../../domain.objects/ContextGithubApi';
5
+ import type { DeclaredGithubAppInstallation } from '../../domain.objects/DeclaredGithubAppInstallation';
6
+ /**
7
+ * .what = gets a GitHub App installation by unique key
8
+ * .why = retrieves current state of an installation from GitHub API for declarative management
9
+ * .note = lookup by primary key (installation id) is not supported - requires App JWT auth
10
+ */
11
+ export declare const getOneAppInstallation: (input: {
12
+ by: {
13
+ unique: RefByUnique<typeof DeclaredGithubAppInstallation>;
14
+ };
15
+ }, context: ContextGithubApi & VisualogicContext) => Promise<HasMetadata<DeclaredGithubAppInstallation> | null>;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOneAppInstallation = void 0;
4
+ const as_procedure_1 = require("as-procedure");
5
+ const helpful_errors_1 = require("helpful-errors");
6
+ const getGithubClient_1 = require("../../access/sdks/getGithubClient");
7
+ const hasContextWithAppToken_1 = require("../context/hasContextWithAppToken");
8
+ const hasContextWithPatToken_1 = require("../context/hasContextWithPatToken");
9
+ const castToDeclaredGithubAppInstallation_1 = require("./castToDeclaredGithubAppInstallation");
10
+ /**
11
+ * .what = gets a GitHub App installation by unique key
12
+ * .why = retrieves current state of an installation from GitHub API for declarative management
13
+ * .note = lookup by primary key (installation id) is not supported - requires App JWT auth
14
+ */
15
+ exports.getOneAppInstallation = (0, as_procedure_1.asProcedure)(async (input, context) => {
16
+ // get cached GitHub client
17
+ const github = (0, getGithubClient_1.getGithubClient)({}, context);
18
+ // handle get by unique key
19
+ if (input.by.unique) {
20
+ const { app, target } = input.by.unique;
21
+ // list installations for the org/user and filter by app
22
+ // uses GET /orgs/{org}/installations which works with PAT (admin:read scope)
23
+ try {
24
+ if (target.type === 'organization') {
25
+ const response = await github.orgs.listAppInstallations({
26
+ org: target.slug,
27
+ per_page: 100,
28
+ });
29
+ // find installation matching app slug
30
+ const installation = response.data.installations.find((inst) => inst.app_slug === app.slug);
31
+ if (!installation)
32
+ return null;
33
+ // fetch repositories if selection is 'selected'
34
+ // (the list endpoint doesn't include repositories)
35
+ let repositories = null;
36
+ if (installation.repository_selection === 'selected') {
37
+ // detect token type
38
+ const isPatToken = (0, hasContextWithPatToken_1.hasContextWithPatToken)(null, context);
39
+ const isAppToken = (0, hasContextWithAppToken_1.hasContextWithAppToken)(null, context);
40
+ // fail fast on unknown token type
41
+ if (!isPatToken && !isAppToken) {
42
+ throw new helpful_errors_1.HelpfulError('Unknown token type. Expected PAT (ghp_* or github_pat_*) or installation token (ghs_*).', { tokenPrefix: context.github.token.slice(0, 10) + '...' });
43
+ }
44
+ // PAT: GET /user/installations/{id}/repositories
45
+ if (isPatToken) {
46
+ const reposResponse = await github.apps.listInstallationReposForAuthenticatedUser({
47
+ installation_id: installation.id,
48
+ per_page: 100,
49
+ });
50
+ repositories = reposResponse.data.repositories.map((r) => r.name);
51
+ }
52
+ // installation token: GET /installation/repositories
53
+ if (isAppToken) {
54
+ const reposResponse = await github.apps.listReposAccessibleToInstallation({
55
+ per_page: 100,
56
+ });
57
+ repositories = reposResponse.data.repositories.map((r) => r.name);
58
+ }
59
+ // fail fast if repositories weren't fetched
60
+ if (repositories === null) {
61
+ throw new helpful_errors_1.UnexpectedCodePathError('repositories not fetched for selected installation', { isPatToken, isAppToken, installation_id: installation.id });
62
+ }
63
+ }
64
+ return (0, castToDeclaredGithubAppInstallation_1.castToDeclaredGithubAppInstallation)({
65
+ installation,
66
+ app,
67
+ repositories,
68
+ });
69
+ }
70
+ // for User targets, there's no PAT-accessible endpoint
71
+ if (target.type === 'user') {
72
+ throw new helpful_errors_1.HelpfulError('User installations are not supported. GitHub API has no PAT-accessible endpoint to read user installations.', { target });
73
+ }
74
+ // for unsupported target.type, fail fast
75
+ throw new helpful_errors_1.UnexpectedCodePathError('unsupported target.type', { input });
76
+ }
77
+ catch (error) {
78
+ if (!(error instanceof Error))
79
+ throw error;
80
+ if (error.message.includes('Not Found'))
81
+ return null;
82
+ throw new helpful_errors_1.HelpfulError('github.getOneAppInstallation.byUnique error', {
83
+ cause: error,
84
+ });
85
+ }
86
+ }
87
+ // no valid key provided
88
+ helpful_errors_1.UnexpectedCodePathError.throw('getOneAppInstallation requires by.unique', {
89
+ input,
90
+ });
91
+ });
92
+ //# sourceMappingURL=getOneAppInstallation.js.map