{
  "version": 3,
  "sources": ["../../src/web/components/FilePicker.tsx", "../../src/web/pages/project/ModulesAPI.ts", "../../src/web/pages/project/lib/useAPI.ts", "../../src/web/lib/uploadAssetByUrlWithToast.ts", "../../src/web/lib/getMultiplayerServiceSubprotocols.ts", "../../src/web/lib/getSocketURL.ts"],
  "sourcesContent": ["import type React from \"react\"\nimport { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from \"react\"\nimport type { Err, Ok, Result } from \"utils/result.ts\"\nimport { err, ok } from \"utils/result.ts\"\nimport { toast } from \"web/lib/toaster.ts\"\n\ninterface Props {\n\tdisabled?: boolean\n\tname?: string\n\tmaxSizeInMB?: number\n\tperformantLimitInMB?: number\n\tonMaxSizeExceeded?: (sizeInKB: number) => void\n\tshouldCheckFileSize?: (fileType: string) => boolean\n}\n\nexport interface FilePickerRef {\n\tshow(accept?: string[], multiple?: boolean): Promise<FilePickerResult>\n}\n\nexport class FilePickerResult {\n\tconstructor(private readonly result: Result<File[], \"cancelled\" | \"empty\">) {\n\t\tObject.assign(this, result)\n\t}\n\n\tisCanceled(): this is Err<\"cancelled\"> {\n\t\treturn !this.result.ok && this.result.error === \"cancelled\"\n\t}\n\tisEmpty(): this is Err<\"empty\"> {\n\t\treturn !this.result.ok && this.result.error === \"empty\"\n\t}\n\tisFiles(): this is Ok<[File, ...File[]]> {\n\t\treturn this.result.ok && Array.isArray(this.result.value) && this.result.value.length > 0\n\t}\n\n\tstatic canceled() {\n\t\treturn new FilePickerResult(err(\"cancelled\"))\n\t}\n\tstatic empty() {\n\t\treturn new FilePickerResult(err(\"empty\"))\n\t}\n\tstatic files(files: File[]) {\n\t\treturn new FilePickerResult(ok(files))\n\t}\n}\n\nfunction isTextOrJson(fileType: string) {\n\treturn fileType.startsWith(\"text\") || fileType === \"application/json\"\n}\n\nfunction isValidFileSize(size: number, maxSizeInMB: number, fileType: string): boolean {\n\tconst sizeInMB = size / 1000000\n\tif (isTextOrJson(fileType)) {\n\t\treturn sizeInMB <= maxSizeInMB\n\t}\n\n\treturn true\n}\n\nfunction FilePickerForwarded(\n\t{ disabled, name, maxSizeInMB, shouldCheckFileSize, onMaxSizeExceeded, performantLimitInMB = 5 }: Props,\n\tref: React.Ref<FilePickerRef>,\n) {\n\tconst formRef = useRef<HTMLFormElement>(null)\n\tconst inputRef = useRef<HTMLInputElement | null>(null)\n\tconst promiseRef = useRef<[(value: FilePickerResult) => void, (reason: unknown) => void] | null>(null)\n\tuseImperativeHandle(\n\t\tref,\n\t\t() =>\n\t\t\t({\n\t\t\t\tshow(accept, multiple) {\n\t\t\t\t\treturn new Promise<FilePickerResult>((resolve, reject) => {\n\t\t\t\t\t\tif (promiseRef.current) {\n\t\t\t\t\t\t\tconst [, oldReject] = promiseRef.current\n\t\t\t\t\t\t\toldReject(Error(\"Multiple calls to show()\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpromiseRef.current = [resolve, reject]\n\t\t\t\t\t\tif (!window.event || !window.event.isTrusted) {\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noConsole: <explanation>\n\t\t\t\t\t\t\tconsole.warn(\"FilePicker\u2018s show() must be called from trusted event\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!inputRef.current) {\n\t\t\t\t\t\t\tpromiseRef.current = null\n\t\t\t\t\t\t\tresolve(FilePickerResult.canceled())\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (accept) {\n\t\t\t\t\t\t\tinputRef.current.accept = accept.join(\",\")\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinputRef.current.removeAttribute(\"accept\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (multiple) {\n\t\t\t\t\t\t\tinputRef.current.multiple = true\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinputRef.current.removeAttribute(\"multiple\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinputRef.current.click()\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t}) satisfies FilePickerRef,\n\t)\n\tconst onInputChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (!promiseRef.current) return\n\t\t\tconst [resolve] = promiseRef.current\n\t\t\tpromiseRef.current = null\n\t\t\tconst { files } = e.currentTarget\n\t\t\tif (!files || files.length === 0) {\n\t\t\t\tresolve(FilePickerResult.empty())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst filesToUpload: File[] = []\n\n\t\t\tfor (const file of files) {\n\t\t\t\tif (maxSizeInMB === undefined || isValidFileSize(file.size, maxSizeInMB, file.type)) {\n\t\t\t\t\tconst sizeInMB = file.size / 1000000\n\n\t\t\t\t\t// This performance warning is displayed only for JSON files because large Lottie JSON files have been observed to cause performance issues.\n\t\t\t\t\tconst shouldShowPerformanceWarning = sizeInMB > performantLimitInMB && file.type === \"application/json\"\n\n\t\t\t\t\tif (shouldShowPerformanceWarning) {\n\t\t\t\t\t\ttoast({\n\t\t\t\t\t\t\ttype: \"add\",\n\t\t\t\t\t\t\tvariant: \"warning\",\n\t\t\t\t\t\t\tkey: \"file-picker-large-file-detected\",\n\t\t\t\t\t\t\tprimaryText: \"Adding large files\",\n\t\t\t\t\t\t\tsecondaryText: \"can impact performance.\",\n\t\t\t\t\t\t\tduration: 6000,\n\t\t\t\t\t\t\taction: {\n\t\t\t\t\t\t\t\ttitle: \"OK\",\n\t\t\t\t\t\t\t\tonClick: () => toast({ type: \"remove\", key: \"file-picker-large-file-detected\" }),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tfilesToUpload.push(file)\n\t\t\t\t} else if (onMaxSizeExceeded) {\n\t\t\t\t\tonMaxSizeExceeded(file.size / 1000)\n\t\t\t\t} else {\n\t\t\t\t\ttoast({\n\t\t\t\t\t\ttype: \"add\",\n\t\t\t\t\t\tvariant: \"error\",\n\t\t\t\t\t\tprimaryText: \"Exceeded max file size\",\n\t\t\t\t\t\tsecondaryText: `of ${maxSizeInMB} MB.`,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (filesToUpload.length > 0) {\n\t\t\t\tresolve(FilePickerResult.files(filesToUpload))\n\t\t\t} else {\n\t\t\t\tresolve(FilePickerResult.empty())\n\t\t\t}\n\n\t\t\tformRef.current?.reset()\n\t\t},\n\t\t[maxSizeInMB, onMaxSizeExceeded, shouldCheckFileSize],\n\t)\n\n\tconst [inputElement, setInputElement] = useState<HTMLInputElement | null>(null)\n\tconst inputCallbackRef = useCallback((node: HTMLInputElement | null) => {\n\t\tinputRef.current = node\n\t\tsetInputElement(node)\n\t}, [])\n\n\tuseEffect(() => {\n\t\tif (!inputElement) return\n\t\tconst controller = new AbortController()\n\t\tinputElement.addEventListener(\n\t\t\t\"cancel\",\n\t\t\t() => {\n\t\t\t\tif (!promiseRef.current) return\n\t\t\t\tconst [resolve] = promiseRef.current\n\t\t\t\tpromiseRef.current = null\n\t\t\t\tresolve(FilePickerResult.canceled())\n\t\t\t},\n\t\t\t{\n\t\t\t\tsignal: controller.signal,\n\t\t\t},\n\t\t)\n\t\treturn () => {\n\t\t\tcontroller.abort()\n\t\t}\n\t}, [inputElement])\n\n\treturn (\n\t\t<form ref={formRef} style={{ display: \"none\" }}>\n\t\t\t<input\n\t\t\t\tdisabled={disabled}\n\t\t\t\tname={name}\n\t\t\t\tonChange={onInputChange}\n\t\t\t\tref={inputCallbackRef}\n\t\t\t\tstyle={{ display: \"none\" }}\n\t\t\t\ttype=\"file\"\n\t\t\t/>\n\t\t</form>\n\t)\n}\n\nexport const FilePicker = forwardRef(FilePickerForwarded)\n", "import {\n\ttype ModulesAPI as ModulesAPIService,\n\tServiceEventEmitter,\n\ttype ServiceStreamOptions,\n} from \"@framerjs/framer-services\"\nimport { asGlobalId, assertNever } from \"@framerjs/shared\"\nimport type { Socket, ModuleEvent as SocketModuleEvent } from \"socket/types.ts\"\nimport type { API } from \"./lib/useAPI.ts\"\n\nexport class ModulesAPI implements ModulesAPIService.Interface {\n\tprivate readonly emitter = new ServiceEventEmitter<ModulesAPIService.ModuleEventList>()\n\n\tconstructor(\n\t\tprivate readonly api: API,\n\t\tprivate readonly socket: Pick<Socket, \"send\" | \"onMessage\">,\n\t) {\n\t\tsocket.onMessage(async message => {\n\t\t\tif (message.type !== \"moduleEvents\") return\n\n\t\t\t// Skip the per-event getModule() fan-out when nothing is listening to the stream.\n\t\t\t// Happens e.g. when ModulesStorage uses the tree as the source of truth for the local\n\t\t\t// module list and therefore never subscribes.\n\t\t\tif (!this.emitter.hasStreams()) return\n\n\t\t\tconst events = await Promise.all(\n\t\t\t\tmessage.value.events.map(async (event): Promise<ModulesAPIService.ModuleEvent> => {\n\t\t\t\t\tswitch (event.type) {\n\t\t\t\t\t\tcase \"delete\":\n\t\t\t\t\t\t\t// Pass through delete events.\n\t\t\t\t\t\t\treturn event\n\n\t\t\t\t\t\tcase \"save\":\n\t\t\t\t\t\t\t// Transform save events into fully decorated modules.\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"save\",\n\t\t\t\t\t\t\t\tmodule: await api.getModule({\n\t\t\t\t\t\t\t\t\tmoduleId: asGlobalId(event.id),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tassertNever(event)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tthis.emitter.emit({ events })\n\t\t})\n\t}\n\n\tprivate notify(events: SocketModuleEvent[]) {\n\t\tthis.socket.send({\n\t\t\ttype: \"moduleEvents\",\n\t\t\tvalue: { events },\n\t\t})\n\t}\n\n\tasync create(request: ModulesAPIService.CreateRequest): Promise<ModulesAPIService.ModuleWithSave> {\n\t\tconst module = await this.api.createModule(request)\n\t\tthis.notify([{ type: \"save\", id: module.id, saveId: module.saveId }])\n\t\treturn module\n\t}\n\n\tasync delete(request: ModulesAPIService.DeleteRequest): Promise<void> {\n\t\tawait this.api.deleteModule(request)\n\t\tthis.notify([{ type: \"delete\", id: request.moduleId }])\n\t}\n\n\tasync restore(request: ModulesAPIService.RestoreRequest): Promise<ModulesAPIService.ModuleWithSave> {\n\t\tconst module = await this.api.restoreModule(request)\n\t\tthis.notify([{ type: \"save\", id: module.id, saveId: module.saveId }])\n\t\treturn module\n\t}\n\n\tasync getModuleDependencies(\n\t\trequest: ModulesAPIService.DependenciesRequest,\n\t): Promise<ModulesAPIService.DependenciesResponse> {\n\t\treturn this.api.getModuleDependencies(request)\n\t}\n\n\tasync list(request: ModulesAPIService.ListRequest): Promise<ModulesAPIService.ListResponse> {\n\t\treturn this.api.listModules(request)\n\t}\n\n\tasync kits(): Promise<ModulesAPIService.KitsResponse> {\n\t\treturn this.api.listKits()\n\t}\n\n\tasync listNamespaces(): Promise<ModulesAPIService.ListNamespacesResponse> {\n\t\treturn this.api.listNamespaces()\n\t}\n\n\tasync listPublishedModules(\n\t\trequest: ModulesAPIService.ListPublishedModulesRequest,\n\t): Promise<ModulesAPIService.ListPublishedModulesResponse> {\n\t\treturn this.api.listPublishedModules(request)\n\t}\n\n\tasync lookUpModules(request: ModulesAPIService.LookupRequest): Promise<ModulesAPIService.LookupResponse> {\n\t\treturn this.api.lookUpModules(request)\n\t}\n\n\tasync publish(request: ModulesAPIService.PublishRequest): Promise<ModulesAPIService.Publish> {\n\t\treturn this.api.publishModule(request)\n\t}\n\n\tasync save(request: ModulesAPIService.SaveRequest): Promise<ModulesAPIService.ModuleWithSave> {\n\t\tconst module = await this.api.saveModule(request)\n\t\tthis.notify([{ type: \"save\", id: module.id, saveId: module.saveId }])\n\t\treturn module\n\t}\n\n\tasync saveBatch(request: ModulesAPIService.SaveBatchRequest): Promise<ModulesAPIService.ListResponse> {\n\t\tconst response = await this.api.saveModules(request)\n\t\tthis.notify(response.data.map(module => ({ type: \"save\", id: module.id, saveId: module.saveId })))\n\t\treturn response\n\t}\n\n\tasync update(request: ModulesAPIService.UpdateRequest): Promise<ModulesAPIService.ModuleWithSave> {\n\t\tconst module = await this.api.updateModule(request)\n\t\tthis.notify([{ type: \"save\", id: module.id, saveId: module.saveId }])\n\t\treturn module\n\t}\n\n\tmoduleEventsStream(options?: ServiceStreamOptions) {\n\t\treturn this.emitter.newStream(options)\n\t}\n\n\tasync createNamespace(request: ModulesAPIService.CreateNamespaceRequest): Promise<ModulesAPIService.Namespace> {\n\t\treturn this.api.createNamespace(request)\n\t}\n\n\tasync enqueueKitScreenshots(request: ModulesAPIService.EnqueueKitScreenshotsRequest): Promise<void> {\n\t\treturn this.api.enqueueKitScreenshots(request)\n\t}\n}\n", "import type {\n\tAccessRequestACLEntry,\n\tInviteACLEntry,\n\tLoadingProjectState,\n\tProject,\n\tUserACLEntry,\n} from \"@framerjs/app-shared\"\nimport { ACLEntryKind, Role } from \"@framerjs/app-shared\"\nimport type { Asset } from \"@framerjs/assets\"\nimport type { ModulesAPI } from \"@framerjs/framer-services\"\nimport type { GlobalModuleId } from \"@framerjs/shared\"\nimport { assert, getLogger, getServiceMap } from \"@framerjs/shared\"\nimport { noop } from \"@framerjs/shared/src/noop.ts\"\nimport { experiments } from \"app/experiments.ts\"\nimport { isModulesInTreeOn } from \"modules/isModulesInTreeOn.ts\"\nimport { useEffect, useMemo, useRef } from \"react\"\nimport type { ProjectChangeScope, Socket } from \"socket/types.ts\"\nimport { isUndefined } from \"utils/typeChecks.ts\"\nimport type { ProjectUpdateOptions } from \"web/lib/ProjectAPI.ts\"\nimport { updateProject } from \"web/lib/ProjectAPI.ts\"\nimport type { AccessRequest, RequestAccessParams } from \"web/lib/RequestEditorAccess.ts\"\nimport { requestAccess } from \"web/lib/RequestEditorAccess.ts\"\nimport { apiFetcher } from \"web/lib/apiFetcher.ts\"\nimport type { DenyAccessRequestResponse, GrantAccessRequestResponse } from \"web/lib/grantAccessRequest.ts\"\nimport { AccessRequestResponseStatus, denyAccessRequest, grantAccessRequest } from \"web/lib/grantAccessRequest.ts\"\nimport type { OnToastCallback } from \"web/lib/upload.ts\"\nimport { uploadWithToast } from \"web/lib/upload.ts\"\nimport { uploadAssetByUrlWithToast } from \"web/lib/uploadAssetByUrlWithToast.ts\"\nimport type { InviteByEmailRequest, InviteByIdRequest, InviteResponse } from \"./api/invite.ts\"\nimport { InviteStatus, invite } from \"./api/invite.ts\"\nimport type { PollResponse } from \"./api/pollProject.ts\"\nimport { PollStatus, pollProject } from \"./api/pollProject.ts\"\nimport type { UpdateUserPermissionsRequest, UpdateUserPermissionsResponse } from \"./api/updateUserPermissions.ts\"\nimport { UpdateUserPermissionsStatus, updateUserPermissions } from \"./api/updateUserPermissions.ts\"\nimport { useCompressionStream } from \"./compressionStream.ts\"\nimport type { ProjectDispatch } from \"./useProject.ts\"\n\nconst log = getLogger(\"useAPI\")\n\ninterface SaveModulesRequest extends ModulesAPI.SaveBatchRequest {\n\tcopyOnWrite?: boolean\n}\n\nexport class API {\n\tprivate readonly apiBaseURL = getServiceMap().api\n\n\tconstructor(\n\t\tprivate readonly socket: Pick<Socket, \"send\">,\n\t\tprivate readonly projectId: string,\n\t\tprivate readonly dispatch: ProjectDispatch = noop,\n\t) {}\n\n\twait(listener: () => void) {\n\t\tapiFetcher.wait(listener)\n\t}\n\n\tprivate normalizeRole(role: Role): Role {\n\t\t// For display: if the experiment is off and the role is ContentCollaborator, show as Collaborator\n\t\tif (role === Role.ContentCollaborator && !experiments.isOn(\"contentEditor\")) {\n\t\t\treturn Role.Collaborator\n\t\t}\n\t\treturn role\n\t}\n\n\tgetACL() {\n\t\tapiFetcher\n\t\t\t.get(`/web/projects/${this.projectId}/acl/`, {\n\t\t\t\tcontentCollaboratorEnabled: experiments.isOn(\"contentEditor\"),\n\t\t\t})\n\t\t\t.then(\n\t\t\t\t({\n\t\t\t\t\tusers,\n\t\t\t\t\tinvites,\n\t\t\t\t\taccessRequests,\n\t\t\t\t}: {\n\t\t\t\t\tusers: Omit<UserACLEntry, \"kind\">[]\n\t\t\t\t\tinvites: Omit<InviteACLEntry, \"kind\">[]\n\t\t\t\t\taccessRequests: Omit<AccessRequestACLEntry, \"kind\">[]\n\t\t\t\t}) => {\n\t\t\t\t\tconst normalizedUsers = users.map(u => ({\n\t\t\t\t\t\t...u,\n\t\t\t\t\t\tkind: ACLEntryKind.User,\n\t\t\t\t\t\trole: this.normalizeRole(u.role),\n\t\t\t\t\t\tpermissions: u.permissions,\n\t\t\t\t\t})) as UserACLEntry[]\n\n\t\t\t\t\tconst normalizedInvites = invites.map(i => ({\n\t\t\t\t\t\t...i,\n\t\t\t\t\t\tkind: ACLEntryKind.Invite,\n\t\t\t\t\t\trole: this.normalizeRole(i.role),\n\t\t\t\t\t\tpermissions: i.permissions,\n\t\t\t\t\t})) as InviteACLEntry[]\n\n\t\t\t\t\tthis.dispatch({\n\t\t\t\t\t\ttype: \"resetACL\",\n\t\t\t\t\t\tacl: [...normalizedUsers, ...normalizedInvites],\n\t\t\t\t\t\taccessRequests: accessRequests.map(r => ({ ...r, kind: ACLEntryKind.AccessRequest })),\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t\t.catch(reason => log.error(\"Failed to get ACL:\", reason))\n\t}\n\n\tsetInitialProject(projectPromise: Promise<Project>) {\n\t\tprojectPromise\n\t\t\t.then((project: Project) => {\n\t\t\t\tthis.dispatch({ type: \"setProject\", project })\n\t\t\t})\n\t\t\t.catch(reason => log.error(\"Failed to set initial project:\", reason))\n\t}\n\n\tgetProject() {\n\t\tapiFetcher\n\t\t\t.get(`/web/projects/${this.projectId}`, {\n\t\t\t\tincludeUsageDataV2: \"true\",\n\t\t\t\tincludeAiCreditLimit: experiments.isOn(\"agent\") ? \"true\" : undefined,\n\t\t\t})\n\t\t\t.then((project: Project) => {\n\t\t\t\tthis.dispatch({ type: \"setProject\", project })\n\t\t\t})\n\t\t\t.catch(reason => log.error(\"Failed to get project:\", reason))\n\t}\n\n\t/**\n\t * Polls for project updates every `intervalMillis`, until the\n\t * `stopCondition` is met, or it exceeds the number of `attempts`.\n\t *\n\t * Useful if you expect a specific async project update to happen, e.g.,\n\t * a site plan update, which takes some time to get processed by our billing\n\t * pipeline.\n\t *\n\t * Upon a successful `stopCondition` (i.e., we got the update we were\n\t * waiting for), it'll also notify the other users in the project to refresh\n\t * their project state.\n\t */\n\tasync pollProject({\n\t\tintervalMillis,\n\t\tattempts,\n\t\tstopCondition,\n\t}: {\n\t\tintervalMillis: number\n\t\tattempts: number\n\t\tstopCondition: (project: Project) => boolean\n\t}): Promise<PollResponse> {\n\t\tconst result = await pollProject(this.projectId, {\n\t\t\tintervalMillis,\n\t\t\tattempts,\n\t\t\tstopCondition,\n\t\t})\n\n\t\tif (result.status === PollStatus.Success) {\n\t\t\tthis.dispatch({ type: \"setProject\", project: result.project })\n\t\t\t// \"metadata\" triggers a getProject for other active users:\n\t\t\t// https://github.com/framer/FramerStudio/blob/b08f189df2c1dbac5de7ff736b40abac5eab60e2/src/app/vekter/src/web/pages/project/components/Project.tsx#L119-L120\n\t\t\tthis.notifyProjectChange(\"metadata\")\n\t\t}\n\n\t\t// Forward the result to the caller\n\t\treturn result\n\t}\n\n\tasync invite(request: InviteByEmailRequest | InviteByIdRequest): Promise<InviteResponse> {\n\t\tconst response = await invite(this.projectId, request)\n\t\tif (response.status === InviteStatus.Success) {\n\t\t\tthis.dispatch({ type: \"updateACL\", acl: [response.aclEntry] })\n\t\t\tthis.notifyProjectChange(\"acl\")\n\t\t}\n\t\treturn response\n\t}\n\n\tasync removeInvite({ id }: { id: string }) {\n\t\tawait apiFetcher.deleteRaw(`/web/projects/${this.projectId}/invites/${id}`)\n\t\tthis.notifyProjectChange(\"acl\")\n\t\t// TODO: We should be able to update the local ACL with the response above.\n\t\tthis.getACL()\n\t}\n\n\tasync updateUserPermissions(request: UpdateUserPermissionsRequest): Promise<UpdateUserPermissionsResponse> {\n\t\tconst result = await updateUserPermissions(this.projectId, request)\n\t\tif (result.status === UpdateUserPermissionsStatus.Success) {\n\t\t\tthis.notifyProjectChange(\"acl\")\n\t\t\t// TODO: We should be able to update the local ACL with the response above.\n\t\t\tthis.getACL()\n\t\t}\n\t\treturn result\n\t}\n\n\tasync requestAccess(options: RequestAccessParams): Promise<AccessRequest> {\n\t\tconst response = await requestAccess(options)\n\t\t// requesting access should refresh acl for project collaborators\n\t\t// in order for them to show the toast\n\t\tthis.notifyProjectChange(\"acl\")\n\t\treturn response\n\t}\n\n\tasync grantProjectAccessRequest({ id }: { id: string }): Promise<GrantAccessRequestResponse> {\n\t\tconst response = await grantAccessRequest(id)\n\t\tif (response.status === AccessRequestResponseStatus.Success) {\n\t\t\tthis.notifyProjectChange(\"acl\")\n\t\t\t// TODO: We should be able to update the local ACL with the response above.\n\t\t\tthis.getACL()\n\t\t}\n\t\treturn response\n\t}\n\n\tasync denyProjectAccessRequest({ id }: { id: string }): Promise<DenyAccessRequestResponse> {\n\t\tconst response = await denyAccessRequest(id)\n\t\tif (response.status === AccessRequestResponseStatus.Success) {\n\t\t\tthis.notifyProjectChange(\"acl\")\n\t\t\t// TODO: We should be able to update the local ACL with the response above.\n\t\t\tthis.getACL()\n\t\t}\n\t\treturn response\n\t}\n\n\tasync forceRefreshACL() {\n\t\tthis.notifyProjectChange(\"acl\")\n\t\tthis.getACL()\n\t}\n\n\tasync removeUserPermissions({ id }: { id: string }) {\n\t\tawait apiFetcher.deleteRaw(`/web/projects/${this.projectId}/acl/${id}`)\n\t\tthis.notifyProjectChange(\"acl\")\n\t\t// TODO: We should be able to update the local ACL with the response above.\n\t\tthis.getACL()\n\t}\n\n\tasync updateProject(changes: ProjectUpdateOptions, useOptimisticUpdate: boolean = true): Promise<void> {\n\t\t// Optimistically update the project.\n\t\t// When not using optimistic update, getProject (used below) below will dispatch the updated project.\n\t\tif (useOptimisticUpdate) {\n\t\t\tthis.dispatch({ type: \"updateProject\", changes })\n\t\t}\n\t\t// Send the changes to the API.\n\t\ttry {\n\t\t\tawait updateProject(this.projectId, changes)\n\t\t\t/**\n\t\t\t * @todo: We should receive the Project metadata here, but we only get \"OK\"...\n\t\t\t * this.dispatch({ type: \"updateProject\", changes: project })\n\t\t\t * @todo: ...so instead, we fetch the project here.\n\t\t\t */\n\t\t\tthis.getProject()\n\t\t\tthis.notifyProjectChange(\"metadata\")\n\t\t} catch (reason) {\n\t\t\tlog.error(\"Failed to update project:\", reason)\n\t\t\t// Rethrow error so the UI can correctly communicate it to the user.\n\t\t\t// NOTE: don't wrap `reason` in a new `Error()` so we don't loose\n\t\t\t// custom ApiError `data`.\n\t\t\tthrow reason\n\t\t}\n\t}\n\n\t// Feedback\n\n\tasync subscribeToNotifications(): Promise<void> {\n\t\tawait apiFetcher.postRaw(`/web/projects/${this.projectId}/threads/notifications/subscribe`)\n\t}\n\n\tasync unsubscribeFromNotifications(): Promise<void> {\n\t\tawait apiFetcher.postRaw(`/web/projects/${this.projectId}/threads/notifications/unsubscribe`)\n\t}\n\n\t// Assets\n\n\tasync getAssets(\n\t\toptions: { updatedFrom?: string } = {},\n\t): Promise<Readonly<{ assets: readonly Asset[]; lastUpdatedAt?: string }>> {\n\t\tconst { updatedFrom } = options\n\n\t\tlet endpoint = `/web/v2/projects/${this.projectId}/assets/`\n\n\t\t// updatedFrom is only supported in the v2 endpoint\n\t\tif (updatedFrom) {\n\t\t\tconst qs = new URLSearchParams({ updatedFrom })\n\t\t\tendpoint += `?${qs.toString()}`\n\t\t}\n\n\t\tconst response = await apiFetcher.get(endpoint)\n\t\tif (!Array.isArray(response.assets)) {\n\t\t\tconst error = new Error(\"malformed /projects/./assets/ response\")\n\t\t\tlog.reportError(error, response)\n\t\t\tthrow error\n\t\t}\n\t\treturn response\n\t}\n\n\t/**\n\t * Used to persist user uploaded files as framer assets.\n\t * @param file - File to persist as a framer asset\n\t * @param maxFileSize - Maximum allowed file size for upload\n\t * @param onToast - Will not show toasts if not passed.\n\t * @returns\n\t */\n\tasync uploadAsset(\n\t\tfile: File,\n\t\t{\n\t\t\tmaxFileSize,\n\t\t\tonExceedsCustomMaxSize,\n\t\t\tonToast = noop,\n\t\t}: {\n\t\t\tmaxFileSize?: number\n\t\t\tonExceedsCustomMaxSize?: (size: number) => void\n\t\t\tonToast?: OnToastCallback\n\t\t} = {},\n\t): Promise<Asset | null> {\n\t\tconst endpoint = new URL(`/web/projects/${this.projectId}/assets`, this.apiBaseURL).href\n\t\tconst response = await uploadWithToast<Asset>({\n\t\t\tendpoint,\n\t\t\tfieldName: \"file\",\n\t\t\tfile,\n\t\t\ticon: \"image\",\n\t\t\tonToast,\n\t\t\tcustomMaxSize: maxFileSize,\n\t\t\tonExceedsCustomMaxSize,\n\t\t})\n\t\tif (response) {\n\t\t\tthis.notifyProjectChange(\"assets\")\n\t\t}\n\t\treturn response\n\t}\n\n\t/**\n\t * Multipart upload that persists a file as a user-scoped asset.\n\t *\n\t * Unlike `uploadAsset`, this does not attach the file to `this.projectId` and does not call\n\t * `notifyProjectChange(\"assets\")`. Use `uploadAsset` when the file should belong to the open project.\n\t *\n\t * Primary use case: agent chat attachments, so duplicating/remixing a project does not create extra\n\t * project-owned asset rows for images the user only attached to a conversation.\n\t *\n\t * @param file - File to persist as a Framer asset for the signed-in user.\n\t * @param maxFileSize - Optional maximum size in MB for the client-side check (see `uploadWithToast`).\n\t * @param onExceedsCustomMaxSize - Invoked when `maxFileSize` rejects the upload before the request runs.\n\t * @param onToast - Toast handler for progress and errors; pass `noop` for silent uploads.\n\t * @returns The created asset, or `null` when the client rejects the upload (e.g. oversize) or the upload fails without throwing.\n\t */\n\tasync uploadUserAsset(\n\t\tfile: File,\n\t\t{\n\t\t\tmaxFileSize,\n\t\t\tonExceedsCustomMaxSize,\n\t\t\tonToast = noop,\n\t\t}: {\n\t\t\tmaxFileSize?: number\n\t\t\tonExceedsCustomMaxSize?: (size: number) => void\n\t\t\tonToast?: OnToastCallback\n\t\t} = {},\n\t): Promise<Asset | null> {\n\t\tconst endpoint = new URL(`/web/users/assets`, this.apiBaseURL).href\n\t\treturn uploadWithToast<Asset>({\n\t\t\tendpoint,\n\t\t\tfieldName: \"file\",\n\t\t\tfile,\n\t\t\ticon: \"image\",\n\t\t\tonToast,\n\t\t\tcustomMaxSize: maxFileSize,\n\t\t\tonExceedsCustomMaxSize,\n\t\t})\n\t}\n\n\t/**\n\t * Used for external assets which for which we only have url references.\n\t * such as in html from the CSV importer or when a user pasts html in the\n\t * CMS that contains images\n\t * @param url - external asset url that server should be fetched and\n\t * uploaded by the assetService\n\t * @param onToast - Will not show toasts if not passed.\n\t */\n\tasync uploadAssetByURL(url: string, onToast: OnToastCallback = noop): Promise<Asset> {\n\t\tconst response: Readonly<Asset> = await uploadAssetByUrlWithToast(\n\t\t\t`/web/projects/${this.projectId}/assets/fetch`,\n\t\t\turl,\n\t\t\t\"image\",\n\t\t\tonToast,\n\t\t)\n\t\tif (response) {\n\t\t\tthis.notifyProjectChange(\"assets\")\n\t\t}\n\t\treturn response\n\t}\n\n\tasync duplicateAssets(keys: string[], sourceProjectId: string): Promise<readonly Asset[]> {\n\t\tif (this.projectId === sourceProjectId) {\n\t\t\tlog.warn(\"Attempted to duplicate assets for current project\")\n\t\t\treturn []\n\t\t}\n\t\tconst response: Readonly<{ assets: readonly Asset[] }> = await apiFetcher.post(\n\t\t\t`/web/projects/${this.projectId}/assets/duplicate`,\n\t\t\t{\n\t\t\t\tsourceProjectId,\n\t\t\t\tkeys,\n\t\t\t},\n\t\t)\n\t\tif (response) {\n\t\t\tthis.notifyProjectChange(\"assets\")\n\t\t}\n\t\treturn response.assets\n\t}\n\n\tasync duplicateWorkspaceAssets(keys: string[], sourceTeamId: string): Promise<readonly Asset[]> {\n\t\tconst response: Readonly<{ assets: readonly Asset[] }> = await apiFetcher.post(\n\t\t\t`/web/projects/${this.projectId}/assets/duplicate`,\n\t\t\t{\n\t\t\t\tsourceTeamId,\n\t\t\t\tkeys,\n\t\t\t},\n\t\t)\n\t\tif (response) {\n\t\t\tthis.notifyProjectChange(\"assets\")\n\t\t}\n\t\treturn response.assets\n\t}\n\n\tasync duplicateModuleAssets(\n\t\tsourceModuleId: string,\n\t\tsourceSaveId: string,\n\t\tkeys?: string[],\n\t): Promise<readonly Asset[]> {\n\t\tconst body: { moduleId: string; saveId: string; keys?: string[] } = {\n\t\t\tmoduleId: sourceModuleId,\n\t\t\tsaveId: sourceSaveId,\n\t\t}\n\t\tif (keys && keys.length > 0) body.keys = keys\n\n\t\tconst response: Readonly<{ assets: readonly Asset[] }> = await apiFetcher.post(\n\t\t\t`/web/projects/${this.projectId}/assets/duplicate-module`,\n\t\t\tbody,\n\t\t)\n\t\tif (response) {\n\t\t\tthis.notifyProjectChange(\"assets\")\n\t\t}\n\t\treturn response.assets\n\t}\n\n\t/**\n\t * Deletes one or more assets from the project.\n\t * The deletion is idempotent, any keys not found (e.g. already deleted) will be silently ignored.\n\t * @param keys - The keys of the assets to delete.\n\t * @returns The response from the API.\n\t */\n\tasync deleteAssets(keys: string[]): Promise<Response> {\n\t\t// The batch delete endpoint can delete one or more assets, so lets use it for all deletions consistently.\n\t\tconst response = await apiFetcher.delete(`/web/projects/${this.projectId}/assets/batch`, {\n\t\t\tkeys,\n\t\t})\n\n\t\t// TODO: this is inefficient, forcing a full reload of the asset list (even if the asset didn't actually exist).\n\t\t// Deleting assets is a very rare operation, so we keep it simple but inefficient for now.\n\t\tthis.notifyProjectChange(\"assetsInvalidated\")\n\n\t\treturn response\n\t}\n\n\t// Modules\n\n\tasync createModule(req: ModulesAPI.CreateRequest): Promise<ModulesAPI.ModuleWithSave> {\n\t\tconst body = new FormData()\n\t\t// TODO: `void` was added here during a ESLint fixing round \u2013 to fix the ESLint error\n\t\t// without changing the code behavior. But do we actually need an `await` here instead?\n\t\tvoid this.addModuleRequestToForm(req, body)\n\t\tconst module = await apiFetcher\n\t\t\t.postRaw(`/modules/v1/modules/`, body)\n\t\t\t.then(r => r.json() as Promise<ModulesAPI.ModuleWithSave>)\n\t\treturn module\n\t}\n\n\tasync deleteModule({ moduleId }: ModulesAPI.DeleteRequest): Promise<void> {\n\t\tawait apiFetcher.deleteRaw(`/modules/v1/modules/${moduleId}${this.modulesCopyOnWriteParam()}`)\n\t}\n\n\tasync restoreModule({ moduleId, name }: ModulesAPI.RestoreRequest): Promise<ModulesAPI.ModuleWithSave> {\n\t\tconst body: Record<string, string> = {}\n\t\tif (name !== undefined) body.name = name\n\t\tconst module: ModulesAPI.ModuleWithSave = await apiFetcher.post(`/modules/v1/modules/${moduleId}/restore`, body)\n\t\treturn module\n\t}\n\n\tasync getModule({\n\t\tmoduleId,\n\t\tsaveId,\n\t}: {\n\t\tmoduleId: GlobalModuleId\n\t\tsaveId?: string\n\t}): Promise<ModulesAPI.ModuleWithSave> {\n\t\tlet path: string | undefined\n\t\tif (saveId) {\n\t\t\tpath = `/modules/v1/modules/${moduleId}/saves/${saveId}`\n\t\t} else {\n\t\t\tpath = `/modules/v1/modules/${moduleId}`\n\t\t}\n\t\treturn apiFetcher.get(path)\n\t}\n\n\tasync getModuleDependencies({\n\t\tmoduleId,\n\t\tsaveId,\n\t}: ModulesAPI.DependenciesRequest): Promise<ModulesAPI.DependenciesResponse> {\n\t\treturn apiFetcher.get(`/modules/v1/modules/${moduleId}/saves/${saveId}/dependencies/`)\n\t}\n\n\tasync listModules({ types }: ModulesAPI.ListRequest = {}): Promise<ModulesAPI.ListResponse> {\n\t\t// Note: The types list is added manually here because Fetcher currently adds [] to names when they're arrays.\n\t\tconst qs = new URLSearchParams()\n\t\tif (types) for (const type of types) qs.append(\"type\", type)\n\t\tconst response: ModulesAPI.ListResponse = await apiFetcher.get(`/modules/v1/modules/?${qs.toString()}`, {\n\t\t\tprojectId: this.projectId,\n\t\t})\n\t\treturn response\n\t}\n\n\tasync listKits(): Promise<ModulesAPI.KitsResponse> {\n\t\tconst response: ModulesAPI.KitsResponse = await apiFetcher.get(`/modules/v1/kits/`, {\n\t\t\tprojectId: this.projectId,\n\t\t})\n\t\treturn response\n\t}\n\n\tasync listNamespaces(): Promise<ModulesAPI.ListNamespacesResponse> {\n\t\tconst response: ModulesAPI.ListNamespacesResponse = await apiFetcher.get(\"/modules/v1/namespaces/\")\n\t\treturn response\n\t}\n\n\tasync createNamespace(request: ModulesAPI.CreateNamespaceRequest): Promise<ModulesAPI.Namespace> {\n\t\tconst response: ModulesAPI.Namespace = await apiFetcher.post(\"/modules/v1/namespaces/\", request)\n\t\treturn response\n\t}\n\n\tasync listPublishedModules({\n\t\tnamespace,\n\t}: ModulesAPI.ListPublishedModulesRequest): Promise<ModulesAPI.ListPublishedModulesResponse> {\n\t\tconst endpoint = `/modules/v1/modules/namespaces/${encodeURIComponent(namespace)}/published/`\n\t\tconst response: ModulesAPI.ListPublishedModulesResponse = await apiFetcher.get(endpoint)\n\t\treturn response\n\t}\n\n\tasync lookUpModules(req: ModulesAPI.LookupRequest): Promise<ModulesAPI.LookupResponse> {\n\t\t// See https://github.com/framer/FramerModulesService/pull/962\n\t\tconst query = isModulesInTreeOn() ? \"?respectIncludeStatus=true\" : \"\"\n\t\treturn apiFetcher.post(`/modules/v1/modules/batch/lookup/${query}`, req)\n\t}\n\n\tasync publishModule({ namespace, name, ...body }: ModulesAPI.PublishRequest): Promise<ModulesAPI.Publish> {\n\t\tconst endpoint = `/modules/v1/namespaces/${encodeURIComponent(namespace)}/published/${encodeURIComponent(name)}`\n\t\tconst publish: ModulesAPI.Publish = await apiFetcher.post(endpoint, body)\n\t\treturn publish\n\t}\n\n\tasync updateModule({ moduleId, ...changes }: ModulesAPI.UpdateRequest): Promise<ModulesAPI.ModuleWithSave> {\n\t\tconst module: ModulesAPI.ModuleWithSave = await apiFetcher.post(\n\t\t\t`/modules/v1/modules/${moduleId}${this.modulesCopyOnWriteParam()}`,\n\t\t\tchanges,\n\t\t)\n\t\treturn module\n\t}\n\n\tasync saveModule(req: ModulesAPI.SaveRequest): Promise<ModulesAPI.ModuleWithSave> {\n\t\tconst body = new FormData()\n\t\tawait this.addModuleRequestToForm(req, body)\n\t\tconst module = await apiFetcher\n\t\t\t.postRaw(`/modules/v1/modules/${req.moduleId}/saves/${this.modulesCopyOnWriteParam()}`, body)\n\t\t\t.then(r => r.json() as Promise<ModulesAPI.ModuleWithSave>)\n\t\treturn module\n\t}\n\n\tasync saveModules({ batch, copyOnWrite }: SaveModulesRequest): Promise<ModulesAPI.ListResponse> {\n\t\tconst body = new FormData()\n\t\tawait Promise.all(batch.map(req => this.addModuleRequestToForm(req, body)))\n\t\tconst response = await apiFetcher\n\t\t\t.postRaw(`/modules/v1/modules/batch/saves/${this.modulesCopyOnWriteParam(copyOnWrite)}`, body)\n\t\t\t.then(r => r.json() as Promise<ModulesAPI.ListResponse>)\n\t\treturn response\n\t}\n\n\tprivate async addModuleRequestToForm(\n\t\treq: ModulesAPI.BatchSave | ModulesAPI.CreateRequest | ModulesAPI.SaveRequest,\n\t\tform: FormData,\n\t) {\n\t\tconst { files, ...metadata } = req\n\t\t// Determine which index we're adding based on the current number of metadata values.\n\t\tconst i = form.getAll(\"metadata\").length\n\t\t// Set transfer encoding if browser supports it.\n\t\tif (useCompressionStream && window.CompressionStream) {\n\t\t\tmetadata.transferEncoding = \"gzip\"\n\t\t}\n\t\t// Add the metadata (everything except the file contents).\n\t\tform.append(\n\t\t\t\"metadata\",\n\t\t\tJSON.stringify({\n\t\t\t\t...metadata,\n\t\t\t\tprojectId: this.projectId,\n\t\t\t\tfiles: files.map(({ content: _content, bytes: _bytes, ...info }) => info),\n\t\t\t}),\n\t\t)\n\t\t// Attach the files as individual form entries.\n\t\tawait Promise.all(\n\t\t\tfiles.map(async file => {\n\t\t\t\tconst content = file.content ?? file.bytes\n\t\t\t\tassert(!isUndefined(content), \"File needs content or bytes\")\n\n\t\t\t\tlet blob = new Blob([content])\n\t\t\t\tif (useCompressionStream && window.CompressionStream) {\n\t\t\t\t\tconst cs = new window.CompressionStream(\"gzip\")\n\t\t\t\t\tconst stream = blob.stream() as unknown as ReadableStream\n\t\t\t\t\tblob = await new Response(stream.pipeThrough(cs)).blob()\n\t\t\t\t\tconst bytesSaved = content.length - blob.size\n\t\t\t\t\tconst percentSmaller = (bytesSaved / content.length) * 100\n\t\t\t\t\tlog.debug(\"Saved\", bytesSaved, \"bytes\", `(${percentSmaller.toFixed(1)}%)`, \"compressing\", file.name)\n\t\t\t\t}\n\n\t\t\t\tform.append(`files[${i}]`, new File([blob], file.name))\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate modulesCopyOnWriteParam(forceCopyOnWrite = false): string {\n\t\t// Modules in the tree present a unique problem when duplicating a project: the tree\n\t\t// references the source project's modules! To solve that, we've introduced \"copy on write\"\n\t\t// semantics: the first time you make a mutating request to a module that doesn't belong to\n\t\t// us (specifically, the project ID given in the query param), we'll instead \"redirect\" that\n\t\t// request to our own copy of the module.\n\t\treturn forceCopyOnWrite || isModulesInTreeOn() ? `?copyOnWrite=${this.projectId}` : \"\"\n\t}\n\n\tasync enqueueKitScreenshots(request: ModulesAPI.EnqueueKitScreenshotsRequest): Promise<void> {\n\t\tconst body = new FormData()\n\n\t\t// Compress section page content when supported to reduce upload size.\n\t\tlet file: File | undefined\n\t\tif (useCompressionStream && window.CompressionStream) {\n\t\t\tconst cs = new window.CompressionStream(\"gzip\")\n\t\t\tconst rawReadable = new Response(request.kitPageContent).body\n\t\t\tassert(rawReadable, \"Section page content body is not readable\")\n\t\t\tconst blob = await new Response(rawReadable.pipeThrough(cs)).blob()\n\t\t\tfile = new File([blob], \"kitPage.html.gz\", { type: \"application/gzip\" })\n\t\t} else {\n\t\t\tfile = new File([request.kitPageContent], \"kitPage.html\", { type: \"text/html; charset=utf-8\" })\n\t\t}\n\n\t\tbody.append(\"sectionPage\", file)\n\t\tbody.append(\"sectionIds\", JSON.stringify(request.ids))\n\t\t// If we aren't generating for a specific saveId, then request draft screenshots.\n\t\tawait apiFetcher.postRaw(\n\t\t\t`/modules/v1/modules/${request.moduleId}/saves/${request.saveId ?? \"draft\"}/kit-screenshots/`,\n\t\t\tbody,\n\t\t)\n\t\treturn\n\t}\n\n\tasync requestAgentScreenshot(request: { url: string; selectors: string[]; theme: \"light\" | \"dark\" }): Promise<{\n\t\tresults: Record<\n\t\t\tstring,\n\t\t\t{ url: string } | { error: { code: string; message: string } } | { error: { code: string; message: string } }\n\t\t>\n\t}> {\n\t\treturn apiFetcher.post(\"/web/agents/screenshot\", request)\n\t}\n\n\t// Project code files\n\n\tasync getFileList(): Promise<Response> {\n\t\treturn apiFetcher.getRaw(`/web/vekter/projects/${this.projectId}/files`)\n\t}\n\n\tasync getFile(path: string): Promise<Response> {\n\t\treturn apiFetcher.getRaw(`/web/vekter/projects/${this.projectId}/files/${path}`)\n\t}\n\n\tasync saveFile(path: string, content: string): Promise<Response> {\n\t\tconst body = new FormData()\n\t\tconst file = new File([content], path, { type: \"text/plain\" })\n\t\tbody.set(\"file\", file)\n\t\t// We do not pass the multipart/form-data content type here, because it will be\n\t\t// filled in by the browser and contain the multipart boundary\n\t\treturn apiFetcher.postRaw(`/web/vekter/projects/${this.projectId}/files/${path}`, body, undefined)\n\t}\n\n\tasync deleteFile(path: string): Promise<Response> {\n\t\treturn apiFetcher.deleteRaw(`/web/vekter/projects/${this.projectId}/files/${path}`)\n\t}\n\n\t// Build output\n\n\tasync getBuildOutput(path: string): Promise<Response> {\n\t\treturn apiFetcher.getRaw(`/web/projects/${this.projectId}/files/${path}`)\n\t}\n\n\t// Packages\n\n\tprivate packagesPerPage = 36\n\n\tasync getPackage(options: { fromPublicPackages: boolean; packageName: string }) {\n\t\tconst { fromPublicPackages, packageName } = options\n\t\treturn apiFetcher.get(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/${packageName}`)\n\t}\n\n\tasync deletePackage(options: { fromPublicPackages: boolean; packageName: string }) {\n\t\tconst { fromPublicPackages, packageName } = options\n\t\tawait apiFetcher.deleteRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/${packageName}`)\n\t}\n\n\tasync getPackageVersionStatus(options: { isPrivate: boolean; packageName: string; version: string }) {\n\t\tconst { isPrivate, packageName, version } = options\n\t\treturn apiFetcher.get(`/store/packages${isPrivate ? \"/private\" : \"\"}/${packageName}/version/${version}`)\n\t}\n\n\tasync preflightPackage(options: { fromPublicPackages: boolean; body: object }) {\n\t\tconst { fromPublicPackages, body } = options\n\t\treturn apiFetcher.post(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/preflight`, body)\n\t}\n\n\tasync findPackage(options: { fromPublicPackages: boolean; friendlyName: string; spaceId?: string }) {\n\t\tconst { fromPublicPackages, friendlyName, spaceId } = options\n\t\treturn apiFetcher.getRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/find-by-slugify`, {\n\t\t\tname: friendlyName,\n\t\t\tspaceId,\n\t\t})\n\t}\n\n\tasync findPackages(options: {\n\t\tfromPublicPackages: boolean\n\t\tquery: string\n\t\toffset: number\n\t\tspaceIds?: readonly string[]\n\t}) {\n\t\tconst { fromPublicPackages, query, offset, spaceIds } = options\n\t\treturn apiFetcher.getRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/search`, {\n\t\t\tquery,\n\t\t\toffset,\n\t\t\tlimit: this.packagesPerPage,\n\t\t\tspaceIds,\n\t\t})\n\t}\n\n\tasync favoritePackage(options: { fromPublicPackages: boolean; packageName: string }) {\n\t\tconst { fromPublicPackages, packageName } = options\n\t\treturn apiFetcher.postRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/${packageName}/favorite`)\n\t}\n\n\tasync unfavoritePackage(options: { fromPublicPackages: boolean; packageName: string }) {\n\t\tconst { fromPublicPackages, packageName } = options\n\t\treturn apiFetcher.deleteRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/${packageName}/favorite`)\n\t}\n\n\tasync getPackages(options: {\n\t\tfromPublicPackages: boolean\n\t\tsection?: string\n\t\toffset: number\n\t\tspaceIds?: readonly string[]\n\t}) {\n\t\tconst { fromPublicPackages, section, offset, spaceIds } = options\n\t\treturn apiFetcher.getRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/${section ? section : \"\"}`, {\n\t\t\toffset,\n\t\t\tlimit: this.packagesPerPage,\n\t\t\tspaceIds,\n\t\t})\n\t}\n\n\tasync getPopularPackages(options: {\n\t\tfromPublicPackages: boolean\n\t\toffset: number\n\t\tdays: number\n\t\tspaceIds?: readonly string[]\n\t}) {\n\t\tconst { fromPublicPackages, offset, days, spaceIds } = options\n\t\treturn apiFetcher.getRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/popular`, {\n\t\t\toffset,\n\t\t\tdays,\n\t\t\tlimit: this.packagesPerPage,\n\t\t\tspaceIds,\n\t\t})\n\t}\n\n\tasync getFeaturedPackages(options: { fromPublicPackages: boolean; offset: number }) {\n\t\tconst { fromPublicPackages, offset } = options\n\t\treturn apiFetcher.getRaw(`/store/packages${fromPublicPackages ? \"\" : \"/private\"}/`, {\n\t\t\tfeatured: true,\n\t\t\toffset,\n\t\t\tlimit: this.packagesPerPage,\n\t\t})\n\t}\n\n\t// NOTE: Only for public packages\n\tasync getPublisherPackages(options: { publisherId: string; offset: number }) {\n\t\tconst { publisherId, offset } = options\n\t\treturn apiFetcher.getRaw(`/store/packages/published-by/${publisherId}`, {\n\t\t\toffset,\n\t\t\tlimit: this.packagesPerPage,\n\t\t})\n\t}\n\n\t// NOTE: Only for public packages\n\tasync getTrendingPackages() {\n\t\treturn apiFetcher.getRaw(\"/store/packages/trending\")\n\t}\n\n\tasync getPackagesMetadata(options: { packageNames: readonly string[] }) {\n\t\treturn apiFetcher.post(\"/store/meta/get-many\", options)\n\t}\n\n\t// Unsplash\n\n\tasync listPhotos(options: { page?: number; per_page?: number; order_by?: \"latest\" | \"oldest\" | \"popular\" }) {\n\t\treturn apiFetcher.get(\"/web/unsplash/photos\", options)\n\t}\n\n\tasync searchPhotos(options: {\n\t\tquery: string\n\t\tpage?: number\n\t\tper_page?: number\n\t\torientation?: \"landscape\" | \"portrait\" | \"squarish\"\n\t}) {\n\t\treturn apiFetcher.get(\"/web/unsplash/search/photos\", options)\n\t}\n\n\tasync getRandomPhoto(options: { query?: string }) {\n\t\treturn apiFetcher.get(\"/web/unsplash/photos/random\", options)\n\t}\n\n\tasync downloadPhoto(options: { id: string }) {\n\t\treturn apiFetcher.get(`/web/unsplash/photos/${options.id}/download`)\n\t}\n\n\tasync checkControlRequest(): Promise<{ accountSharing: boolean }> {\n\t\treturn apiFetcher.get(\"/auth/analysis/account-sharing\")\n\t}\n\n\tasync takeControl(options: { token?: string }): Promise<void> {\n\t\treturn apiFetcher.post(\"/auth/analysis/account-sharing/take-control\", options)\n\t}\n\n\t/** Registers user-scoped chat attachment keys with the project after the agent applies them on the canvas. */\n\tasync linkUserAttachmentAssetToProject(assetKey: string): Promise<void> {\n\t\tconst response = await apiFetcher.post(`/web/projects/${this.projectId}/assets/duplicate-from-user`, {\n\t\t\tkeys: [assetKey],\n\t\t})\n\t\tif (response) {\n\t\t\tthis.notifyProjectChange(\"assets\")\n\t\t}\n\t}\n\n\t// Helpers\n\n\tprivate notifyProjectChange(scope: ProjectChangeScope) {\n\t\tthis.socket.send({ type: \"notifyProjectChange\", value: { scope } })\n\t}\n}\n\nexport function useAPI(socket: Socket, state: LoadingProjectState, dispatch: ProjectDispatch): API {\n\tconst api = useMemo(() => {\n\t\treturn new API(socket, state.projectId, dispatch)\n\t}, [socket, state.projectId, dispatch])\n\n\t// Fetch the ACL list on startup.\n\tuseEffect(() => {\n\t\tapi.getACL()\n\t}, [api])\n\n\t// Watch for unknown users joining.\n\tconst stateRef = useRef(state)\n\tstateRef.current = state\n\tuseEffect(() => {\n\t\treturn socket.onMessage(message => {\n\t\t\tconst state = stateRef.current\n\t\t\tif (message.type === \"join\") {\n\t\t\t\tif (state.aclById[message.id]) return\n\t\t\t} else if (message.type === \"welcome\") {\n\t\t\t\t// If the current ACL is empty we can expect it to come in soon.\n\t\t\t\tif (state.acl.length === 0) return\n\t\t\t\t// This is a reconnect, so we need to check the active users list.\n\t\t\t\tlet containsMissingId = false\n\t\t\t\tfor (const id of state.activeIds) {\n\t\t\t\t\tif (state.aclById[id]) continue\n\t\t\t\t\tcontainsMissingId = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif (!containsMissingId) return\n\t\t\t\t// At least one of the active users is not in the cached ACL list.\n\t\t\t} else {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// At least one user is not in the cached ACL \u2013 request it again.\n\t\t\tapi.getACL()\n\t\t})\n\t}, [api, socket])\n\n\treturn api\n}\n", "import type { ToastIcon, ToasterAction } from \"@framerjs/fresco\"\nimport { apiFetcher } from \"./apiFetcher.ts\"\n\ntype OnToastCallback = (value: Extract<ToasterAction, { type: \"add\" }>) => void\n\n/**\n * Note: Unlike the uploadWithToast, this function throws on error.\n */\nexport async function uploadAssetByUrlWithToast<R>(\n\tendpoint: string,\n\turl: string,\n\ticon: ToastIcon,\n\tonToast: OnToastCallback,\n): Promise<R> {\n\tconst key = `upload${Math.random()}`\n\n\t// TODO the endpoint should return errors for files that are to large\n\n\ttry {\n\t\tonToast({\n\t\t\ttype: \"add\",\n\t\t\tkey,\n\t\t\tvariant: \"progress\",\n\t\t\ticon,\n\t\t\tprimaryText: \"Uploading remote file\u2026\",\n\t\t\tduration: Infinity,\n\t\t\tshowCloseButton: \"never\",\n\t\t})\n\t\tconst info = await apiFetcher.post(endpoint, { url })\n\t\tonToast({\n\t\t\ttype: \"add\",\n\t\t\tkey,\n\t\t\tvariant: \"success\",\n\t\t\tprimaryText: \"Your file\",\n\t\t\tsecondaryText: \"has been uploaded.\",\n\t\t\tduration: 10000,\n\t\t\ticon: \"success\",\n\t\t\tmoveToTop: true,\n\t\t})\n\t\treturn info\n\t} catch (error) {\n\t\tonToast({\n\t\t\ttype: \"add\",\n\t\t\tkey,\n\t\t\tvariant: \"error\",\n\t\t\tprimaryText: \"Error uploading file.\",\n\t\t\tsecondaryText: \"Please try again.\",\n\t\t\tduration: 30000,\n\t\t\ticon: \"error\",\n\t\t\tmoveToTop: true,\n\t\t})\n\t\tthrow error\n\t}\n}\n", "import { accessTokenRefresher } from \"./accessTokenRefresherWeb.ts\"\n\n/**\n * Supplies the subprotocols for the Multiplayer Service WebSocket: the JWT\n * access token is passed as the second subprotocol alongside the\n * `framer.bearer.v1` scheme marker. Re-resolved on every (re)connect so expired\n * tokens are refreshed transparently.\n */\nexport async function getMultiplayerServiceSubprotocols(): Promise<string[] | undefined> {\n\tconst accessToken = await accessTokenRefresher.getAccessToken()\n\tif (!accessToken) return undefined\n\treturn [\"framer.bearer.v1\", accessToken]\n}\n", "import { getServiceMap } from \"@framerjs/framer-environment/domains.ts\"\n\nexport function getSocketURL(projectId: string) {\n\tconst services = getServiceMap()\n\tconst socketURL = new URL(services.app)\n\tsocketURL.protocol = socketURL.protocol === \"http:\" ? \"ws:\" : \"wss:\"\n\tsocketURL.pathname = `/projects/${projectId}/socket`\n\treturn socketURL.href\n}\n"],
  "mappings": "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",
  "names": ["import_react", "state"]
}
