@noodleseed/one 0.62.0 → 0.63.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 (143) hide show
  1. package/dist/bin.js +8 -2
  2. package/dist/bin.js.map +1 -1
  3. package/dist/browser.d.ts +10 -0
  4. package/dist/browser.d.ts.map +1 -0
  5. package/dist/browser.js +18 -0
  6. package/dist/browser.js.map +1 -0
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +4 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/apps-ops.js +1 -1
  11. package/dist/commands/apps-ops.js.map +1 -1
  12. package/dist/commands/deploy-ops.d.ts +2 -3
  13. package/dist/commands/deploy-ops.d.ts.map +1 -1
  14. package/dist/commands/deploy-ops.js +5 -17
  15. package/dist/commands/deploy-ops.js.map +1 -1
  16. package/dist/commands/github-ops.d.ts +3 -2
  17. package/dist/commands/github-ops.d.ts.map +1 -1
  18. package/dist/commands/github-ops.js +7 -4
  19. package/dist/commands/github-ops.js.map +1 -1
  20. package/dist/control-plane.d.ts +2 -1
  21. package/dist/control-plane.d.ts.map +1 -1
  22. package/dist/control-plane.js +31 -10
  23. package/dist/control-plane.js.map +1 -1
  24. package/dist/device-login.d.ts +30 -0
  25. package/dist/device-login.d.ts.map +1 -0
  26. package/dist/device-login.js +162 -0
  27. package/dist/device-login.js.map +1 -0
  28. package/dist/doctor.d.ts.map +1 -1
  29. package/dist/doctor.js +11 -0
  30. package/dist/doctor.js.map +1 -1
  31. package/dist/platform-support.d.ts +22 -0
  32. package/dist/platform-support.d.ts.map +1 -0
  33. package/dist/platform-support.js +118 -0
  34. package/dist/platform-support.js.map +1 -0
  35. package/node_modules/@noodle-borg/service/dist/oauth/app.d.ts.map +1 -1
  36. package/node_modules/@noodle-borg/service/dist/oauth/app.js +65 -0
  37. package/node_modules/@noodle-borg/service/dist/oauth/app.js.map +1 -1
  38. package/node_modules/@noodle-borg/service/dist/oauth/branding.d.ts +2 -0
  39. package/node_modules/@noodle-borg/service/dist/oauth/branding.d.ts.map +1 -1
  40. package/node_modules/@noodle-borg/service/dist/oauth/branding.js +3 -2
  41. package/node_modules/@noodle-borg/service/dist/oauth/branding.js.map +1 -1
  42. package/node_modules/@noodle-borg/service/dist/oauth/developer-grant-page.d.ts.map +1 -1
  43. package/node_modules/@noodle-borg/service/dist/oauth/developer-grant-page.js +216 -28
  44. package/node_modules/@noodle-borg/service/dist/oauth/developer-grant-page.js.map +1 -1
  45. package/node_modules/@noodle-borg/service/dist/oauth/device-flow.d.ts +20 -0
  46. package/node_modules/@noodle-borg/service/dist/oauth/device-flow.d.ts.map +1 -0
  47. package/node_modules/@noodle-borg/service/dist/oauth/device-flow.js +239 -0
  48. package/node_modules/@noodle-borg/service/dist/oauth/device-flow.js.map +1 -0
  49. package/node_modules/@noodle-borg/service/dist/oauth/device-provider.d.ts +15 -0
  50. package/node_modules/@noodle-borg/service/dist/oauth/device-provider.d.ts.map +1 -0
  51. package/node_modules/@noodle-borg/service/dist/oauth/device-provider.js +45 -0
  52. package/node_modules/@noodle-borg/service/dist/oauth/device-provider.js.map +1 -0
  53. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-schema.d.ts +3 -0
  54. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-schema.d.ts.map +1 -0
  55. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-schema.js +33 -0
  56. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-schema.js.map +1 -0
  57. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-types.d.ts +30 -0
  58. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-types.d.ts.map +1 -0
  59. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-types.js +31 -0
  60. package/node_modules/@noodle-borg/service/dist/oauth/device-store-postgres-types.js.map +1 -0
  61. package/node_modules/@noodle-borg/service/dist/oauth/device-store.d.ts +66 -0
  62. package/node_modules/@noodle-borg/service/dist/oauth/device-store.d.ts.map +1 -0
  63. package/node_modules/@noodle-borg/service/dist/oauth/device-store.js +2 -0
  64. package/node_modules/@noodle-borg/service/dist/oauth/device-store.js.map +1 -0
  65. package/node_modules/@noodle-borg/service/dist/oauth/paths.d.ts.map +1 -1
  66. package/node_modules/@noodle-borg/service/dist/oauth/paths.js +3 -0
  67. package/node_modules/@noodle-borg/service/dist/oauth/paths.js.map +1 -1
  68. package/node_modules/@noodle-borg/service/dist/oauth/provider.d.ts +7 -0
  69. package/node_modules/@noodle-borg/service/dist/oauth/provider.d.ts.map +1 -1
  70. package/node_modules/@noodle-borg/service/dist/oauth/provider.js +36 -1
  71. package/node_modules/@noodle-borg/service/dist/oauth/provider.js.map +1 -1
  72. package/node_modules/@noodle-borg/service/dist/oauth/store-postgres.d.ts +14 -0
  73. package/node_modules/@noodle-borg/service/dist/oauth/store-postgres.d.ts.map +1 -1
  74. package/node_modules/@noodle-borg/service/dist/oauth/store-postgres.js +122 -0
  75. package/node_modules/@noodle-borg/service/dist/oauth/store-postgres.js.map +1 -1
  76. package/node_modules/@noodle-borg/service/dist/oauth/store.d.ts +15 -1
  77. package/node_modules/@noodle-borg/service/dist/oauth/store.d.ts.map +1 -1
  78. package/node_modules/@noodle-borg/service/dist/oauth/store.js +83 -0
  79. package/node_modules/@noodle-borg/service/dist/oauth/store.js.map +1 -1
  80. package/node_modules/bundle-name/index.js +5 -0
  81. package/node_modules/bundle-name/license +9 -0
  82. package/node_modules/bundle-name/package.json +45 -0
  83. package/node_modules/bundle-name/readme.md +23 -0
  84. package/node_modules/default-browser/index.d.ts +29 -0
  85. package/node_modules/default-browser/index.js +34 -0
  86. package/node_modules/default-browser/license +9 -0
  87. package/node_modules/default-browser/package.json +54 -0
  88. package/node_modules/default-browser/readme.md +24 -0
  89. package/node_modules/default-browser/windows.js +57 -0
  90. package/node_modules/default-browser-id/index.js +25 -0
  91. package/node_modules/default-browser-id/license +9 -0
  92. package/node_modules/default-browser-id/package.json +41 -0
  93. package/node_modules/default-browser-id/readme.md +19 -0
  94. package/node_modules/define-lazy-prop/index.d.ts +31 -0
  95. package/node_modules/define-lazy-prop/index.js +18 -0
  96. package/node_modules/define-lazy-prop/license +9 -0
  97. package/node_modules/define-lazy-prop/package.json +51 -0
  98. package/node_modules/define-lazy-prop/readme.md +55 -0
  99. package/node_modules/is-docker/cli.js +5 -0
  100. package/node_modules/is-docker/index.d.ts +13 -0
  101. package/node_modules/is-docker/index.js +29 -0
  102. package/node_modules/is-docker/license +9 -0
  103. package/node_modules/is-docker/package.json +44 -0
  104. package/node_modules/is-docker/readme.md +27 -0
  105. package/node_modules/is-in-ssh/index.d.ts +15 -0
  106. package/node_modules/is-in-ssh/index.js +7 -0
  107. package/node_modules/is-in-ssh/license +9 -0
  108. package/node_modules/is-in-ssh/package.json +43 -0
  109. package/node_modules/is-in-ssh/readme.md +43 -0
  110. package/node_modules/is-inside-container/cli.js +5 -0
  111. package/node_modules/is-inside-container/index.d.ts +13 -0
  112. package/node_modules/is-inside-container/index.js +23 -0
  113. package/node_modules/is-inside-container/license +9 -0
  114. package/node_modules/is-inside-container/package.json +51 -0
  115. package/node_modules/is-inside-container/readme.md +36 -0
  116. package/node_modules/is-wsl/index.d.ts +15 -0
  117. package/node_modules/is-wsl/index.js +36 -0
  118. package/node_modules/is-wsl/license +9 -0
  119. package/node_modules/is-wsl/package.json +58 -0
  120. package/node_modules/is-wsl/readme.md +21 -0
  121. package/node_modules/open/index.d.ts +158 -0
  122. package/node_modules/open/index.js +417 -0
  123. package/node_modules/open/license +9 -0
  124. package/node_modules/open/package.json +70 -0
  125. package/node_modules/open/readme.md +197 -0
  126. package/node_modules/open/xdg-open +1267 -0
  127. package/node_modules/powershell-utils/index.d.ts +122 -0
  128. package/node_modules/powershell-utils/index.js +58 -0
  129. package/node_modules/powershell-utils/license +9 -0
  130. package/node_modules/powershell-utils/package.json +47 -0
  131. package/node_modules/powershell-utils/readme.md +153 -0
  132. package/node_modules/run-applescript/index.d.ts +66 -0
  133. package/node_modules/run-applescript/index.js +37 -0
  134. package/node_modules/run-applescript/license +9 -0
  135. package/node_modules/run-applescript/package.json +42 -0
  136. package/node_modules/run-applescript/readme.md +78 -0
  137. package/node_modules/wsl-utils/index.d.ts +81 -0
  138. package/node_modules/wsl-utils/index.js +98 -0
  139. package/node_modules/wsl-utils/license +9 -0
  140. package/node_modules/wsl-utils/package.json +48 -0
  141. package/node_modules/wsl-utils/readme.md +111 -0
  142. package/node_modules/wsl-utils/utilities.js +19 -0
  143. package/package.json +14 -1
