No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

extensionsApi.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getExtension = exports.deleteExtension = exports.unpublishExtension = exports.publishExtensionVersion = exports.undeprecateExtensionVersion = exports.deprecateExtensionVersion = exports.registerPublisherProfile = exports.getPublisherProfile = exports.listExtensionVersions = exports.listExtensions = exports.getExtensionVersion = exports.getSource = exports.createSource = exports.updateInstanceFromRegistry = exports.updateInstance = exports.configureInstance = exports.listInstances = exports.getInstance = exports.deleteInstance = exports.createInstance = void 0;
  4. const yaml = require("js-yaml");
  5. const clc = require("colorette");
  6. const { marked } = require("marked");
  7. const apiv2_1 = require("../apiv2");
  8. const api_1 = require("../api");
  9. const error_1 = require("../error");
  10. const logger_1 = require("../logger");
  11. const operationPoller = require("../operation-poller");
  12. const refs = require("./refs");
  13. const VERSION = "v1beta";
  14. const PAGE_SIZE_MAX = 100;
  15. const apiClient = new apiv2_1.Client({ urlPrefix: api_1.extensionsOrigin, apiVersion: VERSION });
  16. async function createInstanceHelper(projectId, instanceId, config, validateOnly = false) {
  17. const createRes = await apiClient.post(`/projects/${projectId}/instances/`, {
  18. name: `projects/${projectId}/instances/${instanceId}`,
  19. config,
  20. }, {
  21. queryParams: {
  22. validateOnly: validateOnly ? "true" : "false",
  23. },
  24. });
  25. if (validateOnly) {
  26. return createRes.body;
  27. }
  28. const pollRes = await operationPoller.pollOperation({
  29. apiOrigin: api_1.extensionsOrigin,
  30. apiVersion: VERSION,
  31. operationResourceName: createRes.body.name,
  32. masterTimeout: 600000,
  33. });
  34. return pollRes;
  35. }
  36. async function createInstance(args) {
  37. var _a, _b;
  38. const config = {
  39. params: args.params,
  40. allowedEventTypes: args.allowedEventTypes,
  41. eventarcChannel: args.eventarcChannel,
  42. };
  43. if (args.extensionSource && args.extensionVersionRef) {
  44. throw new error_1.FirebaseError("ExtensionSource and ExtensionVersion both provided, but only one should be.");
  45. }
  46. else if (args.extensionSource) {
  47. config.source = { name: (_a = args.extensionSource) === null || _a === void 0 ? void 0 : _a.name };
  48. }
  49. else if (args.extensionVersionRef) {
  50. const ref = refs.parse(args.extensionVersionRef);
  51. config.extensionRef = refs.toExtensionRef(ref);
  52. config.extensionVersion = (_b = ref.version) !== null && _b !== void 0 ? _b : "";
  53. }
  54. else {
  55. throw new error_1.FirebaseError("No ExtensionVersion or ExtensionSource provided but one is required.");
  56. }
  57. if (args.allowedEventTypes) {
  58. config.allowedEventTypes = args.allowedEventTypes;
  59. }
  60. if (args.eventarcChannel) {
  61. config.eventarcChannel = args.eventarcChannel;
  62. }
  63. return createInstanceHelper(args.projectId, args.instanceId, config, args.validateOnly);
  64. }
  65. exports.createInstance = createInstance;
  66. async function deleteInstance(projectId, instanceId) {
  67. const deleteRes = await apiClient.delete(`/projects/${projectId}/instances/${instanceId}`);
  68. const pollRes = await operationPoller.pollOperation({
  69. apiOrigin: api_1.extensionsOrigin,
  70. apiVersion: VERSION,
  71. operationResourceName: deleteRes.body.name,
  72. masterTimeout: 600000,
  73. });
  74. return pollRes;
  75. }
  76. exports.deleteInstance = deleteInstance;
  77. async function getInstance(projectId, instanceId) {
  78. try {
  79. const res = await apiClient.get(`/projects/${projectId}/instances/${instanceId}`);
  80. return res.body;
  81. }
  82. catch (err) {
  83. if (err.status === 404) {
  84. throw new error_1.FirebaseError(`Extension instance '${clc.bold(instanceId)}' not found in project '${clc.bold(projectId)}'.`, { status: 404 });
  85. }
  86. throw err;
  87. }
  88. }
  89. exports.getInstance = getInstance;
  90. async function listInstances(projectId) {
  91. const instances = [];
  92. const getNextPage = async (pageToken = "") => {
  93. const res = await apiClient.get(`/projects/${projectId}/instances`, {
  94. queryParams: {
  95. pageSize: PAGE_SIZE_MAX,
  96. pageToken,
  97. },
  98. });
  99. if (Array.isArray(res.body.instances)) {
  100. instances.push(...res.body.instances);
  101. }
  102. if (res.body.nextPageToken) {
  103. await getNextPage(res.body.nextPageToken);
  104. }
  105. };
  106. await getNextPage();
  107. return instances;
  108. }
  109. exports.listInstances = listInstances;
  110. async function configureInstance(args) {
  111. var _a;
  112. const reqBody = {
  113. projectId: args.projectId,
  114. instanceId: args.instanceId,
  115. updateMask: "config.params",
  116. validateOnly: (_a = args.validateOnly) !== null && _a !== void 0 ? _a : false,
  117. data: {
  118. config: {
  119. params: args.params,
  120. },
  121. },
  122. };
  123. if (args.canEmitEvents) {
  124. if (args.allowedEventTypes === undefined || args.eventarcChannel === undefined) {
  125. throw new error_1.FirebaseError(`This instance is configured to emit events, but either allowed event types or eventarc channel is undefined.`);
  126. }
  127. reqBody.data.config.allowedEventTypes = args.allowedEventTypes;
  128. reqBody.data.config.eventarcChannel = args.eventarcChannel;
  129. }
  130. reqBody.updateMask += ",config.allowed_event_types,config.eventarc_channel";
  131. return patchInstance(reqBody);
  132. }
  133. exports.configureInstance = configureInstance;
  134. async function updateInstance(args) {
  135. var _a;
  136. const body = {
  137. config: {
  138. source: { name: args.extensionSource.name },
  139. },
  140. };
  141. let updateMask = "config.source.name";
  142. if (args.params) {
  143. body.config.params = args.params;
  144. updateMask += ",config.params";
  145. }
  146. if (args.canEmitEvents) {
  147. if (args.allowedEventTypes === undefined || args.eventarcChannel === undefined) {
  148. throw new error_1.FirebaseError(`This instance is configured to emit events, but either allowed event types or eventarc channel is undefined.`);
  149. }
  150. body.config.allowedEventTypes = args.allowedEventTypes;
  151. body.config.eventarcChannel = args.eventarcChannel;
  152. }
  153. updateMask += ",config.allowed_event_types,config.eventarc_channel";
  154. return patchInstance({
  155. projectId: args.projectId,
  156. instanceId: args.instanceId,
  157. updateMask,
  158. validateOnly: (_a = args.validateOnly) !== null && _a !== void 0 ? _a : false,
  159. data: body,
  160. });
  161. }
  162. exports.updateInstance = updateInstance;
  163. async function updateInstanceFromRegistry(args) {
  164. var _a;
  165. const ref = refs.parse(args.extRef);
  166. const body = {
  167. config: {
  168. extensionRef: refs.toExtensionRef(ref),
  169. extensionVersion: ref.version,
  170. },
  171. };
  172. let updateMask = "config.extension_ref,config.extension_version";
  173. if (args.params) {
  174. body.config.params = args.params;
  175. updateMask += ",config.params";
  176. }
  177. if (args.canEmitEvents) {
  178. if (args.allowedEventTypes === undefined || args.eventarcChannel === undefined) {
  179. throw new error_1.FirebaseError(`This instance is configured to emit events, but either allowed event types or eventarc channel is undefined.`);
  180. }
  181. body.config.allowedEventTypes = args.allowedEventTypes;
  182. body.config.eventarcChannel = args.eventarcChannel;
  183. }
  184. updateMask += ",config.allowed_event_types,config.eventarc_channel";
  185. return patchInstance({
  186. projectId: args.projectId,
  187. instanceId: args.instanceId,
  188. updateMask,
  189. validateOnly: (_a = args.validateOnly) !== null && _a !== void 0 ? _a : false,
  190. data: body,
  191. });
  192. }
  193. exports.updateInstanceFromRegistry = updateInstanceFromRegistry;
  194. async function patchInstance(args) {
  195. const updateRes = await apiClient.patch(`/projects/${args.projectId}/instances/${args.instanceId}`, args.data, {
  196. queryParams: {
  197. updateMask: args.updateMask,
  198. validateOnly: args.validateOnly ? "true" : "false",
  199. },
  200. });
  201. if (args.validateOnly) {
  202. return updateRes;
  203. }
  204. const pollRes = await operationPoller.pollOperation({
  205. apiOrigin: api_1.extensionsOrigin,
  206. apiVersion: VERSION,
  207. operationResourceName: updateRes.body.name,
  208. masterTimeout: 600000,
  209. });
  210. return pollRes;
  211. }
  212. function populateResourceProperties(spec) {
  213. if (spec) {
  214. spec.resources.forEach((r) => {
  215. try {
  216. if (r.propertiesYaml) {
  217. r.properties = yaml.safeLoad(r.propertiesYaml);
  218. }
  219. }
  220. catch (err) {
  221. logger_1.logger.debug(`[ext] failed to parse resource properties yaml: ${err}`);
  222. }
  223. });
  224. }
  225. }
  226. async function createSource(projectId, packageUri, extensionRoot) {
  227. const createRes = await apiClient.post(`/projects/${projectId}/sources/`, {
  228. packageUri,
  229. extensionRoot,
  230. });
  231. const pollRes = await operationPoller.pollOperation({
  232. apiOrigin: api_1.extensionsOrigin,
  233. apiVersion: VERSION,
  234. operationResourceName: createRes.body.name,
  235. masterTimeout: 600000,
  236. });
  237. if (pollRes.spec) {
  238. populateResourceProperties(pollRes.spec);
  239. }
  240. return pollRes;
  241. }
  242. exports.createSource = createSource;
  243. async function getSource(sourceName) {
  244. const res = await apiClient.get(`/${sourceName}`);
  245. if (res.body.spec) {
  246. populateResourceProperties(res.body.spec);
  247. }
  248. return res.body;
  249. }
  250. exports.getSource = getSource;
  251. async function getExtensionVersion(extensionVersionRef) {
  252. const ref = refs.parse(extensionVersionRef);
  253. if (!ref.version) {
  254. throw new error_1.FirebaseError(`ExtensionVersion ref "${extensionVersionRef}" must supply a version.`);
  255. }
  256. try {
  257. const res = await apiClient.get(`/${refs.toExtensionVersionName(ref)}`);
  258. if (res.body.spec) {
  259. populateResourceProperties(res.body.spec);
  260. }
  261. return res.body;
  262. }
  263. catch (err) {
  264. if (err.status === 404) {
  265. throw refNotFoundError(ref);
  266. }
  267. else if (err instanceof error_1.FirebaseError) {
  268. throw err;
  269. }
  270. throw new error_1.FirebaseError(`Failed to query the extension version '${clc.bold(extensionVersionRef)}': ${err}`);
  271. }
  272. }
  273. exports.getExtensionVersion = getExtensionVersion;
  274. async function listExtensions(publisherId) {
  275. const extensions = [];
  276. const getNextPage = async (pageToken = "") => {
  277. const res = await apiClient.get(`/publishers/${publisherId}/extensions`, {
  278. queryParams: {
  279. pageSize: PAGE_SIZE_MAX,
  280. pageToken,
  281. },
  282. });
  283. if (Array.isArray(res.body.extensions)) {
  284. extensions.push(...res.body.extensions);
  285. }
  286. if (res.body.nextPageToken) {
  287. await getNextPage(res.body.nextPageToken);
  288. }
  289. };
  290. await getNextPage();
  291. return extensions;
  292. }
  293. exports.listExtensions = listExtensions;
  294. async function listExtensionVersions(ref, filter = "", showPrereleases = false) {
  295. const { publisherId, extensionId } = refs.parse(ref);
  296. const extensionVersions = [];
  297. const getNextPage = async (pageToken = "") => {
  298. const res = await apiClient.get(`/publishers/${publisherId}/extensions/${extensionId}/versions`, {
  299. queryParams: {
  300. filter,
  301. showPrereleases: String(showPrereleases),
  302. pageSize: PAGE_SIZE_MAX,
  303. pageToken,
  304. },
  305. });
  306. if (Array.isArray(res.body.extensionVersions)) {
  307. extensionVersions.push(...res.body.extensionVersions);
  308. }
  309. if (res.body.nextPageToken) {
  310. await getNextPage(res.body.nextPageToken);
  311. }
  312. };
  313. await getNextPage();
  314. return extensionVersions;
  315. }
  316. exports.listExtensionVersions = listExtensionVersions;
  317. async function getPublisherProfile(projectId, publisherId) {
  318. const res = await apiClient.get(`/projects/${projectId}/publisherProfile`, {
  319. queryParams: publisherId === undefined
  320. ? undefined
  321. : {
  322. publisherId,
  323. },
  324. });
  325. return res.body;
  326. }
  327. exports.getPublisherProfile = getPublisherProfile;
  328. async function registerPublisherProfile(projectId, publisherId) {
  329. const res = await apiClient.post(`/projects/${projectId}/publisherProfile:register`, {
  330. publisherId,
  331. });
  332. return res.body;
  333. }
  334. exports.registerPublisherProfile = registerPublisherProfile;
  335. async function deprecateExtensionVersion(extensionRef, deprecationMessage) {
  336. const ref = refs.parse(extensionRef);
  337. try {
  338. const res = await apiClient.post(`/${refs.toExtensionVersionName(ref)}:deprecate`, {
  339. deprecationMessage,
  340. });
  341. return res.body;
  342. }
  343. catch (err) {
  344. if (err.status === 403) {
  345. throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to deprecate this extension version.` + err, { status: err.status });
  346. }
  347. else if (err.status === 404) {
  348. throw new error_1.FirebaseError(`Extension version ${clc.bold(extensionRef)} was not found.`);
  349. }
  350. else if (err instanceof error_1.FirebaseError) {
  351. throw err;
  352. }
  353. throw new error_1.FirebaseError(`Error occurred deprecating extension version '${extensionRef}': ${err}`, {
  354. status: err.status,
  355. });
  356. }
  357. }
  358. exports.deprecateExtensionVersion = deprecateExtensionVersion;
  359. async function undeprecateExtensionVersion(extensionRef) {
  360. const ref = refs.parse(extensionRef);
  361. try {
  362. const res = await apiClient.post(`/${refs.toExtensionVersionName(ref)}:undeprecate`);
  363. return res.body;
  364. }
  365. catch (err) {
  366. if (err.status === 403) {
  367. throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to undeprecate this extension version.`, { status: err.status });
  368. }
  369. else if (err.status === 404) {
  370. throw new error_1.FirebaseError(`Extension version ${clc.bold(extensionRef)} was not found.`);
  371. }
  372. else if (err instanceof error_1.FirebaseError) {
  373. throw err;
  374. }
  375. throw new error_1.FirebaseError(`Error occurred undeprecating extension version '${extensionRef}': ${err}`, {
  376. status: err.status,
  377. });
  378. }
  379. }
  380. exports.undeprecateExtensionVersion = undeprecateExtensionVersion;
  381. async function publishExtensionVersion(extensionVersionRef, packageUri, extensionRoot) {
  382. const ref = refs.parse(extensionVersionRef);
  383. if (!ref.version) {
  384. throw new error_1.FirebaseError(`ExtensionVersion ref "${extensionVersionRef}" must supply a version.`);
  385. }
  386. const publishRes = await apiClient.post(`/${refs.toExtensionName(ref)}/versions:publish`, {
  387. versionId: ref.version,
  388. packageUri,
  389. extensionRoot: extensionRoot !== null && extensionRoot !== void 0 ? extensionRoot : "/",
  390. });
  391. const pollRes = await operationPoller.pollOperation({
  392. apiOrigin: api_1.extensionsOrigin,
  393. apiVersion: VERSION,
  394. operationResourceName: publishRes.body.name,
  395. masterTimeout: 600000,
  396. });
  397. return pollRes;
  398. }
  399. exports.publishExtensionVersion = publishExtensionVersion;
  400. async function unpublishExtension(extensionRef) {
  401. const ref = refs.parse(extensionRef);
  402. if (ref.version) {
  403. throw new error_1.FirebaseError(`Extension reference "${extensionRef}" must not contain a version.`);
  404. }
  405. try {
  406. await apiClient.post(`/${refs.toExtensionName(ref)}:unpublish`);
  407. }
  408. catch (err) {
  409. if (err.status === 403) {
  410. throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to unpublish this extension.`, { status: err.status });
  411. }
  412. else if (err instanceof error_1.FirebaseError) {
  413. throw err;
  414. }
  415. throw new error_1.FirebaseError(`Error occurred unpublishing extension '${extensionRef}': ${err}`, {
  416. status: err.status,
  417. });
  418. }
  419. }
  420. exports.unpublishExtension = unpublishExtension;
  421. async function deleteExtension(extensionRef) {
  422. const ref = refs.parse(extensionRef);
  423. if (ref.version) {
  424. throw new error_1.FirebaseError(`Extension reference "${extensionRef}" must not contain a version.`);
  425. }
  426. try {
  427. await apiClient.delete(`/${refs.toExtensionName(ref)}`);
  428. }
  429. catch (err) {
  430. if (err.status === 403) {
  431. throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to delete this extension.`, { status: err.status });
  432. }
  433. else if (err.status === 404) {
  434. throw new error_1.FirebaseError(`Extension ${clc.bold(extensionRef)} was not found.`);
  435. }
  436. else if (err instanceof error_1.FirebaseError) {
  437. throw err;
  438. }
  439. throw new error_1.FirebaseError(`Error occurred delete extension '${extensionRef}': ${err}`, {
  440. status: err.status,
  441. });
  442. }
  443. }
  444. exports.deleteExtension = deleteExtension;
  445. async function getExtension(extensionRef) {
  446. const ref = refs.parse(extensionRef);
  447. try {
  448. const res = await apiClient.get(`/${refs.toExtensionName(ref)}`);
  449. return res.body;
  450. }
  451. catch (err) {
  452. if (err.status === 404) {
  453. throw refNotFoundError(ref);
  454. }
  455. else if (err instanceof error_1.FirebaseError) {
  456. throw err;
  457. }
  458. throw new error_1.FirebaseError(`Failed to query the extension '${clc.bold(extensionRef)}': ${err}`, {
  459. status: err.status,
  460. });
  461. }
  462. }
  463. exports.getExtension = getExtension;
  464. function refNotFoundError(ref) {
  465. return new error_1.FirebaseError(`The extension reference '${clc.bold(ref.version ? refs.toExtensionVersionRef(ref) : refs.toExtensionRef(ref))}' doesn't exist. This could happen for two reasons:\n` +
  466. ` -The publisher ID '${clc.bold(ref.publisherId)}' doesn't exist or could be misspelled\n` +
  467. ` -The name of the ${ref.version ? "extension version" : "extension"} '${clc.bold(ref.version ? `${ref.extensionId}@${ref.version}` : ref.extensionId)}' doesn't exist or could be misspelled\n\n` +
  468. `Please correct the extension reference and try again. If you meant to install an extension from a local source, please provide a relative path prefixed with '${clc.bold("./")}', '${clc.bold("../")}', or '${clc.bold("~/")}'. Learn more about local extension installation at ${marked("[https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install](https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install).")}`, { status: 404 });
  469. }