@forge/bridge
5.15.2-next.0-experimental-5b726e65.16.0-next.1
~
Modified (49 files)
Index: package/out/view/close.js
===================================================================
--- package/out/view/close.js
+++ package/out/view/close.js
@@ -6,8 +6,9 @@
const callBridge = (0, bridge_1.getCallBridge)();
const close = async (payload) => {
try {
const success = await callBridge('close', payload);
+ // TODO: Modify @atlassian/forge-ui to throw if close fails instead of returning boolean DEVO-680
if (success === false) {
throw new errors_1.BridgeAPIError("this resource's view is not closable.");
}
} Index: package/out/object-store/deleteObjects.js
===================================================================
--- package/out/object-store/deleteObjects.js
+++ package/out/object-store/deleteObjects.js
@@ -5,8 +5,16 @@
const errors_1 = require("../errors");
const utils_1 = require("./utils");
const bridge_1 = require("../bridge");
const callBridge = (0, bridge_1.getCallBridge)();
+/**
+ * Delete multiple objects
+ *
+ * @param functionKey - Configuration object containing the backend function key to delete objects
+ * @param keys - Array of object keys to delete
+ * @returns Promise<void>
+ * @throws {BridgeAPIError} When deleting fails
+ */
const deleteObjects = async ({ functionKey, keys }) => {
await (0, utils_1.checkRestrictedEnvironment)();
void callBridge('trackObjectStoreAction', { action: 'delete' });
if (!functionKey || functionKey.length === 0) { Index: package/out/object-store/download.js
===================================================================
--- package/out/object-store/download.js
+++ package/out/object-store/download.js
@@ -5,8 +5,16 @@
const errors_1 = require("../errors");
const utils_1 = require("./utils");
const bridge_1 = require("../bridge");
const callBridge = (0, bridge_1.getCallBridge)();
+/**
+ * Download multiple objects from pre-signed URLs
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate download URLs
+ * @param keys - Array of object keys to download
+ * @returns Promise resolving to DownloadResult[]
+ * @throws {BridgeAPIError} When filtering fails or download encounters an error
+ */
const download = async ({ functionKey, keys }) => {
await (0, utils_1.checkRestrictedEnvironment)();
void callBridge('trackObjectStoreAction', { action: 'download' });
if (!functionKey || functionKey.length === 0) { Index: package/out/view/emitReadyEvent.js
===================================================================
--- package/out/view/emitReadyEvent.js
+++ package/out/view/emitReadyEvent.js
@@ -6,15 +6,20 @@
const bridge_1 = require("../bridge");
const callBridge = (0, bridge_1.getCallBridge)();
const EXTENSION_READY = 'EXTENSION_READY';
const emitReadyEvent = async () => {
+ // Confluence export relies on events instead of `callBridge`
const context = await view_1.view.getContext();
+ // dispatches event 'forge.bridge.EXTENSION_READY' on product window
await events_1.events.emit(EXTENSION_READY, {
localId: context.localId
});
+ // TODO: Consider using the above event for static macros as well for to avoid two calls
+ // `callBridge` is used for static macros in XEP to signal that the forgeDoc is ready to be snapshotted
try {
await callBridge('emitReadyEvent');
}
catch {
+ // Silently ignore the error as this app may be calling this method in Confluence view mode where the method is not supported.
}
};
exports.emitReadyEvent = emitReadyEvent; Index: package/out/featureFlags/evaluator.js
===================================================================
--- package/out/featureFlags/evaluator.js
+++ package/out/featureFlags/evaluator.js
@@ -6,48 +6,57 @@
this.results = results;
}
checkFlag(flagName, defaultValue) {
if (!this.results || !this.results.feature_flags) {
+ // fallback to default value
return defaultValue;
}
const featureFlags = this.results.feature_flags;
let hashedValue = '';
try {
hashedValue = this.getHashedValue(flagName);
}
catch (err) {
+ // eslint-disable-next-line no-console
console.error('Unexpected error occurred while evaluating flag ', err);
+ // If hashing fails for any reason, do not throw; safely return default
return defaultValue;
}
if (!hashedValue) {
return defaultValue;
}
const evaluatedFlag = featureFlags[hashedValue];
if (evaluatedFlag) {
+ // if flag being checked is disabled
if (evaluatedFlag.disabled) {
return false;
}
return evaluatedFlag.value;
}
+ // fallback to default value
return defaultValue;
}
shutDown() {
this.results = undefined;
}
+ // To be Updated with proper hashing function
getHashedValue(flagName) {
+ // Defensive: ensure stable, non-throwing behavior for unexpected inputs
if (typeof flagName !== 'string') {
return '';
}
const input = flagName.trim();
if (input.length === 0) {
return '';
}
+ // djb2 hashing (unsigned 32-bit), matches server-side encoding
let hash = 5381;
for (let i = 0; i < input.length; i += 1) {
const charCode = input.charCodeAt(i);
- hash = (hash << 5) + hash + charCode;
- hash |= 0;
+ hash = (hash << 5) + hash + charCode; // hash * 33 + c
+ hash |= 0; // force 32-bit signed int
}
+ // Convert to unsigned 32-bit and return as a decimal string
return (hash >>> 0).toString();
}
}
exports.Evaluator = Evaluator; Index: package/out/featureFlags/featureFlags.js
===================================================================
--- package/out/featureFlags/featureFlags.js
+++ package/out/featureFlags/featureFlags.js
@@ -9,8 +9,11 @@
constructor() {
this.initialized = false;
this.eventProps = {};
}
+ /**
+ * Initialize the feature flags client
+ */
async initialize(user, config = { environment: 'development' }) {
if (this.isInitialized()) {
return;
}
@@ -21,16 +24,22 @@
const result = await (0, initFeatureFlags_1.initFeatureFlags)({ user, config });
this.initialized = true;
this.evaluator = new evaluator_1.Evaluator(result);
}
+ /**
+ * Check if a feature flag is enabled for the user
+ */
checkFlag(flagName, defaultValue = false) {
if (!this.isInitialized() || !this.evaluator) {
this.sendCheckFlagEvent(flagName, false);
throw new Error('FeatureFlags not initialized. Call initialize() first.');
}
this.sendCheckFlagEvent(flagName, true);
return this.evaluator.checkFlag(flagName, defaultValue);
}
+ /**
+ * Shutdown the feature flags client
+ */
shutdown() {
if (!this.isInitialized()) {
return;
} Index: package/out/fetch/fetch.js
===================================================================
--- package/out/fetch/fetch.js
+++ package/out/fetch/fetch.js
@@ -4,13 +4,20 @@
const blobParser_1 = require("../utils/blobParser");
const parseFormData = async (form, matchFilePrefix = false) => {
const parsed = {};
for (const [key, value] of form.entries()) {
+ // Jira and Confluence REST APIs requires that the field containing
+ // the file MUST be named exactly 'file'
const isFileKey = matchFilePrefix ? key.startsWith('file') : key === 'file';
if (isFileKey) {
const fileName = value.name;
const fileType = value.type;
+ // we parse the file as a base64 string so it
+ // can be properly transfered over the bridge.
+ // we'll parse it back to Blob in the host product
parsed[key] = await (0, blobParser_1.blobToBase64)(value);
+ // we also need to pass the file name and type,
+ // as those will be lost in the base64 conversion
parsed[`__${key}Name`] = fileName;
parsed[`__${key}Type`] = fileType;
}
else {
@@ -23,9 +30,11 @@
if (!init) {
return init;
}
if ('signal' in init) {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
const { signal: _signal, ...rest } = init;
+ // eslint-disable-next-line no-console
console.error('Signal is not supported in @forge/bridge and was removed from fetch options. Please use the fetch method from @forge/api for signal support.');
return rest;
}
return init;
@@ -33,8 +42,10 @@
const parseRequest = async (fetchType, init) => {
const isFormData = (init === null || init === void 0 ? void 0 : init.body) instanceof FormData ? true : false;
const requestBody = isFormData ? await parseFormData(init === null || init === void 0 ? void 0 : init.body, fetchType === 'remote') : init === null || init === void 0 ? void 0 : init.body;
const req = new Request('', { body: requestBody, method: init === null || init === void 0 ? void 0 : init.method, headers: init === null || init === void 0 ? void 0 : init.headers });
+ // If `init.body` is a `FormData`, a `content-type` header required for the body to be parsed by the
+ // API receiving this request will be generated in req.headers.
const headers = Object.fromEntries(req.headers.entries());
const body = req.method !== 'GET' ? await req.text() : null;
return {
body,
@@ -63,8 +74,9 @@
const productFetchApi = (callBridge) => {
const fetch = async (product, restPath, init) => {
const validatedInit = validateFetchOptions(init);
const { body: requestBody, headers: requestHeaders, isMultipartFormData } = await parseRequest('product', validatedInit);
+ // https://ecosystem.atlassian.net/browse/BUILD-1118 Skip xsrf check for oauth request
if (!requestHeaders.has('X-Atlassian-Token')) {
requestHeaders.set('X-Atlassian-Token', 'no-check');
}
const fetchPayload = { Index: package/out/view/getContext.js
===================================================================
--- package/out/view/getContext.js
+++ package/out/view/getContext.js
@@ -8,8 +8,10 @@
var _a;
const context = await callBridge('getContext');
const locale = context === null || context === void 0 ? void 0 : context.locale;
if (locale) {
+ // still fallback to the locale if it is not supported,
+ // this is to avoid breaking changes
context.locale = (_a = (0, i18n_1.ensureLocale)(locale)) !== null && _a !== void 0 ? _a : locale;
}
return context;
}; Index: package/out/object-store/getMetadata.js
===================================================================
--- package/out/object-store/getMetadata.js
+++ package/out/object-store/getMetadata.js
@@ -5,8 +5,16 @@
const errors_1 = require("../errors");
const utils_1 = require("./utils");
const bridge_1 = require("../bridge");
const callBridge = (0, bridge_1.getCallBridge)();
+/**
+ * Get metadata for multiple objectIds
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate object metadata
+ * @param keys - Array of object keys to get metadata for
+ * @returns Promise resolving to GetMetadataResult[]
+ * @throws {BridgeAPIError} When filtering fails or download encounters an error
+ */
const getMetadata = async ({ functionKey, keys }) => {
await (0, utils_1.checkRestrictedEnvironment)();
void callBridge('trackObjectStoreAction', { action: 'getMetadata' });
if (!functionKey || functionKey.length === 0) { Index: package/out/i18n/index.js
===================================================================
--- package/out/i18n/index.js
+++ package/out/i18n/index.js
@@ -35,8 +35,15 @@
}
return await translationsGetter.getTranslations(targetLocale, options);
};
exports.getTranslations = getTranslations;
+/**
+ * Creates a translation function (i.e. `t`) for the given locale.
+ * If no locale is provided, the locale from the current view context is used.
+ *
+ * @param locale The locale to create the translation function for.
+ * @returns The translation function.
+ */
const createTranslationFunction = async (locale = null) => {
let targetLocale = locale;
if (!targetLocale) {
const context = await view_1.view.getContext(); Index: package/out/invoke/invoke.js
===================================================================
--- package/out/invoke/invoke.js
+++ package/out/invoke/invoke.js
@@ -18,9 +18,21 @@
}
validatePayload(payload);
return callBridge('invoke', { functionKey, payload });
};
-exports.invoke = (0, utils_1.withRateLimiter)(_invoke, 500, 1000 * 25, 'Resolver calls are rate limited at 500req/25s');
+const limitedInvoke = (0, utils_1.withRateLimiter)(_invoke, 500, 1000 * 25, 'Resolver calls are rate limited at 500req/25s');
+/**
+ * Calls a backend resolver function by key.
+ */
+function invoke(functionKey, payload) {
+ return limitedInvoke(functionKey, payload);
+}
+exports.invoke = invoke;
+/**
+ * Specialises the invoke function to a given Definitions type.
+ *
+ * @returns An invoke function that can be used to call backend functions.
+ */
function makeInvoke() {
- return exports.invoke;
+ return invoke;
}
exports.makeInvoke = makeInvoke; Index: package/out/rovo/isEnabled.js
===================================================================
--- package/out/rovo/isEnabled.js
+++ package/out/rovo/isEnabled.js
@@ -2,8 +2,13 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.isEnabled = void 0;
const bridge_1 = require("../bridge");
const callBridge = (0, bridge_1.getCallBridge)();
+/**
+ * Checks if Rovo is enabled for the current tenant.
+ *
+ * @returns boolean
+ */
const isEnabled = () => {
return callBridge('isRovoEnabled');
};
exports.isEnabled = isEnabled; Index: package/out/modal/modal.js
===================================================================
--- package/out/modal/modal.js
+++ package/out/modal/modal.js
@@ -3,8 +3,9 @@
exports.Modal = void 0;
const bridge_1 = require("../bridge");
const errors_1 = require("../errors");
const callBridge = (0, bridge_1.getCallBridge)();
+// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = () => { };
class Modal {
constructor(opts) {
var _a, _b; Index: package/out/rovo/open.js
===================================================================
--- package/out/rovo/open.js
+++ package/out/rovo/open.js
@@ -22,8 +22,17 @@
default:
return { prompt: openRovoPayload.prompt };
}
};
+/**
+ * Opens Rovo chat from the given Rovo agent name.
+ *
+ * @param {OpenRovoPayload} [openRovoPayload] - Payload to open chat.
+ * Can be one of:
+ * - ForgeAgentPayload: { agentName: string, agentKey: string, prompt?: string }
+ * - AtlassianAgentPayload: { agentName: string, prompt?: string }
+ * - DefaultAgentPayload: { prompt?: string }
+ */
const open = async (openRovoPayload) => {
if (openRovoPayload.type === 'forge') {
if (openRovoPayload.agentName.length > MAX_AGENT_LENGTH) {
throw new Error('rovo agent name too long'); Index: package/out/view/open.js
===================================================================
--- package/out/view/open.js
+++ package/out/view/open.js
@@ -6,8 +6,9 @@
const callBridge = (0, bridge_1.getCallBridge)();
const open = async () => {
try {
const success = await callBridge('open');
+ // TODO: Modify @atlassian/forge-ui to throw if close fails instead of returning boolean DEVO-680
if (success === false) {
throw new errors_1.BridgeAPIError("this resource's view is not openable.");
}
} Index: package/out/permissions/permissionsUtil.js
===================================================================
--- package/out/permissions/permissionsUtil.js
+++ package/out/permissions/permissionsUtil.js
@@ -2,8 +2,12 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkPermissions = exports.createPermissionUtils = void 0;
const egress_1 = require("@forge/egress");
const view_1 = require("../view");
+/**
+ * Helper function to extract URL string from external URL permissions.
+ * Matches the implementation in @forge/api for consistency.
+ */
function extractUrlString(url) {
if (typeof url === 'string') {
return url;
}
@@ -11,10 +15,21 @@
return url.address;
}
return url.remote || '';
}
+/**
+ * Resource types that can be loaded externally
+ */
const RESOURCE_TYPES = ['fonts', 'styles', 'frames', 'images', 'media', 'scripts'];
+/**
+ * Fetch types for external requests
+ */
const FETCH_TYPES = ['backend', 'client'];
+/**
+ * Create permission utilities from runtime permissions
+ * @param runtimePermissions - The runtime permissions from context
+ * @returns Permission utilities or null if permissions are not available
+ */
function createPermissionUtils(runtimePermissions) {
if (!runtimePermissions) {
return null;
}
@@ -26,23 +41,29 @@
var _a;
const fetchUrls = (_a = external.fetch) === null || _a === void 0 ? void 0 : _a[type];
if (!(fetchUrls === null || fetchUrls === void 0 ? void 0 : fetchUrls.length))
return false;
+ // Extract URLs and create egress filter
const allowList = fetchUrls.map(extractUrlString).filter((u) => u.length > 0);
if (allowList.length === 0)
return false;
const egressFilter = new egress_1.EgressFilteringService(allowList);
+ // Backend: hostname-only matching, Client: CSP validation (includes paths)
+ // Type assertion needed because node_modules may have outdated types
const egressFilterWithCSP = egressFilter;
return type === 'client' ? egressFilterWithCSP.isValidUrlCSP(url) : egressFilter.isValidUrl(url);
},
canLoadResource: (type, url) => {
const resourceUrls = external[type];
if (!(resourceUrls === null || resourceUrls === void 0 ? void 0 : resourceUrls.length))
return false;
+ // Extract URLs and create egress filter
const allowList = resourceUrls.map(extractUrlString).filter((u) => u.length > 0);
if (allowList.length === 0)
return false;
const egressFilter = new egress_1.EgressFilteringService(allowList);
+ // All resources use CSP validation (checks protocol + hostname + paths)
+ // Type assertion needed because node_modules may have outdated types
const egressFilterWithCSP = egressFilter;
return egressFilterWithCSP.isValidUrlCSP(url);
},
getScopes: () => scopeArray,
@@ -50,15 +71,21 @@
hasAnyPermissions: () => scopeArray.length > 0 || Object.keys(external).length > 0
};
}
exports.createPermissionUtils = createPermissionUtils;
+/**
+ * Check if required scopes are granted
+ */
function checkScopes(requiredScopes, permissionUtils) {
if (!(requiredScopes === null || requiredScopes === void 0 ? void 0 : requiredScopes.length)) {
return undefined;
}
const missingScopes = requiredScopes.filter((scope) => !permissionUtils.hasScope(scope));
return missingScopes.length > 0 ? missingScopes : undefined;
}
+/**
+ * Check if required fetch permissions are granted
+ */
function checkFetchPermissions(requiredFetch, permissionUtils) {
if (!(requiredFetch === null || requiredFetch === void 0 ? void 0 : requiredFetch.fetch)) {
return undefined;
}
@@ -74,8 +101,11 @@
}
});
return Object.keys(missingFetch).length > 0 ? missingFetch : undefined;
}
+/**
+ * Check if required resource permissions are granted
+ */
function checkResourcePermissions(requiredExternal, permissionUtils) {
const missingResources = {};
RESOURCE_TYPES.forEach((type) => {
const requiredUrls = requiredExternal === null || requiredExternal === void 0 ? void 0 : requiredExternal[type];
@@ -87,8 +117,11 @@
}
});
return Object.keys(missingResources).length > 0 ? missingResources : undefined;
}
+/**
+ * Check if required external permissions are granted
+ */
function checkExternalPermissions(requiredExternal, permissionUtils) {
if (!requiredExternal) {
return undefined;
}
@@ -105,20 +138,26 @@
Object.assign(missingExternal, missingResources);
}
return missingExternal;
}
+// Throws if a field that should be a plain object but is something else.
+// Only used for external and external.fetch, which are guarded above.
function validateObjectField(value, fieldPath) {
if (value !== undefined) {
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
throw new TypeError(`${fieldPath} should be an object, not ${Array.isArray(value) ? 'an array' : `a ${typeof value}`}`);
}
}
}
+// Throws if a field that should be an array but is something else.
function validateArrayField(value, fieldPath) {
if (value !== undefined && !Array.isArray(value)) {
throw new TypeError(`${fieldPath} should be an array, not a ${typeof value}`);
}
}
+/**
+ * Validates that fields in requiredPermissions have the correct types.
+ */
function validatePermissionShape(requiredPermissions) {
validateArrayField(requiredPermissions.scopes, 'scopes');
const external = requiredPermissions.external;
if (external === undefined)
@@ -133,38 +172,51 @@
for (const type of RESOURCE_TYPES) {
validateArrayField(external[type], `external.${type}`);
}
}
+/**
+ * Check if required permissions are granted
+ * @param requiredPermissions - The permissions required to check
+ * @param runtimePermissions - The runtime permissions from context (optional, will be fetched from view.getContext() if not provided)
+ * @returns Promise resolving to permission check result with granted status and missing permissions
+ */
async function checkPermissions(requiredPermissions, runtimePermissions) {
var _a;
+ // Early return for falsy required permissions
if (!requiredPermissions) {
return { granted: false, missing: null };
}
validatePermissionShape(requiredPermissions);
+ // Early return for empty permissions (no requirements = all granted)
if (!((_a = requiredPermissions.scopes) === null || _a === void 0 ? void 0 : _a.length) && !requiredPermissions.external) {
return { granted: true, missing: null };
}
+ // If runtimePermissions is not provided, fetch it from context
let permissionsToCheck = runtimePermissions;
if (!permissionsToCheck) {
const context = await view_1.view.getContext();
permissionsToCheck = context.permissions;
}
const permissionUtils = createPermissionUtils(permissionsToCheck);
if (!permissionUtils) {
+ // If permissions are not available, return not granted
return { granted: false, missing: null };
}
const missing = {};
let hasAllRequiredPermissions = true;
+ // Check scopes
const missingScopes = checkScopes(requiredPermissions.scopes, permissionUtils);
if (missingScopes) {
missing.scopes = missingScopes;
hasAllRequiredPermissions = false;
}
+ // Check external permissions
const missingExternal = checkExternalPermissions(requiredPermissions.external, permissionUtils);
if (missingExternal) {
missing.external = missingExternal;
hasAllRequiredPermissions = false;
}
+ // Note: Content permissions are not supported in the current RuntimePermissions type
return {
granted: hasAllRequiredPermissions,
missing: hasAllRequiredPermissions ? null : missing
}; Index: package/out/realtime/productContext.js
===================================================================
--- package/out/realtime/productContext.js
+++ package/out/realtime/productContext.js
@@ -1,5 +1,7 @@
"use strict";
+// These enum values directly map to properties in the context.extension object in a product's FCT.
+// It allows a subset of properties to be specified for Realtime channel authorization.
Object.defineProperty(exports, "__esModule", { value: true });
exports.Bitbucket = exports.Confluence = exports.Jira = void 0;
var Jira;
(function (Jira) { Index: package/out/router/router.js
===================================================================
--- package/out/router/router.js
+++ package/out/router/router.js
@@ -2,8 +2,14 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.router = void 0;
const bridge_1 = require("../bridge");
const callBridge = (0, bridge_1.getCallBridge)();
+/**
+ * Returns a URL object for a given location.
+ *
+ * @param location - The location to get the URL for
+ * @returns A URL object for the given location
+ */
const getUrl = async (location) => {
if (!(location === null || location === void 0 ? void 0 : location.target)) {
throw new Error('target is required for getUrl');
}
@@ -17,8 +23,14 @@
catch (error) {
throw new Error(`Failed to parse URL: ${url} (${error})`);
}
};
+/**
+ * Navigates to a location within the same tab.
+ *
+ * @param location URL or `NavigationLocation` object
+ * @returns a promise that resolves when navigation is complete
+ */
const navigate = (location) => {
if (typeof location === 'string') {
return callBridge('navigate', { url: location, type: 'same-tab' });
}
@@ -28,8 +40,14 @@
}
return callBridge('navigate', { ...location, type: 'same-tab' });
}
};
+/**
+ * Opens a new tab in the browser and navigates to the specified location.
+ *
+ * @param location URL or `NavigationLocation` object
+ * @returns a promise that resolves when navigation is complete
+ */
const open = (location) => {
if (typeof location === 'string') {
return callBridge('navigate', { url: location, type: 'new-tab' });
}
@@ -39,8 +57,13 @@
}
return callBridge('navigate', { ...location, type: 'new-tab' });
}
};
+/**
+ * Reloads the page.
+ *
+ * @returns a promise that resolves to void when the page is reloaded
+ */
const reload = async () => callBridge('reload');
exports.router = {
getUrl,
navigate, Index: package/out/events/serialiseBlob.js
===================================================================
--- package/out/events/serialiseBlob.js
+++ package/out/events/serialiseBlob.js
@@ -1,8 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.containsSerialisedBlobs = exports.containsBlobs = exports.deserialiseBlobsInPayload = exports.serialiseBlobsInPayload = void 0;
const blobParser_1 = require("../utils/blobParser");
+// Copied from https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore?tab=readme-ov-file#_isplainobject
const isPlainObject = (value) => {
if (typeof value !== 'object' || value === null)
return false;
if (Object.prototype.toString.call(value) !== '[object Object]')
@@ -22,40 +23,50 @@
type: blob.type
};
};
const base64WithMetadataToBlob = (metadata) => {
+ // typecasting as Blob since base64ToBlob returns Blob | null but this is only null if data is undefined which it won't be here
return (0, blobParser_1.base64ToBlob)(metadata.data, metadata.type);
};
+// Recursively converts all Blobs in an object or array to base64 with metadata
const serialiseBlobsInPayload = async (payload) => {
if (payload instanceof Blob) {
+ // Convert blob to base64 with metadata and mark it as a serialized blob
const blobData = await blobToBase64WithMetadata(payload);
return {
...blobData,
+ // Custom property used to identify serialized blob data for deserialization
__isBlobData: true
};
}
if (Array.isArray(payload)) {
+ // Recursively process array elements
return Promise.all(payload.map((item) => (0, exports.serialiseBlobsInPayload)(item)));
}
if (payload && isPlainObject(payload)) {
+ // Recursively process object properties
const entries = await Promise.all(Object.entries(payload).map(async ([key, value]) => [key, await (0, exports.serialiseBlobsInPayload)(value)]));
return Object.fromEntries(entries);
}
return payload;
};
exports.serialiseBlobsInPayload = serialiseBlobsInPayload;
+// Recursively converts all serialized blob data back to Blobs in an object or array
const deserialiseBlobsInPayload = (payload) => {
if (payload && isPlainObject(payload) && '__isBlobData' in payload) {
const typedData = payload;
+ // Convert serialized blob data back to Blob
return base64WithMetadataToBlob({
data: typedData.data,
type: typedData.type
});
}
if (Array.isArray(payload)) {
+ // Recursively process array elements
return payload.map((item) => (0, exports.deserialiseBlobsInPayload)(item));
}
if (payload && isPlainObject(payload)) {
+ // Recursively process object properties
const result = {};
for (const [key, value] of Object.entries(payload)) {
result[key] = (0, exports.deserialiseBlobsInPayload)(value);
} Index: package/out/router/targets.js
===================================================================
--- package/out/router/targets.js
+++ package/out/router/targets.js
@@ -1,14 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NavigationTarget = void 0;
+// Constants for developer convenience. The JS Docs below will also be displayed in the IDE when the developer is using this object.
exports.NavigationTarget = {
+ /**
+ * The view page for pages, blogs and custom content. Takes a contentId to identify the content.
+ */
ContentView: 'contentView',
+ /**
+ * The edit page for pages, blogs and custom content. Takes a contentId to identify the content.
+ */
ContentEdit: 'contentEdit',
+ /**
+ * The list/collector page for pages, blogs and custom content contained in a space. Takes a spaceKey and a contentType to identify the content type for pages and blogs. Takes a moduleKey for custom content.
+ */
ContentList: 'contentList',
+ /**
+ * The space view page. Takes a spaceKey to identify the space.
+ */
SpaceView: 'spaceView',
+ /**
+ * The page within a specific module. Takes a moduleKey to identify the correct module.
+ */
Module: 'module',
+ /**
+ * The profile page for a specific user. Takes an accountId to identify the user.
+ */
UserProfile: 'userProfile',
+ /**
+ * A dashboard in Jira. Takes a dashboardId to identify the dashboard.
+ */
Dashboard: 'dashboard',
+ /**
+ * An issue in Jira. Takes an issueKey to identify the issue.
+ */
Issue: 'issue',
+ /**
+ * The project settings details of a Jira project. Takes a projectKey to identify the project. Only accessible to administrators.
+ */
ProjectSettingsDetails: 'projectSettingsDetails'
}; Index: package/out/object-store/upload.js
===================================================================
--- package/out/object-store/upload.js
+++ package/out/object-store/upload.js
@@ -5,8 +5,11 @@
const errors_1 = require("../errors");
const utils_1 = require("./utils");
const bridge_1 = require("../bridge");
const callBridge = (0, bridge_1.getCallBridge)();
+/**
+ * Convert base64 string to Blob
+ */
const base64ToBlob = (base64, mimeType) => {
const byteCharacters = atob(base64);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
@@ -14,28 +17,43 @@
}
const byteArray = new Uint8Array(byteNumbers);
return new Blob([byteArray], { type: mimeType || 'application/octet-stream' });
};
+/**
+ * Get metadata for a blob object including size and checksum
+ */
const getObjectMetadata = async (blob) => {
const length = blob.size;
+ // Calculate checksum using SubtleCrypto API
const arrayBuffer = await blob.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
const hashArray = new Uint8Array(hashBuffer);
+ // Convert to base64 format (required by OS API)
const checksum = btoa(String.fromCharCode(...hashArray));
const checksumType = 'SHA256';
return {
length,
checksum,
checksumType
};
};
+/**
+ * Start individual upload operations and return array of promises
+ * This allows tracking per-file upload progress
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate presigned URLs
+ * @param objects - Array of Blob objects or Base64Object (with data and optional mimeType) to upload
+ * @returns Array of individual upload promises with their associated index
+ * @throws {BridgeAPIError} When filtering fails or upload encounters an error
+ */
const createUploadPromises = async ({ functionKey, objects }) => {
if (!functionKey || functionKey.length === 0) {
throw new errors_1.BridgeAPIError('functionKey is required to filter and generate presigned URLs');
}
if (!Array.isArray(objects) || objects.length === 0) {
throw new errors_1.BridgeAPIError('objects array is required and must not be empty');
}
+ // Validate and convert objects to Blobs in a single pass
const blobs = objects.map((obj, index) => {
if (obj instanceof Blob) {
return obj;
}
@@ -118,8 +136,16 @@
});
return uploadPromises;
};
exports.createUploadPromises = createUploadPromises;
+/**
+ * Upload multiple objects to pre-signed URLs
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate presigned URLs
+ * @param objects - Array of Blob objects or Base64Object (with data and optional mimeType) to upload
+ * @returns Promise resolving to UploadResult[]
+ * @throws {BridgeAPIError} When filtering fails or upload encounters an error
+ */
const upload = async ({ functionKey, objects }) => {
await (0, utils_1.checkRestrictedEnvironment)();
void callBridge('trackObjectStoreAction', { action: 'upload' });
const uploadPromises = await (0, exports.createUploadPromises)({ functionKey, objects }); Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,7 +1,7 @@
{
"name": "@forge/bridge",
- "version": "5.15.2-next.0-experimental-5b726e6",
+ "version": "5.16.0-next.1",
"description": "Forge bridge API for custom UI apps",
"author": "Atlassian",
"license": "SEE LICENSE IN LICENSE.txt",
"main": "out/index.js",
@@ -16,11 +16,11 @@
"@atlaskit/adf-schema": "^48.0.0",
"@atlaskit/tokens": "^1.58.0",
"@forge/egress": "^2.3.2",
"@forge/i18n": "0.0.7",
- "@forge/resolver": "1.7.1",
+ "@forge/resolver": "1.8.0-next.0",
"@types/history": "^4.7.11",
- "@forge/manifest": "12.6.0-next.0-experimental-5b726e6",
+ "@forge/manifest": "12.6.0-next.0",
"@types/iframe-resizer": "^3.5.8",
"iframe-resizer": "^4.4.5",
"uuid": "^9.0.1"
}, Index: package/out/object-store/deleteObjects.d.ts.map
===================================================================
--- package/out/object-store/deleteObjects.d.ts.map
+++ package/out/object-store/deleteObjects.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"deleteObjects.d.ts","sourceRoot":"","sources":["../../src/object-store/deleteObjects.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,aAAa;iBAAgD,MAAM;UAAQ,MAAM,EAAE;MAAK,QAAQ,IAAI,CAkBhH,CAAC"}
\ No newline at end of file
+{"version":3,"file":"deleteObjects.d.ts","sourceRoot":"","sources":["../../src/object-store/deleteObjects.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;iBAAgD,MAAM;UAAQ,MAAM,EAAE;MAAK,QAAQ,IAAI,CAkBhH,CAAC"}
\ No newline at end of file Index: package/out/object-store/download.d.ts.map
===================================================================
--- package/out/object-store/download.d.ts.map
+++ package/out/object-store/download.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/object-store/download.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAsB,MAAM,SAAS,CAAC;AAclE,eAAO,MAAM,QAAQ;iBAIN,MAAM;UACb,MAAM,EAAE;MACZ,QAAQ,cAAc,EAAE,CAyD3B,CAAC"}
\ No newline at end of file
+{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/object-store/download.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAsB,MAAM,SAAS,CAAC;AAMlE;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ;iBAIN,MAAM;UACb,MAAM,EAAE;MACZ,QAAQ,cAAc,EAAE,CAyD3B,CAAC"}
\ No newline at end of file Index: package/out/featureFlags/featureFlags.d.ts.map
===================================================================
--- package/out/featureFlags/featureFlags.d.ts.map
+++ package/out/featureFlags/featureFlags.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"featureFlags.d.ts","sourceRoot":"","sources":["../../src/featureFlags/featureFlags.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,eAAe,EACf,sBAAsB,EAEvB,MAAM,SAAS,CAAC;AAEjB,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,UAAU,CAAkC;IAKvC,UAAU,CACrB,IAAI,EAAE,eAAe,EACrB,MAAM,GAAE,sBAAuD,GAC9D,OAAO,CAAC,IAAI,CAAC;IAoBT,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,OAAO;IAa1D,QAAQ;IAQR,aAAa;IAIpB,OAAO,CAAC,kBAAkB;CAa3B"}
\ No newline at end of file
+{"version":3,"file":"featureFlags.d.ts","sourceRoot":"","sources":["../../src/featureFlags/featureFlags.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,eAAe,EACf,sBAAsB,EAEvB,MAAM,SAAS,CAAC;AAEjB,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,UAAU,CAAkC;IAEpD;;OAEG;IACU,UAAU,CACrB,IAAI,EAAE,eAAe,EACrB,MAAM,GAAE,sBAAuD,GAC9D,OAAO,CAAC,IAAI,CAAC;IAiBhB;;OAEG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,OAAO;IAUjE;;OAEG;IACI,QAAQ;IAQR,aAAa;IAIpB,OAAO,CAAC,kBAAkB;CAa3B"}
\ No newline at end of file Index: package/out/flag/flag.d.ts.map
===================================================================
--- package/out/flag/flag.d.ts.map
+++ package/out/flag/flag.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"flag.d.ts","sourceRoot":"","sources":["../../src/flag/flag.ts"],"names":[],"mappings":"AAGA,oBAAY,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AACtE,oBAAY,QAAQ,GAAG,cAAc,CAAC;AAEtC,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IAKrB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAIhB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAID,eAAO,MAAM,QAAQ,YAAa,WAAW,KAAG,IAgB/C,CAAC"}
\ No newline at end of file
+{"version":3,"file":"flag.d.ts","sourceRoot":"","sources":["../../src/flag/flag.ts"],"names":[],"mappings":"AAGA,oBAAY,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AACtE,oBAAY,QAAQ,GAAG,cAAc,CAAC;AAEtC,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;OAEG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAID,eAAO,MAAM,QAAQ,YAAa,WAAW,KAAG,IAgB/C,CAAC"}
\ No newline at end of file Index: package/out/object-store/getMetadata.d.ts.map
===================================================================
--- package/out/object-store/getMetadata.d.ts.map
+++ package/out/object-store/getMetadata.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"getMetadata.d.ts","sourceRoot":"","sources":["../../src/object-store/getMetadata.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAcjD,eAAO,MAAM,WAAW;iBAIT,MAAM;UACb,MAAM,EAAE;MACZ,QAAQ,iBAAiB,EAAE,CA6B9B,CAAC"}
\ No newline at end of file
+{"version":3,"file":"getMetadata.d.ts","sourceRoot":"","sources":["../../src/object-store/getMetadata.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAMjD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;iBAIT,MAAM;UACb,MAAM,EAAE;MACZ,QAAQ,iBAAiB,EAAE,CA6B9B,CAAC"}
\ No newline at end of file Index: package/out/i18n/index.d.ts.map
===================================================================
--- package/out/i18n/index.d.ts.map
+++ package/out/i18n/index.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAM3B,MAAM,aAAa,CAAC;AAuBrB,eAAO,MAAM,sBAAsB,QAAO,IAEzC,CAAC;AAEF,eAAO,MAAM,eAAe,YAClB,wBAAwB,GAAG,IAAI,YAC9B,sBAAsB,KAG9B,QAAQ,qBAAqB,CAO/B,CAAC;AAUF,oBAAY,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AASrF,eAAO,MAAM,yBAAyB,YAC5B,wBAAwB,GAAG,IAAI,KACtC,QAAQ,mBAAmB,CAS7B,CAAC"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAM3B,MAAM,aAAa,CAAC;AAuBrB,eAAO,MAAM,sBAAsB,QAAO,IAEzC,CAAC;AAEF,eAAO,MAAM,eAAe,YAClB,wBAAwB,GAAG,IAAI,YAC9B,sBAAsB,KAG9B,QAAQ,qBAAqB,CAO/B,CAAC;AAEF;;;;;;;GAOG;AACH,oBAAY,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAErF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,YAC5B,wBAAwB,GAAG,IAAI,KACtC,QAAQ,mBAAmB,CAS7B,CAAC"}
\ No newline at end of file Index: package/out/invoke/invoke.d.ts.map
===================================================================
--- package/out/invoke/invoke.d.ts.map
+++ package/out/invoke/invoke.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/invoke/invoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAInF,OAAO,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAC;AAuBzD,eAAO,MAAM,MAAM,6EAA4F,CAAC;AAEhH,aAAK,MAAM,CAAC,IAAI,SAAS,WAAW,IAAI,CAAC,GAAG,SAAS,MAAM,IAAI,GAAG,MAAM,EACtE,IAAI,EAAE,GAAG,EACT,GAAG,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,KAC5B,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAOnC,wBAAgB,UAAU,CAAC,IAAI,SAAS,WAAW,KAAK,MAAM,CAAC,IAAI,CAAC,CAEnE"}
\ No newline at end of file
+{"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/invoke/invoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAInF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA+BzD;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,OAAO,SAAS,aAAa,EAAE,CAAC,GAAG,cAAc,EACtE,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,CAAC,CAAC,CAAC;AAEd;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,GAAG,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AASrG,aAAK,MAAM,CAAC,IAAI,SAAS,WAAW,IAAI,CAAC,GAAG,SAAS,MAAM,IAAI,GAAG,MAAM,EACtE,IAAI,EAAE,GAAG,EACT,GAAG,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,KAC5B,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAEnC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,SAAS,WAAW,KAAK,MAAM,CAAC,IAAI,CAAC,CAEnE"}
\ No newline at end of file Index: package/out/rovo/isEnabled.d.ts.map
===================================================================
--- package/out/rovo/isEnabled.d.ts.map
+++ package/out/rovo/isEnabled.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"isEnabled.d.ts","sourceRoot":"","sources":["../../src/rovo/isEnabled.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,SAAS,wBAErB,CAAC"}
\ No newline at end of file
+{"version":3,"file":"isEnabled.d.ts","sourceRoot":"","sources":["../../src/rovo/isEnabled.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,SAAS,wBAErB,CAAC"}
\ No newline at end of file Index: package/out/rovo/open.d.ts.map
===================================================================
--- package/out/rovo/open.d.ts.map
+++ package/out/rovo/open.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../src/rovo/open.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAO1C,eAAO,MAAM,8BAA8B,uPAC2M,CAAC;AA4BvP,eAAO,MAAM,IAAI,oBAA2B,eAAe,kBAiB1D,CAAC"}
\ No newline at end of file
+{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../src/rovo/open.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAO1C,eAAO,MAAM,8BAA8B,uPAC2M,CAAC;AAmBvP;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,oBAA2B,eAAe,kBAiB1D,CAAC"}
\ No newline at end of file Index: package/out/permissions/permissionsUtil.d.ts.map
===================================================================
--- package/out/permissions/permissionsUtil.d.ts.map
+++ package/out/permissions/permissionsUtil.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"permissionsUtil.d.ts","sourceRoot":"","sources":["../../src/permissions/permissionsUtil.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAoBnD,QAAA,MAAM,cAAc,sEAAuE,CAAC;AAC5F,oBAAY,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAK3D,QAAA,MAAM,WAAW,gCAAiC,CAAC;AACnD,oBAAY,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAKrD,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE;YACN,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;SACnB,CAAC;QACF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAKD,oBAAY,kBAAkB,GAAG,sBAAsB,CAAC;AAKxD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACpC;AAKD,MAAM,WAAW,eAAe;IAI9B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAOrC,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAOxD,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAK9D,SAAS,EAAE,MAAM,MAAM,EAAE,CAAC;IAK1B,sBAAsB,EAAE,MAAM,QAAQ,GAAG,SAAS,CAAC;IAKnD,iBAAiB,EAAE,MAAM,OAAO,CAAC;CAClC;AAOD,wBAAgB,qBAAqB,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,GAAG,eAAe,GAAG,IAAI,CAmDhH;AA+ID,wBAAsB,gBAAgB,CACpC,mBAAmB,EAAE,sBAAsB,EAC3C,kBAAkB,CAAC,EAAE,kBAAkB,GAAG,SAAS,GAClD,OAAO,CAAC,qBAAqB,CAAC,CAiDhC"}
\ No newline at end of file
+{"version":3,"file":"permissionsUtil.d.ts","sourceRoot":"","sources":["../../src/permissions/permissionsUtil.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAiBnD;;GAEG;AACH,QAAA,MAAM,cAAc,sEAAuE,CAAC;AAC5F,oBAAY,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D;;GAEG;AACH,QAAA,MAAM,WAAW,gCAAiC,CAAC;AACnD,oBAAY,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE;YACN,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;SACnB,CAAC;QACF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,oBAAY,kBAAkB,GAAG,sBAAsB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAErC;;;;OAIG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAExD;;;;OAIG;IACH,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAE9D;;OAEG;IACH,SAAS,EAAE,MAAM,MAAM,EAAE,CAAC;IAE1B;;OAEG;IACH,sBAAsB,EAAE,MAAM,QAAQ,GAAG,SAAS,CAAC;IAEnD;;OAEG;IACH,iBAAiB,EAAE,MAAM,OAAO,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,GAAG,eAAe,GAAG,IAAI,CAmDhH;AAyID;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,mBAAmB,EAAE,sBAAsB,EAC3C,kBAAkB,CAAC,EAAE,kBAAkB,GAAG,SAAS,GAClD,OAAO,CAAC,qBAAqB,CAAC,CAiDhC"}
\ No newline at end of file Index: package/out/router/targets.d.ts.map
===================================================================
--- package/out/router/targets.d.ts.map
+++ package/out/router/targets.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../src/router/targets.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,gBAAgB;;;;;;;;;;CAqCnB,CAAC"}
\ No newline at end of file
+{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../src/router/targets.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,gBAAgB;IAC3B;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;CAEK,CAAC"}
\ No newline at end of file Index: package/out/types.d.ts.map
===================================================================
--- package/out/types.d.ts.map
+++ package/out/types.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,oBAAY,aAAa,GAAG;KACzB,GAAG,IAAI,MAAM,GAAG,MAAM,GAAG,GAAG;CAC9B,CAAC;AAEF,oBAAY,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;AAExD,aAAK,aAAa,GAAG;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,YAAY,CAAC,CAAC;AAEhD,oBAAY,oBAAoB,GAAG,aAAa,CAAC;AACjD,oBAAY,mBAAmB,GAAG,aAAa,CAAC;AAEhD,oBAAY,oBAAoB;IAC9B,WAAW,gBAAgB;IAC3B,OAAO,YAAY;IACnB,UAAU,eAAe;CAC1B;AAED,aAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,oBAAY,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAEhE,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,aAAa,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,wBAAwB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AACD,UAAU,aAAa;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB;AAED,aAAK,oBAAoB;IACvB,WAAW,gBAAgB;CAC5B;AACD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAAC;CACtC;AAED,oBAAY,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAQF,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAGD,oBAAY,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAE3D,oBAAY,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC"}
\ No newline at end of file
+{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,oBAAY,aAAa,GAAG;KACzB,GAAG,IAAI,MAAM,GAAG,MAAM,GAAG,GAAG;CAC9B,CAAC;AAEF,oBAAY,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;AAExD,aAAK,aAAa,GAAG;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,YAAY,CAAC,CAAC;AAEhD,oBAAY,oBAAoB,GAAG,aAAa,CAAC;AACjD,oBAAY,mBAAmB,GAAG,aAAa,CAAC;AAEhD,oBAAY,oBAAoB;IAC9B,WAAW,gBAAgB;IAC3B,OAAO,YAAY;IACnB,UAAU,eAAe;CAC1B;AAED,aAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,oBAAY,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAEhE,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,aAAa,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,wBAAwB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AACD,UAAU,aAAa;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB;AAED,aAAK,oBAAoB;IACvB,WAAW,gBAAgB;CAC5B;AACD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAAC;CACtC;AAED,oBAAY,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAGD,oBAAY,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAE3D,oBAAY,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC"}
\ No newline at end of file Index: package/out/object-store/upload.d.ts.map
===================================================================
--- package/out/object-store/upload.d.ts.map
+++ package/out/object-store/upload.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/object-store/upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAuC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAiDlH,eAAO,MAAM,oBAAoB;iBAIlB,MAAM;aACV,YAAY,EAAE;MACrB,QAAQ,iBAAiB,EAAE,CA0G9B,CAAC;AAUF,eAAO,MAAM,MAAM;iBAIJ,MAAM;aACV,YAAY,EAAE;MACrB,QAAQ,YAAY,EAAE,CASzB,CAAC"}
\ No newline at end of file
+{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/object-store/upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAuC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAwClH;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB;iBAIlB,MAAM;aACV,YAAY,EAAE;MACrB,QAAQ,iBAAiB,EAAE,CA0G9B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM;iBAIJ,MAAM;aACV,YAAY,EAAE;MACrB,QAAQ,YAAY,EAAE,CASzB,CAAC"}
\ No newline at end of file Index: package/CHANGELOG.md
===================================================================
--- package/CHANGELOG.md
+++ package/CHANGELOG.md
@@ -1,13 +1,16 @@
# @forge/bridge
-## 5.15.2-next.0-experimental-5b726e6
+## 5.16.0-next.1
+### Minor Changes
+
+- fd8e87e: Add payload generic and jsdoc to invoke
+
### Patch Changes
-- Updated dependencies [5b726e6]
-- Updated dependencies [399ae7d]
- - @forge/[email protected]
+- Updated dependencies [6b848cf]
+ - @forge/[email protected]
## 5.15.2-next.0
### Patch Changes Index: package/out/object-store/deleteObjects.d.ts
===================================================================
--- package/out/object-store/deleteObjects.d.ts
+++ package/out/object-store/deleteObjects.d.ts
@@ -1,4 +1,12 @@
+/**
+ * Delete multiple objects
+ *
+ * @param functionKey - Configuration object containing the backend function key to delete objects
+ * @param keys - Array of object keys to delete
+ * @returns Promise<void>
+ * @throws {BridgeAPIError} When deleting fails
+ */
export declare const deleteObjects: ({ functionKey, keys }: {
functionKey: string;
keys: string[];
}) => Promise<void>; Index: package/out/object-store/download.d.ts
===================================================================
--- package/out/object-store/download.d.ts
+++ package/out/object-store/download.d.ts
@@ -1,5 +1,13 @@
import type { DownloadResult } from './types';
+/**
+ * Download multiple objects from pre-signed URLs
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate download URLs
+ * @param keys - Array of object keys to download
+ * @returns Promise resolving to DownloadResult[]
+ * @throws {BridgeAPIError} When filtering fails or download encounters an error
+ */
export declare const download: ({ functionKey, keys }: {
functionKey: string;
keys: string[];
}) => Promise<DownloadResult[]>; Index: package/out/featureFlags/featureFlags.d.ts
===================================================================
--- package/out/featureFlags/featureFlags.d.ts
+++ package/out/featureFlags/featureFlags.d.ts
@@ -2,10 +2,19 @@
export declare class FeatureFlags {
private initialized;
private evaluator;
private eventProps;
+ /**
+ * Initialize the feature flags client
+ */
initialize(user: FeatureFlagUser, config?: ForgeFeatureFlagConfig): Promise<void>;
+ /**
+ * Check if a feature flag is enabled for the user
+ */
checkFlag(flagName: string, defaultValue?: boolean): boolean;
+ /**
+ * Shutdown the feature flags client
+ */
shutdown(): void;
isInitialized(): boolean;
private sendCheckFlagEvent;
} Index: package/out/flag/flag.d.ts
===================================================================
--- package/out/flag/flag.d.ts
+++ package/out/flag/flag.d.ts
@@ -10,9 +10,16 @@
export interface FlagOptions {
id: number | string;
title?: string;
description?: string;
+ /**
+ * `type` is used to determine the icon of Flag.
+ * If `appearance` is given, `type` is overriden to equal `appearance`.
+ */
type?: FlagType;
+ /**
+ * When `appearance` is given, the Flag is bold. If not, it's a normal Flag.
+ */
appearance?: FlagAppearance;
actions?: FlagAction[];
isAutoDismiss?: boolean;
} Index: package/out/object-store/getMetadata.d.ts
===================================================================
--- package/out/object-store/getMetadata.d.ts
+++ package/out/object-store/getMetadata.d.ts
@@ -1,5 +1,13 @@
import type { GetMetadataResult } from './types';
+/**
+ * Get metadata for multiple objectIds
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate object metadata
+ * @param keys - Array of object keys to get metadata for
+ * @returns Promise resolving to GetMetadataResult[]
+ * @throws {BridgeAPIError} When filtering fails or download encounters an error
+ */
export declare const getMetadata: ({ functionKey, keys }: {
functionKey: string;
keys: string[];
}) => Promise<GetMetadataResult[]>; Index: package/out/i18n/index.d.ts
===================================================================
--- package/out/i18n/index.d.ts
+++ package/out/i18n/index.d.ts
@@ -1,6 +1,21 @@
import { type ForgeSupportedLocaleCode, type GetTranslationsOptions, type GetTranslationsResult } from '@forge/i18n';
export declare const resetTranslationsCache: () => void;
export declare const getTranslations: (locale?: ForgeSupportedLocaleCode | null, options?: GetTranslationsOptions) => Promise<GetTranslationsResult>;
+/**
+ * A function that translates an i18n key to a string.
+ *
+ * @param i18nKey The i18n key to translate.
+ * @param defaultValue The default value to return if the i18n key is not found.
+ * If not provided, the i18n key is returned.
+ * @returns The translated string.
+ */
export declare type TranslationFunction = (i18nKey: string, defaultValue?: string) => string;
+/**
+ * Creates a translation function (i.e. `t`) for the given locale.
+ * If no locale is provided, the locale from the current view context is used.
+ *
+ * @param locale The locale to create the translation function for.
+ * @returns The translation function.
+ */
export declare const createTranslationFunction: (locale?: ForgeSupportedLocaleCode | null) => Promise<TranslationFunction>;
//# sourceMappingURL=index.d.ts.map
\ No newline at end of file Index: package/out/invoke/invoke.d.ts
===================================================================
--- package/out/invoke/invoke.d.ts
+++ package/out/invoke/invoke.d.ts
@@ -1,7 +1,30 @@
import type { Definitions, DefArguments, DefResult } from '@forge/resolver/shared';
-import { InvokePayload } from '../types';
-export declare const invoke: <T>(functionKey: string, payload?: InvokePayload | undefined) => Promise<T>;
+import { InvokePayload, InvokeResponse } from '../types';
+/**
+ * Calls a resolver function with explicit payload and return types.
+ *
+ * The first generic is the payload shape and the second generic is the return type.
+ * When this overload is used, payload is required.
+ *
+ * @example
+ * type Payload = { name: string };
+ * type Response = { message: string };
+ * const response = await invoke<Payload, Response>('greet', { name: 'Taylor' });
+ */
+export declare function invoke<Payload extends InvokePayload, T = InvokeResponse>(functionKey: string, payload: Payload): Promise<T>;
+/**
+ * Calls a resolver function using the legacy generic form where the type argument is the return type.
+ *
+ * @example
+ * const response = await invoke<{ message: string }>('greet', { name: 'Taylor' });
+ */
+export declare function invoke<T = InvokeResponse>(functionKey: string, payload?: InvokePayload): Promise<T>;
declare type Invoke<Defs extends Definitions> = <Def extends keyof Defs & string>(call: Def, ...arg: DefArguments<Defs, Def>) => Promise<DefResult<Defs, Def>>;
+/**
+ * Specialises the invoke function to a given Definitions type.
+ *
+ * @returns An invoke function that can be used to call backend functions.
+ */
export declare function makeInvoke<Defs extends Definitions>(): Invoke<Defs>;
export {};
//# sourceMappingURL=invoke.d.ts.map
\ No newline at end of file Index: package/out/rovo/isEnabled.d.ts
===================================================================
--- package/out/rovo/isEnabled.d.ts
+++ package/out/rovo/isEnabled.d.ts
@@ -1,2 +1,7 @@
+/**
+ * Checks if Rovo is enabled for the current tenant.
+ *
+ * @returns boolean
+ */
export declare const isEnabled: () => Promise<boolean>;
//# sourceMappingURL=isEnabled.d.ts.map
\ No newline at end of file Index: package/out/rovo/open.d.ts
===================================================================
--- package/out/rovo/open.d.ts
+++ package/out/rovo/open.d.ts
@@ -1,4 +1,13 @@
import { OpenRovoPayload } from './types';
export declare const OPEN_ROVO_BRIDGE_ERROR_MESSAGE = "Unable to open Rovo Chat due to usage in an unsupported product. Only Confluence, Jira and some Jira Service Management modules are supported at this point. See https://developer.atlassian.com/platform/forge/apis-reference/ui-api-bridge/rovo/";
+/**
+ * Opens Rovo chat from the given Rovo agent name.
+ *
+ * @param {OpenRovoPayload} [openRovoPayload] - Payload to open chat.
+ * Can be one of:
+ * - ForgeAgentPayload: { agentName: string, agentKey: string, prompt?: string }
+ * - AtlassianAgentPayload: { agentName: string, prompt?: string }
+ * - DefaultAgentPayload: { prompt?: string }
+ */
export declare const open: (openRovoPayload: OpenRovoPayload) => Promise<void>;
//# sourceMappingURL=open.d.ts.map
\ No newline at end of file Index: package/out/permissions/permissionsUtil.d.ts
===================================================================
--- package/out/permissions/permissionsUtil.d.ts
+++ package/out/permissions/permissionsUtil.d.ts
@@ -1,10 +1,19 @@
import type { External } from '@forge/manifest';
import type { RuntimePermissions } from '../types';
+/**
+ * Resource types that can be loaded externally
+ */
declare const RESOURCE_TYPES: readonly ["fonts", "styles", "frames", "images", "media", "scripts"];
export declare type ResourceType = (typeof RESOURCE_TYPES)[number];
+/**
+ * Fetch types for external requests
+ */
declare const FETCH_TYPES: readonly ["backend", "client"];
export declare type FetchType = (typeof FETCH_TYPES)[number];
+/**
+ * Required permissions for checking
+ */
export interface PermissionRequirements {
scopes?: string[];
external?: {
fetch?: {
@@ -19,21 +28,63 @@
scripts?: string[];
};
content?: Record<string, unknown>;
}
+/**
+ * Missing permissions information
+ */
export declare type MissingPermissions = PermissionRequirements;
+/**
+ * Permission check result
+ */
export interface PermissionCheckResult {
granted: boolean;
missing: MissingPermissions | null;
}
+/**
+ * Permission utilities for checking runtime permissions
+ */
export interface PermissionUtils {
+ /**
+ * Check if a specific scope is granted
+ */
hasScope: (scope: string) => boolean;
+ /**
+ * Check if fetching from a URL is allowed for the given fetch type
+ * @param type - 'backend' (hostname-only matching) or 'client' (CSP validation with paths)
+ * @param url - The URL to check
+ */
canFetchFrom: (type: FetchType, url: string) => boolean;
+ /**
+ * Check if loading a resource from a URL is allowed
+ * @param type - The resource type (fonts, styles, frames, images, media, scripts)
+ * @param url - The URL to check
+ */
canLoadResource: (type: ResourceType, url: string) => boolean;
+ /**
+ * Get all granted scopes
+ */
getScopes: () => string[];
+ /**
+ * Get all external permissions
+ */
getExternalPermissions: () => External | undefined;
+ /**
+ * Check if any permissions are granted
+ */
hasAnyPermissions: () => boolean;
}
+/**
+ * Create permission utilities from runtime permissions
+ * @param runtimePermissions - The runtime permissions from context
+ * @returns Permission utilities or null if permissions are not available
+ */
export declare function createPermissionUtils(runtimePermissions: RuntimePermissions | undefined): PermissionUtils | null;
+/**
+ * Check if required permissions are granted
+ * @param requiredPermissions - The permissions required to check
+ * @param runtimePermissions - The runtime permissions from context (optional, will be fetched from view.getContext() if not provided)
+ * @returns Promise resolving to permission check result with granted status and missing permissions
+ */
export declare function checkPermissions(requiredPermissions: PermissionRequirements, runtimePermissions?: RuntimePermissions | undefined): Promise<PermissionCheckResult>;
export {};
//# sourceMappingURL=permissionsUtil.d.ts.map
\ No newline at end of file Index: package/out/router/targets.d.ts
===================================================================
--- package/out/router/targets.d.ts
+++ package/out/router/targets.d.ts
@@ -1,12 +1,39 @@
export declare const NavigationTarget: {
+ /**
+ * The view page for pages, blogs and custom content. Takes a contentId to identify the content.
+ */
readonly ContentView: "contentView";
+ /**
+ * The edit page for pages, blogs and custom content. Takes a contentId to identify the content.
+ */
readonly ContentEdit: "contentEdit";
+ /**
+ * The list/collector page for pages, blogs and custom content contained in a space. Takes a spaceKey and a contentType to identify the content type for pages and blogs. Takes a moduleKey for custom content.
+ */
readonly ContentList: "contentList";
+ /**
+ * The space view page. Takes a spaceKey to identify the space.
+ */
readonly SpaceView: "spaceView";
+ /**
+ * The page within a specific module. Takes a moduleKey to identify the correct module.
+ */
readonly Module: "module";
+ /**
+ * The profile page for a specific user. Takes an accountId to identify the user.
+ */
readonly UserProfile: "userProfile";
+ /**
+ * A dashboard in Jira. Takes a dashboardId to identify the dashboard.
+ */
readonly Dashboard: "dashboard";
+ /**
+ * An issue in Jira. Takes an issueKey to identify the issue.
+ */
readonly Issue: "issue";
+ /**
+ * The project settings details of a Jira project. Takes a projectKey to identify the project. Only accessible to administrators.
+ */
readonly ProjectSettingsDetails: "projectSettingsDetails";
};
//# sourceMappingURL=targets.d.ts.map
\ No newline at end of file Index: package/out/types.d.ts
===================================================================
--- package/out/types.d.ts
+++ package/out/types.d.ts
@@ -62,8 +62,14 @@
}
export declare type Subscription = {
unsubscribe: () => void;
};
+/**
+ * Runtime representation of app permissions that extends the manifest schema.
+ *
+ * This type represents the scopes and external permissions that the app
+ * has been granted, as configured in the manifest.yml file.
+ */
export interface RuntimePermissions {
scopes?: Scopes;
external?: External;
} Index: package/out/object-store/upload.d.ts
===================================================================
--- package/out/object-store/upload.d.ts
+++ package/out/object-store/upload.d.ts
@@ -1,9 +1,26 @@
import type { UploadResult, UploadObject, UploadPromiseItem } from './types';
+/**
+ * Start individual upload operations and return array of promises
+ * This allows tracking per-file upload progress
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate presigned URLs
+ * @param objects - Array of Blob objects or Base64Object (with data and optional mimeType) to upload
+ * @returns Array of individual upload promises with their associated index
+ * @throws {BridgeAPIError} When filtering fails or upload encounters an error
+ */
export declare const createUploadPromises: ({ functionKey, objects }: {
functionKey: string;
objects: UploadObject[];
}) => Promise<UploadPromiseItem[]>;
+/**
+ * Upload multiple objects to pre-signed URLs
+ *
+ * @param functionKey - Configuration object containing the backend function key to filter and generate presigned URLs
+ * @param objects - Array of Blob objects or Base64Object (with data and optional mimeType) to upload
+ * @returns Promise resolving to UploadResult[]
+ * @throws {BridgeAPIError} When filtering fails or upload encounters an error
+ */
export declare const upload: ({ functionKey, objects }: {
functionKey: string;
objects: UploadObject[];
}) => Promise<UploadResult[]>;