@@ -0,0 +1,118 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { delimiter, join } from 'node:path';
3
+ import { EXIT, printJsonFailure } from './commands/output.js';
4
+ const DISCOVERY_COMMANDS = new Set(['--help', '-h', 'help', '--version', '-v', 'version']);
5
+ const MOUNTED_WINDOWS_PATH = /^\/mnt\/[a-z](?:\/|$)/i;
6
+ export function platformSupportFailure(argv, platform) {
7
+ if (platform !== 'win32' || DISCOVERY_COMMANDS.has(argv[0] ?? ''))
8
+ return undefined;
9
+ return {
10
+ code: 'unsupported_platform',
11
+ message: 'Noodle CLI commands run on macOS or Windows through WSL2.',
12
+ cause: 'Native Windows shells are not supported in this first slice.',
13
+ fix: 'Install WSL2 with Ubuntu and run Noodle from its Linux terminal.',
14
+ next: 'wsl --install -d Ubuntu',
15
+ };
16
+ }
17
+ export function enforcePlatformSupport(argv, platform) {
18
+ const failure = platformSupportFailure(argv, platform);
19
+ if (failure === undefined)
20
+ return undefined;
21
+ if (argv.includes('--json'))
22
+ return printJsonFailure(failure, EXIT.USAGE);
23
+ console.error([
24
+ `${failure.code}: ${failure.message}`,
25
+ `Cause: ${failure.cause}`,
26
+ `Fix: ${failure.fix}`,
27
+ `Next: ${failure.next}`,
28
+ ].join('\n'));
29
+ return EXIT.USAGE;
30
+ }
31
+ export function wslPlatformChecks(input) {
32
+ if (!isWsl(input.platform, input.env, input.kernelRelease))
33
+ return [];
34
+ const distro = input.env.WSL_DISTRO_NAME;
35
+ const isWsl2 = /wsl2/i.test(input.kernelRelease);
36
+ const isUbuntu = distro !== undefined && /^ubuntu(?:-|$)/i.test(distro);
37
+ const checks = [
38
+ !isWsl2
39
+ ? {
40
+ level: 'WARN',
41
+ name: 'Platform',
42
+ message: `WSL version 2 not detected${distro ? ` (${distro})` : ''}`,
43
+ cause: 'The supported Windows environment is WSL2 with Ubuntu.',
44
+ fix: 'Upgrade this distro to WSL2 from PowerShell.',
45
+ next: distro !== undefined
46
+ ? `wsl.exe --set-version ${distro} 2`
47
+ : 'wsl.exe --set-default-version 2',
48
+ }
49
+ : distro === undefined
50
+ ? {
51
+ level: 'WARN',
52
+ name: 'Platform',
53
+ message: 'WSL2 distro could not be identified',
54
+ cause: 'The supported Windows environment is WSL2 with Ubuntu.',
55
+ fix: 'Run Noodle from an Ubuntu WSL2 terminal.',
56
+ next: 'wsl.exe --list --verbose',
57
+ }
58
+ : !isUbuntu
59
+ ? {
60
+ level: 'WARN',
61
+ name: 'Platform',
62
+ message: `WSL2 distro is not Ubuntu (${distro})`,
63
+ cause: 'The supported Windows environment is WSL2 with Ubuntu.',
64
+ fix: 'Install the supported Ubuntu distro for Noodle CLI work.',
65
+ next: 'wsl.exe --install -d Ubuntu',
66
+ }
67
+ : {
68
+ level: 'PASS',
69
+ name: 'Platform',
70
+ message: `WSL2 (${distro})`,
71
+ },
72
+ ];
73
+ if (isMountedWindowsPath(input.cwd)) {
74
+ checks.push({
75
+ level: 'WARN',
76
+ name: 'WSL workspace',
77
+ message: input.cwd,
78
+ cause: 'The project is on a mounted Windows drive, which makes Node file watching and installs slower and less reliable.',
79
+ fix: 'Move the repository into the WSL Linux filesystem, such as ~/src.',
80
+ next: 'mkdir -p ~/src',
81
+ });
82
+ }
83
+ if (isMountedWindowsPath(input.nodePath) || isMountedWindowsPath(input.npmPath)) {
84
+ checks.push({
85
+ level: 'WARN',
86
+ name: 'WSL runtime',
87
+ message: 'mounted Windows Node/npm detected',
88
+ cause: 'Node or npm resolves from /mnt, so the CLI is mixing Windows tools with the WSL environment.',
89
+ fix: 'Install Node 24 and npm inside WSL, then ensure the Linux binaries appear first on PATH.',
90
+ next: 'command -v node && command -v npm',
91
+ });
92
+ }
93
+ return checks;
94
+ }
95
+ export function findExecutableOnPath(name, pathValue) {
96
+ if (!pathValue)
97
+ return undefined;
98
+ for (const directory of pathValue.split(delimiter)) {
99
+ if (!directory)
100
+ continue;
101
+ for (const candidateName of [name, `${name}.cmd`, `${name}.exe`]) {
102
+ const candidate = join(directory, candidateName);
103
+ if (existsSync(candidate))
104
+ return candidate;
105
+ }
106
+ }
107
+ return undefined;
108
+ }
109
+ function isWsl(platform, env, kernelRelease) {
110
+ return (platform === 'linux' &&
111
+ (env.WSL_DISTRO_NAME !== undefined ||
112
+ env.WSL_INTEROP !== undefined ||
113
+ /microsoft|wsl/i.test(kernelRelease)));
114
+ }
115
+ function isMountedWindowsPath(path) {
116
+ return path !== undefined && MOUNTED_WINDOWS_PATH.test(path);
117
+ }
118
+ //# sourceMappingURL=platform-support.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-support.js","sourceRoot":"","sources":["../src/platform-support.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/oauth/app.ts"],"names":[],"mappings":"AAIA,OAAgB,EAAE,KAAK,OAAO,EAA+B,MAAM,SAAS,CAAC;AAE7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAqET;AAkCD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/oauth/app.ts"],"names":[],"mappings":"AAIA,OAAgB,EAAE,KAAK,OAAO,EAA+B,MAAM,SAAS,CAAC;AAG7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAuIT;AA0CD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -3,6 +3,7 @@ import { clientRegistrationHandler } from '@modelcontextprotocol/sdk/server/auth
3
3
  import { revocationHandler } from '@modelcontextprotocol/sdk/server/auth/handlers/revoke.js';
4
4
  import { tokenHandler } from '@modelcontextprotocol/sdk/server/auth/handlers/token.js';
5
5
  import express, {} from 'express';
6
+ import { rateLimit as createRateLimit } from 'express-rate-limit';
6
7
  import { renderOAuthErrorPage } from './branding.js';
7
8
  export function createOAuthApp(provider, options = {}) {
8
9
  const app = express();
@@ -17,7 +18,64 @@ export function createOAuthApp(provider, options = {}) {
17
18
  xForwardedForHeader: false,
18
19
  },
19
20
  };
21
+ app.use(['/device_authorization', '/device', '/oauth/device/callback'], createRateLimit({
22
+ windowMs: 60_000,
23
+ limit: 30,
24
+ standardHeaders: true,
25
+ legacyHeaders: false,
26
+ ...rateLimit,
27
+ }), createRateLimit({
28
+ windowMs: 60_000,
29
+ limit: 600,
30
+ standardHeaders: false,
31
+ legacyHeaders: false,
32
+ keyGenerator: transportRateLimitKey,
33
+ validate: rateLimit.validate,
34
+ }));
35
+ const deviceTokenRateLimit = createRateLimit({
36
+ windowMs: 60_000,
37
+ limit: 30,
38
+ standardHeaders: true,
39
+ legacyHeaders: false,
40
+ ...rateLimit,
41
+ });
42
+ const deviceTokenTransportRateLimit = createRateLimit({
43
+ windowMs: 60_000,
44
+ limit: 600,
45
+ standardHeaders: false,
46
+ legacyHeaders: false,
47
+ keyGenerator: transportRateLimitKey,
48
+ validate: rateLimit.validate,
49
+ });
20
50
  app.use('/authorize', authorizationHandler({ provider, rateLimit }));
51
+ app.post('/device_authorization', express.urlencoded({ extended: false }), (req, res) => {
52
+ void provider.deviceAuthorizationFlow
53
+ .handleAuthorization(req, res)
54
+ .catch(() => failJson(res));
55
+ });
56
+ app.get('/device', (req, res) => {
57
+ provider.deviceAuthorizationFlow.handleVerificationPage(req, res);
58
+ });
59
+ app.post('/device', express.urlencoded({ extended: false }), (req, res) => {
60
+ void provider.deviceAuthorizationFlow.handleVerification(req, res).catch(() => failPlain(res));
61
+ });
62
+ app.get('/oauth/device/callback', (req, res) => {
63
+ void provider.deviceAuthorizationFlow.handleCallback(req, res).catch(() => failPlain(res));
64
+ });
65
+ app.use(express.urlencoded({ extended: false }));
66
+ app.use('/token', allowCors);
67
+ app.use('/token', (req, res, next) => {
68
+ const body = (req.body ?? {});
69
+ if (body.grant_type !== 'urn:ietf:params:oauth:grant-type:device_code') {
70
+ next();
71
+ return;
72
+ }
73
+ deviceTokenTransportRateLimit(req, res, () => {
74
+ deviceTokenRateLimit(req, res, () => {
75
+ void provider.deviceAuthorizationFlow.handleToken(req, res).catch(() => failJson(res));
76
+ });
77
+ });
78
+ });
21
79
  app.use('/token', tokenHandler({ provider, rateLimit }));
22
80
  app.use('/revoke', revocationHandler({ provider, rateLimit }));
23
81
  app.use('/register', clientRegistrationHandler({ clientsStore: provider.clientsStore, rateLimit }));
@@ -63,6 +121,10 @@ function failPlain(res) {
63
121
  if (!res.headersSent)
64
122
  res.status(500).type('text/html').send(renderOAuthErrorPage());
65
123
  }
124
+ function failJson(res) {
125
+ if (!res.headersSent)
126
+ res.status(500).json({ error: 'server_error' });
127
+ }
66
128
  function rateLimitKey(req, trustProxy) {
67
129
  if (trustProxy) {
68
130
  const forwarded = firstForwardedFor(req.headers.forwarded);
@@ -74,6 +136,9 @@ function rateLimitKey(req, trustProxy) {
74
136
  }
75
137
  return req.ip ?? req.socket.remoteAddress ?? 'unknown';
76
138
  }
139
+ function transportRateLimitKey(req) {
140
+ return req.socket.remoteAddress ?? 'unknown';
141
+ }
77
142
  function firstForwardedFor(value) {
78
143
  const raw = firstHeaderValue(value);
79
144
  if (!raw)
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/oauth/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/oauth/app.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,8 @@ export interface OAuthPageInput {
20
20
  readonly heading: string;
21
21
  /** Pre-escaped inner HTML (lede, detail list, form). Callers own their own escaping. */
22
22
  readonly contentHtml: string;
23
+ /** Optional trusted static CSS appended after the shared OAuth styles. */
24
+ readonly additionalStyles?: string;
23
25
  /** Optional pre-built `<script>` block appended before `</body>` (e.g. the customer sign-in module). */
24
26
  readonly scriptHtml?: string;
25
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/oauth/branding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAiLH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wGAAwG;IACxG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CA+B7D;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C"}
1
+ {"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/oauth/branding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAkLH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,wGAAwG;IACxG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CA+B7D;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C"}
@@ -120,7 +120,7 @@ body{
120
120
  margin:0;min-height:100dvh;background:var(--bg);color:var(--fg);
121
121
  font-family:"Geist",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
122
122
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
123
- display:grid;place-items:center;padding:24px;position:relative;overflow:hidden;
123
+ display:flex;justify-content:center;align-items:flex-start;padding:24px;position:relative;overflow:auto;
124
124
  }
125
125
  /* WebGL grain-gradient canvas over an on-brand CSS radial-gradient fallback. */
126
126
  .ns-canvas{position:fixed;inset:0;width:100%;height:100%;z-index:-4;display:block;pointer-events:none}
@@ -139,6 +139,7 @@ body{
139
139
  border:1px solid var(--border);border-radius:1.1rem;background:var(--card);
140
140
  -webkit-backdrop-filter:blur(16px) saturate(1.2);backdrop-filter:blur(16px) saturate(1.2);
141
141
  padding:1.9rem;
142
+ margin:auto 0;
142
143
  box-shadow:0 30px 90px -45px rgba(0,0,0,.9),0 0 0 1px rgba(255,255,255,.02),inset 0 1px 0 0 rgba(255,255,255,.06);
143
144
  }
144
145
  .ns-head{display:flex;align-items:center;margin-bottom:1.6rem}
@@ -193,7 +194,7 @@ export function renderOAuthPage(input) {
193
194
  <link rel="preconnect" href="https://fonts.googleapis.com" />
194
195
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
195
196
  <link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
196
- <style>${STYLES}</style>
197
+ <style>${STYLES}${input.additionalStyles ?? ''}</style>
197
198
  </head>
198
199
  <body>
199
200
  <canvas id="ns-canvas" class="ns-canvas" aria-hidden="true"></canvas>
@@ -1 +1 @@
1
- {"version":3,"file":"branding.js","sourceRoot":"","sources":["../../src/oauth/branding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,SAAS,GAAG,CAAC,KAAa;IACxB,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,2FAA2F;AAC3F,MAAM,OAAO,GAAG,sBAAsB,kBAAkB,CACtD,0nBAA0nB,CAC3nB,EAAE,CAAC;AAEJ,8GAA8G;AAC9G,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;OAcV,CAAC;AAER;;;;;GAKG;AACH,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6DZ,CAAC;AAEX,0GAA0G;AAC1G,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0EAwE2D,CAAC;AAe3E,oGAAoG;AACpG,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,OAAO;;;;;;;SAOA,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;8CACqB,OAAO;;;;SAI5C,MAAM;;;;;;;;;yBASU,QAAQ;yBACR,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;yBACjB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;IACvC,KAAK,CAAC,WAAW;;EAEnB,aAAa;EACb,KAAK,CAAC,UAAU,IAAI,EAAE;;QAEhB,CAAC;AACT,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,oBAAoB;IAClC,OAAO,eAAe,CAAC;QACrB,KAAK,EAAE,6BAA6B;QACpC,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,eAAe;QACxB,WAAW,EACT,6HAA6H;KAChI,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"branding.js","sourceRoot":"","sources":["../../src/oauth/branding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,SAAS,GAAG,CAAC,KAAa;IACxB,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,2FAA2F;AAC3F,MAAM,OAAO,GAAG,sBAAsB,kBAAkB,CACtD,0nBAA0nB,CAC3nB,EAAE,CAAC;AAEJ,8GAA8G;AAC9G,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;OAcV,CAAC;AAER;;;;;GAKG;AACH,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6DZ,CAAC;AAEX,0GAA0G;AAC1G,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0EAyE2D,CAAC;AAiB3E,oGAAoG;AACpG,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,OAAO;;;;;;;SAOA,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;8CACqB,OAAO;;;;SAI5C,MAAM,GAAG,KAAK,CAAC,gBAAgB,IAAI,EAAE;;;;;;;;;yBASrB,QAAQ;yBACR,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;yBACjB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;IACvC,KAAK,CAAC,WAAW;;EAEnB,aAAa;EACb,KAAK,CAAC,UAAU,IAAI,EAAE;;QAEhB,CAAC;AACT,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,oBAAoB;IAClC,OAAO,eAAe,CAAC;QACrB,KAAK,EAAE,6BAA6B;QACpC,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,eAAe;QACxB,WAAW,EACT,6HAA6H;KAChI,CAAC,CAAC;AACL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"developer-grant-page.d.ts","sourceRoot":"","sources":["../../src/oauth/developer-grant-page.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACnD;AAQD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAyB/E"}
1
+ {"version":3,"file":"developer-grant-page.d.ts","sourceRoot":"","sources":["../../src/oauth/developer-grant-page.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACnD;AA+HD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAuB/E"}
@@ -4,21 +4,133 @@ const CAPABILITY_COPY = {
4
4
  'deployments:write': 'Build and deploy apps to the selected environments',
5
5
  'deployments:rollback': 'Roll back deployments',
6
6
  };
7
+ const ENVIRONMENT_PRIORITY = {
8
+ dev: 0,
9
+ staging: 1,
10
+ prod: 3,
11
+ };
12
+ const DEVELOPER_GRANT_STYLES = `
13
+ .ns-card{width:min(100%,46rem)}
14
+ .ns-title{max-width:38rem;white-space:normal}
15
+ .developer-context{grid-template-columns:repeat(3,minmax(0,1fr));gap:.75rem;margin-bottom:1.55rem}
16
+ .developer-context>div{min-width:0}
17
+ .developer-context .ns-dd{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
18
+ .developer-grant{display:grid;gap:1.35rem}
19
+ .developer-section{min-width:0;margin:0;padding:0;border:0}
20
+ .developer-step{display:flex;align-items:center;gap:.6rem;margin:0 0 .3rem;color:var(--fg);font-size:.94rem;font-weight:650}
21
+ .developer-step-number{display:grid;place-items:center;width:1.6rem;height:1.6rem;border:1px solid var(--border);border-radius:999px;color:var(--orange);font-size:.72rem}
22
+ .developer-help{margin:0 0 .8rem;color:var(--muted);font-size:.8rem;line-height:1.5}
23
+ .developer-org-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.65rem}
24
+ .developer-org-choice{position:relative;display:block;min-width:0;cursor:pointer}
25
+ .developer-org-choice>input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
26
+ .developer-org-card{display:flex;align-items:center;justify-content:space-between;gap:.85rem;min-height:4rem;padding:.85rem .95rem;border:1px solid var(--border);border-radius:.8rem;background:rgba(255,255,255,.025);transition:border-color .16s ease,background .16s ease,box-shadow .16s ease}
27
+ .developer-org-choice:hover .developer-org-card{border-color:color-mix(in srgb,var(--border),var(--fg) 20%);background:rgba(255,255,255,.04)}
28
+ .developer-org-choice>input:focus-visible+.developer-org-card{outline:2px solid var(--orange);outline-offset:2px}
29
+ .developer-org-choice>input:checked+.developer-org-card{border-color:color-mix(in srgb,var(--orange) 70%,transparent);background:linear-gradient(135deg,color-mix(in srgb,var(--orange) 13%,transparent),rgba(255,255,255,.025));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--orange) 12%,transparent)}
30
+ .developer-org-name{display:block;overflow:hidden;color:var(--fg);font-size:.88rem;font-weight:650;text-overflow:ellipsis;white-space:nowrap}
31
+ .developer-org-access{display:block;margin-top:.18rem;color:var(--muted);font-size:.72rem}
32
+ .developer-choice-mark{display:grid;flex:0 0 auto;place-items:center;width:1.1rem;height:1.1rem;border:1px solid var(--border);border-radius:999px;color:transparent;font-size:.65rem}
33
+ .developer-org-choice>input:checked+.developer-org-card .developer-choice-mark{border-color:var(--orange);background:var(--orange);color:#130b07}
34
+ .developer-environment-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.6rem}
35
+ .developer-environment{position:relative;display:block;min-width:0;cursor:pointer}
36
+ .developer-environment>input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
37
+ .developer-environment-card{display:flex;align-items:flex-start;gap:.65rem;min-height:4.1rem;padding:.8rem;border:1px solid var(--border);border-radius:.75rem;background:rgba(255,255,255,.025);transition:border-color .16s ease,background .16s ease}
38
+ .developer-environment:hover .developer-environment-card{border-color:color-mix(in srgb,var(--border),var(--fg) 20%);background:rgba(255,255,255,.04)}
39
+ .developer-environment>input:focus-visible+.developer-environment-card{outline:2px solid var(--orange);outline-offset:2px}
40
+ .developer-environment>input:checked+.developer-environment-card{border-color:color-mix(in srgb,var(--orange) 70%,transparent);background:color-mix(in srgb,var(--orange) 10%,transparent)}
41
+ .developer-checkbox{display:grid;flex:0 0 auto;place-items:center;width:1rem;height:1rem;margin-top:.08rem;border:1px solid var(--border);border-radius:.25rem;color:transparent;font-size:.68rem}
42
+ .developer-environment>input:checked+.developer-environment-card .developer-checkbox{border-color:var(--orange);background:var(--orange);color:#130b07}
43
+ .developer-environment-name{display:block;color:var(--fg);font-size:.84rem;font-weight:650}
44
+ .developer-environment-note{display:block;margin-top:.2rem;color:var(--muted);font-size:.68rem;line-height:1.35}
45
+ .developer-environment-note.is-production{color:#f1a273}
46
+ .developer-capabilities{margin:.75rem 0 0;padding:.7rem .8rem;border:1px solid var(--border);border-radius:.7rem;background:rgba(0,0,0,.12);color:var(--muted);font-size:.75rem}
47
+ .developer-capabilities summary{cursor:pointer;color:var(--fg);font-weight:600}
48
+ .developer-capabilities ul{display:grid;gap:.35rem;margin:.6rem 0 0;padding-left:1.15rem;line-height:1.45}
49
+ .developer-summary{padding:.85rem .95rem;border:1px solid var(--border);border-radius:.75rem;background:rgba(255,255,255,.025)}
50
+ .developer-summary-label{margin:0 0 .24rem;color:var(--muted);font-size:.65rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase}
51
+ .developer-summary-copy{margin:0;color:var(--fg);font-size:.8rem;line-height:1.5}
52
+ .developer-selection-error{margin:.45rem 0 0;color:#f1a273;font-size:.75rem}
53
+ .developer-grant .ns-row{margin-top:0}
54
+ .developer-grant .btn-primary:disabled{cursor:not-allowed;filter:none;opacity:.45}
55
+ @media(max-width:680px){
56
+ .ns-card{padding:1.35rem}
57
+ .developer-context,.developer-org-list,.developer-environment-grid{grid-template-columns:1fr}
58
+ .developer-context{gap:.55rem}
59
+ }
60
+ `;
61
+ const DEVELOPER_GRANT_SCRIPT = `<script>
62
+ (function(){
63
+ var form=document.querySelector('[data-developer-grant]');
64
+ if(!form)return;
65
+ var choices=Array.from(form.querySelectorAll('[data-org-choice]'));
66
+ var panels=Array.from(form.querySelectorAll('[data-org-panel]'));
67
+ var authorize=form.querySelector('[data-authorize]');
68
+ var summary=form.querySelector('[data-selection-summary]');
69
+ var error=form.querySelector('[data-selection-error]');
70
+ var clientName=form.getAttribute('data-client-name')||'The developer plugin';
71
+ function activeIndex(){
72
+ var selected=choices.find(function(choice){return choice.checked;});
73
+ return selected ? Number(selected.getAttribute('data-org-choice')) : -1;
74
+ }
75
+ function activeEnvironments(){
76
+ var panel=panels[activeIndex()];
77
+ return panel ? Array.from(panel.querySelectorAll('input[name="environment"]:checked')).map(function(input){return input.value;}) : [];
78
+ }
79
+ function naturalList(values){
80
+ if(values.length<2)return values[0]||'';
81
+ if(values.length===2)return values[0]+' and '+values[1];
82
+ return values.slice(0,-1).join(', ')+', and '+values[values.length-1];
83
+ }
84
+ function update(){
85
+ var panel=panels[activeIndex()];
86
+ var environments=activeEnvironments();
87
+ var valid=panel!==undefined&&environments.length>0;
88
+ authorize.disabled=!valid;
89
+ error.hidden=valid;
90
+ if(valid){
91
+ summary.textContent=clientName+' can '+panel.getAttribute('data-capability-summary')+' in '+panel.getAttribute('data-org-name')+' for '+naturalList(environments)+'.';
92
+ }else{
93
+ summary.textContent='Select at least one environment to continue.';
94
+ }
95
+ }
96
+ choices.forEach(function(choice){
97
+ choice.addEventListener('change',function(){
98
+ var next=activeIndex();
99
+ panels.forEach(function(panel,index){
100
+ var active=index===next;
101
+ panel.hidden=!active;
102
+ var environments=Array.from(panel.querySelectorAll('input[name="environment"]'));
103
+ environments.forEach(function(environment){environment.checked=false;environment.disabled=!active;});
104
+ if(active){
105
+ var preferred=environments.find(function(environment){return environment.value==='dev';});
106
+ if(preferred)preferred.checked=true;
107
+ }
108
+ });
109
+ update();
110
+ });
111
+ });
112
+ form.addEventListener('change',function(event){
113
+ if(event.target&&event.target.matches('input[name="environment"]'))update();
114
+ });
115
+ form.addEventListener('submit',function(event){
116
+ var submitter=event.submitter;
117
+ if(submitter&&submitter.value==='deny')return;
118
+ if(activeEnvironments().length===0){event.preventDefault();update();}
119
+ });
120
+ update();
121
+ })();
122
+ </script>`;
7
123
  export function renderDeveloperGrantPage(input) {
8
- const choices = input.choices.map(renderChoice).join('');
9
124
  const controls = input.choices.length === 0
10
- ? '<p class="ns-note">No organizations are available for this account.</p>'
11
- : `${choices}<div class="ns-row">
12
- <button type="submit" name="decision" value="deny" class="btn btn-ghost">Deny</button>
13
- <span class="btn-glow"><button type="submit" name="decision" value="approve" class="btn btn-primary">Authorize</button></span>
14
- </div>`;
15
- const contentHtml = `<p class="ns-lede"><strong>${escapeHtml(input.clientName)}</strong> will be able to guide and operate Noodle Cloud autonomously within the access you select.</p>
16
- <dl class="ns-dl">
17
- <div><dt class="ns-dt">Signed in as</dt><dd class="ns-dd">${escapeHtml(input.userEmail)}</dd></div>
18
- <div><dt class="ns-dt">Noodle Cloud</dt><dd class="ns-dd">${escapeHtml(input.resourceHost)}</dd></div>
19
- <div><dt class="ns-dt">Redirects to</dt><dd class="ns-dd">${escapeHtml(input.redirectHost)}</dd></div>
125
+ ? '<div class="ns-alert"><p class="ns-note">No organizations are available for this account.</p></div>'
126
+ : renderControls(input);
127
+ const contentHtml = `<p class="ns-lede">Review and choose the exact access for <strong>${escapeHtml(input.clientName)}</strong>. You can select more than one environment.</p>
128
+ <dl class="ns-dl developer-context">
129
+ <div><dt class="ns-dt">Signed in as</dt><dd class="ns-dd" title="${escapeHtml(input.userEmail)}">${escapeHtml(input.userEmail)}</dd></div>
130
+ <div><dt class="ns-dt">Noodle Cloud</dt><dd class="ns-dd" title="${escapeHtml(input.resourceHost)}">${escapeHtml(input.resourceHost)}</dd></div>
131
+ <div><dt class="ns-dt">Redirects to</dt><dd class="ns-dd" title="${escapeHtml(input.redirectHost)}">${escapeHtml(input.redirectHost)}</dd></div>
20
132
  </dl>
21
- <form method="post" action="${escapeHtml(input.grantAction)}">
133
+ <form method="post" action="${escapeHtml(input.grantAction)}" class="developer-grant" data-developer-grant data-client-name="${escapeHtml(input.clientName)}">
22
134
  <input type="hidden" name="grant_token" value="${escapeHtml(input.grantToken)}" />
23
135
  ${controls}
24
136
  </form>`;
@@ -27,28 +139,104 @@ export function renderDeveloperGrantPage(input) {
27
139
  kicker: 'Developer access',
28
140
  heading: 'Choose where this developer plugin can operate',
29
141
  contentHtml,
142
+ additionalStyles: DEVELOPER_GRANT_STYLES,
143
+ ...(input.choices.length === 0 ? {} : { scriptHtml: DEVELOPER_GRANT_SCRIPT }),
30
144
  });
31
145
  }
32
- function renderChoice(choice, index) {
33
- const org = escapeHtml(choice.org);
34
- const label = escapeHtml(choice.displayName ?? choice.org);
35
- const environments = choice.environments
36
- .map((environment) => {
37
- const escaped = escapeHtml(environment);
38
- const productionNote = environment === 'prod' ? ' <span class="ns-note">explicit access</span>' : '';
39
- return `<label><input type="checkbox" name="environment" value="${escaped}" /> ${escaped}${productionNote}</label>`;
40
- })
146
+ function renderControls(input) {
147
+ const organizations = input.choices.map(renderOrganizationChoice).join('');
148
+ const panels = input.choices.map(renderEnvironmentPanel).join('');
149
+ const first = input.choices[0];
150
+ const initialEnvironment = first?.environments.includes('dev') ? 'dev' : first?.environments[0];
151
+ const initialSummary = first !== undefined && initialEnvironment !== undefined
152
+ ? `${input.clientName} can ${capabilitySummary(first.capabilities)} in ${first.displayName ?? first.org} for ${initialEnvironment}.`
153
+ : 'Select at least one environment to continue.';
154
+ return `<fieldset class="developer-section">
155
+ <legend class="developer-step"><span class="developer-step-number">1</span>Choose organization</legend>
156
+ <p class="developer-help">Only one organization can be authorized in this connection.</p>
157
+ <div class="developer-org-list">${organizations}</div>
158
+ </fieldset>
159
+ <div>${panels}</div>
160
+ <div class="developer-summary" aria-live="polite">
161
+ <p class="developer-summary-label">Access summary</p>
162
+ <p class="developer-summary-copy" data-selection-summary>${escapeHtml(initialSummary)}</p>
163
+ <p class="developer-selection-error" data-selection-error hidden>Select at least one environment to continue.</p>
164
+ </div>
165
+ <div class="ns-row">
166
+ <button type="submit" name="decision" value="deny" class="btn btn-ghost">Deny</button>
167
+ <span class="btn-glow"><button type="submit" name="decision" value="approve" class="btn btn-primary" data-authorize>Authorize access</button></span>
168
+ </div>`;
169
+ }
170
+ function renderOrganizationChoice(choice, index) {
171
+ const label = choice.displayName ?? choice.org;
172
+ const access = choice.capabilities.includes('deployments:rollback')
173
+ ? 'Owner access'
174
+ : 'Developer access';
175
+ return `<label class="developer-org-choice">
176
+ <input type="radio" name="org" value="${escapeHtml(choice.org)}" data-org-choice="${index}"${index === 0 ? ' checked' : ''} />
177
+ <span class="developer-org-card">
178
+ <span><span class="developer-org-name">${escapeHtml(label)}</span><span class="developer-org-access">${access}</span></span>
179
+ <span class="developer-choice-mark" aria-hidden="true">✓</span>
180
+ </span>
181
+ </label>`;
182
+ }
183
+ function renderEnvironmentPanel(choice, choiceIndex) {
184
+ const environments = orderedEnvironments(choice.environments)
185
+ .map((environment, environmentIndex) => renderEnvironment(environment, choiceIndex, environmentIndex, choiceIndex === 0))
41
186
  .join('');
42
187
  const capabilities = choice.capabilities
43
188
  .map((capability) => `<li>${escapeHtml(CAPABILITY_COPY[capability])}</li>`)
44
189
  .join('');
45
- return `<fieldset>
46
- <legend><label><input type="radio" name="org" value="${org}"${index === 0 ? ' checked' : ''} /> ${label}</label></legend>
47
- <p class="ns-note">Environments</p>
48
- <div>${environments}</div>
49
- <p class="ns-note">Autonomous capabilities</p>
50
- <ul>${capabilities}</ul>
51
- </fieldset>`;
190
+ const label = choice.displayName ?? choice.org;
191
+ return `<section class="developer-section" data-org-panel="${choiceIndex}" data-org-name="${escapeHtml(label)}" data-capability-summary="${escapeHtml(capabilitySummary(choice.capabilities))}"${choiceIndex === 0 ? '' : ' hidden'}>
192
+ <h2 class="developer-step"><span class="developer-step-number">2</span>Choose environments</h2>
193
+ <p class="developer-help">Select every environment this plugin should be able to operate. Development is selected for you.</p>
194
+ <div class="developer-environment-grid">${environments}</div>
195
+ <details class="developer-capabilities">
196
+ <summary>What the plugin can do</summary>
197
+ <ul>${capabilities}</ul>
198
+ </details>
199
+ </section>`;
200
+ }
201
+ function renderEnvironment(environment, choiceIndex, environmentIndex, active) {
202
+ const id = `developer-environment-${choiceIndex}-${environmentIndex}`;
203
+ const selected = active && environment === 'dev';
204
+ const note = environmentNote(environment);
205
+ return `<label class="developer-environment" for="${id}">
206
+ <input id="${id}" type="checkbox" name="environment" value="${escapeHtml(environment)}"${selected ? ' checked' : ''}${active ? '' : ' disabled'} />
207
+ <span class="developer-environment-card">
208
+ <span class="developer-checkbox" aria-hidden="true">✓</span>
209
+ <span><span class="developer-environment-name">${escapeHtml(environment)}</span><span class="developer-environment-note${environment === 'prod' ? ' is-production' : ''}">${note}</span></span>
210
+ </span>
211
+ </label>`;
212
+ }
213
+ function orderedEnvironments(environments) {
214
+ return [...new Set(environments)].sort((left, right) => {
215
+ const leftPriority = ENVIRONMENT_PRIORITY[left] ?? 2;
216
+ const rightPriority = ENVIRONMENT_PRIORITY[right] ?? 2;
217
+ return leftPriority - rightPriority || left.localeCompare(right);
218
+ });
219
+ }
220
+ function environmentNote(environment) {
221
+ if (environment === 'dev')
222
+ return 'Recommended';
223
+ if (environment === 'prod')
224
+ return 'Can affect live users';
225
+ return 'Optional';
226
+ }
227
+ function capabilitySummary(capabilities) {
228
+ const actions = [];
229
+ if (capabilities.includes('cloud:read'))
230
+ actions.push('read cloud state');
231
+ if (capabilities.includes('deployments:write'))
232
+ actions.push('build and deploy apps');
233
+ if (capabilities.includes('deployments:rollback'))
234
+ actions.push('roll back deployments');
235
+ if (actions.length === 0)
236
+ return 'use its assigned capabilities';
237
+ if (actions.length === 1)
238
+ return actions[0] ?? 'use its assigned capabilities';
239
+ return `${actions.slice(0, -1).join(', ')} and ${actions.at(-1)}`;
52
240
  }
53
241
  function escapeHtml(value) {
54
242
  return value
@@ -1 +1 @@
1
- {"version":3,"file":"developer-grant-page.js","sourceRoot":"","sources":["../../src/oauth/developer-grant-page.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAahD,MAAM,eAAe,GAAkD;IACrE,YAAY,EAAE,gEAAgE;IAC9E,mBAAmB,EAAE,oDAAoD;IACzE,sBAAsB,EAAE,uBAAuB;CAChD,CAAC;AAEF,MAAM,UAAU,wBAAwB,CAAC,KAA8B;IACrE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzD,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QACxB,CAAC,CAAC,yEAAyE;QAC3E,CAAC,CAAC,GAAG,OAAO;;;aAGL,CAAC;IACZ,MAAM,WAAW,GAAG,8BAA8B,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC;;kEAEd,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC;kEAC3B,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC;kEAC9B,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC;;kCAE9D,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC;uDACR,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC;QAC3E,QAAQ;YACJ,CAAC;IACX,OAAO,eAAe,CAAC;QACrB,KAAK,EAAE,0CAA0C;QACjD,MAAM,EAAE,kBAAkB;QAC1B,OAAO,EAAE,gDAAgD;QACzD,WAAW;KACZ,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,MAA4B,EAAE,KAAa;IAC/D,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY;SACrC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QACnB,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,cAAc,GAClB,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,+CAA+C,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,OAAO,2DAA2D,OAAO,QAAQ,OAAO,GAAG,cAAc,UAAU,CAAC;IACtH,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY;SACrC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;SAC1E,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO;6DACoD,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK;;aAEhG,YAAY;;YAEb,YAAY;gBACR,CAAC;AACjB,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"developer-grant-page.js","sourceRoot":"","sources":["../../src/oauth/developer-grant-page.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Request, Response } from 'express';
2
+ import type { NoodleOAuthProvider } from './provider.js';
3
+ import type { OAuthStore } from './store.js';
4
+ export declare const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
5
+ /** RFC 8628 endpoints, backed by the existing authorization-code consent path in the browser. */
6
+ export declare class DeviceAuthorizationFlow {
7
+ #private;
8
+ constructor(input: {
9
+ readonly issuer: string;
10
+ readonly store: OAuthStore;
11
+ readonly provider: NoodleOAuthProvider;
12
+ readonly now?: () => number;
13
+ });
14
+ handleAuthorization(req: Request, res: Response): Promise<void>;
15
+ handleVerificationPage(req: Request, res: Response): void;
16
+ handleVerification(req: Request, res: Response): Promise<void>;
17
+ handleCallback(req: Request, res: Response): Promise<void>;
18
+ handleToken(req: Request, res: Response): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=device-flow.d.ts.map