diff --git a/src/puter-js/README.md b/src/puter-js/README.md
index f314ede0..8167449c 100644
--- a/src/puter-js/README.md
+++ b/src/puter-js/README.md
@@ -15,7 +15,7 @@ npm install @heyputer/puter.js
#### ES Modules
```js
-import puter from '@heyputer/puterjs';
+import '@heyputer/puter.js';
```
#### CommonJS
@@ -34,6 +34,8 @@ Include Puter.js directly in your HTML via CDN in the `
` section:
## Usage Example
+After importing, you can use the global `puter` object:
+
```js
// Print a message
puter.print('Hello from Puter.js!');
diff --git a/src/puter-js/index.d.ts b/src/puter-js/index.d.ts
new file mode 100644
index 00000000..72c452cc
--- /dev/null
+++ b/src/puter-js/index.d.ts
@@ -0,0 +1,479 @@
+declare global {
+ interface Window {
+ puter: Puter;
+ }
+}
+
+declare namespace Puter {
+ // Main Puter interface
+ interface Puter {
+ // Properties
+ appID: string;
+ env: 'app' | 'web' | 'gui';
+
+ // Utility methods
+ print(text: string, options?: { code?: boolean }): void;
+ randName(separator?: string): string;
+ exit(statusCode?: number): void;
+
+ // Sub-modules
+ ai: AI;
+ apps: Apps;
+ auth: Auth;
+ drivers: Drivers;
+ fs: FileSystem;
+ hosting: Hosting;
+ kv: KeyValue;
+ net: Networking;
+ perms: Permissions;
+ ui: UI;
+ workers: Workers;
+ }
+
+ // AI Module
+ interface AI {
+ chat(prompt: string, options?: ChatOptions): Promise;
+ chat(prompt: string, testMode?: boolean, options?: ChatOptions): Promise;
+ chat(prompt: string, imageURL?: string, testMode?: boolean, options?: ChatOptions): Promise;
+ chat(prompt: string, imageURLArray?: string[], testMode?: boolean, options?: ChatOptions): Promise;
+ chat(messages: ChatMessage[], testMode?: boolean, options?: ChatOptions): Promise;
+
+ img2txt(image: string | File | Blob, testMode?: boolean): Promise;
+
+ txt2img(prompt: string, testMode?: boolean): Promise;
+ txt2img(prompt: string, options?: Txt2ImgOptions): Promise;
+
+ txt2speech(text: string): Promise;
+ txt2speech(text: string, options?: Txt2SpeechOptions): Promise;
+ txt2speech(text: string, language?: string): Promise;
+ txt2speech(text: string, language?: string, voice?: string): Promise;
+ txt2speech(text: string, language?: string, voice?: string, engine?: string): Promise;
+ }
+
+ interface ChatOptions {
+ model?: string;
+ stream?: boolean;
+ max_tokens?: number;
+ temperature?: number;
+ tools?: ToolDefinition[];
+ }
+
+ interface ToolDefinition {
+ type: 'function';
+ function: {
+ name: string;
+ description: string;
+ parameters: object;
+ strict?: boolean;
+ };
+ }
+
+ interface ChatMessage {
+ role: 'system' | 'assistant' | 'user' | 'function' | 'tool';
+ content: string | ContentObject[];
+ tool_call_id?: string;
+ }
+
+ interface ContentObject {
+ type: 'text' | 'file';
+ text?: string;
+ puter_path?: string;
+ }
+
+ interface ChatResponse {
+ message: {
+ role: string;
+ content: string;
+ tool_calls?: ToolCall[];
+ };
+ }
+
+ interface ToolCall {
+ id: string;
+ function: {
+ name: string;
+ arguments: string;
+ };
+ }
+
+ interface Txt2ImgOptions {
+ model?: 'gpt-image-1' | 'gemini-2.5-flash-image-preview' | 'dall-e-3';
+ quality?: 'high' | 'medium' | 'low' | 'hd' | 'standard';
+ input_image?: string;
+ input_image_mime_type?: string;
+ }
+
+ interface Txt2SpeechOptions {
+ language?: string;
+ voice?: string;
+ engine?: 'standard' | 'neural' | 'generative';
+ }
+
+ // Apps Module
+ interface Apps {
+ create(name: string, indexURL: string): Promise;
+ create(name: string, indexURL: string, title?: string): Promise;
+ create(name: string, indexURL: string, title?: string, description?: string): Promise;
+ create(options: CreateAppOptions): Promise;
+
+ delete(name: string): Promise;
+ get(name: string, options?: GetAppOptions): Promise;
+ list(options?: ListAppOptions): Promise;
+ update(name: string, attributes: UpdateAppAttributes): Promise;
+ }
+
+ interface CreateAppOptions {
+ name: string;
+ indexURL: string;
+ title?: string;
+ description?: string;
+ icon?: string;
+ maximizeOnStart?: boolean;
+ filetypeAssociations?: string[];
+ }
+
+ interface GetAppOptions {
+ stats_period?: StatsPeriod;
+ icon_size?: null | 16 | 32 | 64 | 128 | 256 | 512;
+ }
+
+ interface ListAppOptions extends GetAppOptions { }
+
+ interface UpdateAppAttributes {
+ name?: string;
+ indexURL?: string;
+ title?: string;
+ description?: string;
+ icon?: string;
+ maximizeOnStart?: boolean;
+ filetypeAssociations?: string[];
+ }
+
+ type StatsPeriod = 'all' | 'today' | 'yesterday' | '7d' | '30d' | 'this_month' | 'last_month' | 'this_year' | 'last_year' | 'month_to_date' | 'year_to_date' | 'last_12_months';
+
+ interface App {
+ uid: string;
+ name: string;
+ icon: string;
+ description: string;
+ title: string;
+ maximize_on_start: boolean;
+ index_url: string;
+ created_at: string;
+ background: boolean;
+ filetype_associations: string[];
+ open_count: number;
+ user_count: number;
+ }
+
+ // Auth Module
+ interface Auth {
+ signIn(options?: { attempt_temp_user_creation?: boolean }): Promise;
+ signOut(): void;
+ isSignedIn(): boolean;
+ getUser(): Promise;
+ }
+
+ interface User {
+ uuid: string;
+ username: string;
+ email_confirmed: boolean;
+ }
+
+ // Drivers Module
+ interface Drivers {
+ call(interface: string, driver: string, method: string, args?: object): Promise;
+ }
+
+ // FileSystem Module
+ interface FileSystem {
+ copy(source: string, destination: string, options?: CopyOptions): Promise;
+ delete(path: string, options?: DeleteOptions): Promise;
+ getReadURL(path: string, expiresIn?: number): Promise;
+ mkdir(path: string, options?: MkdirOptions): Promise;
+ move(source: string, destination: string, options?: MoveOptions): Promise;
+ read(path: string, options?: ReadOptions): Promise;
+ readdir(path: string, options?: ReaddirOptions): Promise;
+ readdir(options?: ReaddirOptions): Promise;
+ rename(path: string, newName: string): Promise;
+ space(): Promise;
+ stat(path: string): Promise;
+ upload(items: FileList | File[] | Blob[], dirPath?: string, options?: object): Promise;
+ write(path: string, data?: string | File | Blob, options?: WriteOptions): Promise;
+ }
+
+ interface CopyOptions {
+ overwrite?: boolean;
+ dedupeName?: boolean;
+ newName?: string;
+ }
+
+ interface DeleteOptions {
+ recursive?: boolean;
+ descendantsOnly?: boolean;
+ }
+
+ interface MkdirOptions {
+ overwrite?: boolean;
+ dedupeName?: boolean;
+ createMissingParents?: boolean;
+ }
+
+ interface MoveOptions extends CopyOptions {
+ createMissingParents?: boolean;
+ }
+
+ interface ReadOptions {
+ offset?: number;
+ byte_count?: number;
+ }
+
+ interface ReaddirOptions {
+ path?: string;
+ uid?: string;
+ }
+
+ interface WriteOptions {
+ overwrite?: boolean;
+ dedupeName?: boolean;
+ createMissingParents?: boolean;
+ }
+
+ interface SpaceInfo {
+ capacity: number;
+ used: number;
+ }
+
+ interface FSItem {
+ id: string;
+ uid: string;
+ name: string;
+ path: string;
+ is_dir: boolean;
+ parent_id: string;
+ parent_uid: string;
+ created: number;
+ modified: number;
+ accessed: number;
+ size: number | null;
+ writable: boolean;
+ read(): Promise;
+ readdir(): Promise;
+ }
+
+ // Hosting Module
+ interface Hosting {
+ create(subdomain: string, dirPath?: string): Promise;
+ delete(subdomain: string): Promise;
+ get(subdomain: string): Promise;
+ list(): Promise;
+ update(subdomain: string, dirPath?: string): Promise;
+ }
+
+ interface Subdomain {
+ uid: string;
+ subdomain: string;
+ root_dir: FSItem;
+ }
+
+ // KeyValue Module
+ interface KeyValue {
+ set(key: string, value: string | number | boolean | object | any[]): Promise;
+ get(key: string): Promise;
+ del(key: string): Promise;
+ incr(key: string, amount?: number): Promise;
+ decr(key: string, amount?: number): Promise;
+ list(pattern?: string, returnValues?: boolean): Promise;
+ list(returnValues?: boolean): Promise;
+ flush(): Promise;
+ }
+
+ interface KeyValuePair {
+ key: string;
+ value: any;
+ }
+
+ // Networking Module
+ interface Networking {
+ fetch(url: string, options?: RequestInit): Promise;
+ Socket: typeof Socket;
+ tls: {
+ TLSSocket: typeof TLSSocket;
+ };
+ }
+
+ class Socket {
+ constructor(hostname: string, port: number);
+ write(data: ArrayBuffer | Uint8Array | string): void;
+ close(): void;
+ on(event: 'open', callback: () => void): void;
+ on(event: 'data', callback: (buffer: Uint8Array) => void): void;
+ on(event: 'error', callback: (reason: string) => void): void;
+ on(event: 'close', callback: (hadError: boolean) => void): void;
+ }
+
+ class TLSSocket extends Socket {
+ constructor(hostname: string, port: number);
+ }
+
+ // Permissions Module
+ interface Permissions {
+ grantApp(app_uid: string, permissionString: string): Promise;
+ grantAppAnyUser(app_uid: string, permissionString: string): Promise;
+ grantGroup(group_uid: string, permissionString: string): Promise;
+ grantOrigin(origin: string, permissionString: string): Promise;
+ grantUser(username: string, permissionString: string): Promise;
+ revokeApp(app_uid: string, permissionString: string): Promise;
+ revokeAppAnyUser(app_uid: string, permissionString: string): Promise;
+ revokeGroup(group_uid: string, permissionString: string): Promise;
+ revokeOrigin(origin: string, permissionString: string): Promise;
+ revokeUser(username: string, permissionString: string): Promise;
+ }
+
+ // UI Module
+ interface UI {
+ alert(message?: string, buttons?: AlertButton[]): Promise;
+ prompt(message?: string, defaultValue?: string): Promise;
+ authenticateWithPuter(): Promise;
+ contextMenu(options: ContextMenuOptions): void;
+ createWindow(options?: WindowOptions): void;
+ exit(statusCode?: number): void;
+ getLanguage(): Promise;
+ hideSpinner(): void;
+ launchApp(appName?: string, args?: object): Promise;
+ launchApp(options: LaunchAppOptions): Promise;
+ on(eventName: 'localeChanged', handler: (data: { language: string }) => void): void;
+ on(eventName: 'themeChanged', handler: (data: ThemeData) => void): void;
+ onItemsOpened(handler: (items: FSItem[]) => void): void;
+ onLaunchedWithItems(handler: (items: FSItem[]) => void): void;
+ onWindowClose(handler: () => void): void;
+ parentApp(): AppConnection | null;
+ setMenubar(options: MenubarOptions): void;
+ setWindowHeight(height: number): void;
+ setWindowPosition(x: number, y: number): void;
+ setWindowSize(width: number, height: number): void;
+ setWindowTitle(title: string): void;
+ setWindowWidth(width: number): void;
+ setWindowX(x: number): void;
+ setWindowY(y: number): void;
+ showColorPicker(defaultColor?: string): Promise;
+ showColorPicker(options?: object): Promise;
+ showDirectoryPicker(options?: { multiple?: boolean }): Promise;
+ showFontPicker(defaultFont?: string): Promise<{ fontFamily: string }>;
+ showFontPicker(options?: object): Promise<{ fontFamily: string }>;
+ showOpenFilePicker(options?: FilePickerOptions): Promise;
+ showSaveFilePicker(data?: any, defaultFileName?: string): Promise;
+ showSpinner(): void;
+ socialShare(url: string, message?: string, options?: { left?: number; top?: number }): void;
+ wasLaunchedWithItems(): boolean;
+ }
+
+ interface AlertButton {
+ label: string;
+ value?: string;
+ type?: 'primary' | 'success' | 'info' | 'warning' | 'danger';
+ }
+
+ interface ContextMenuOptions {
+ items: (ContextMenuItem | '-')[];
+ }
+
+ interface ContextMenuItem {
+ label: string;
+ action?: () => void;
+ icon?: string;
+ icon_active?: string;
+ disabled?: boolean;
+ items?: (ContextMenuItem | '-')[];
+ }
+
+ interface WindowOptions {
+ center?: boolean;
+ content?: string;
+ disable_parent_window?: boolean;
+ has_head?: boolean;
+ height?: number;
+ is_resizable?: boolean;
+ show_in_taskbar?: boolean;
+ title?: string;
+ width?: number;
+ }
+
+ interface LaunchAppOptions {
+ name?: string;
+ args?: object;
+ }
+
+ interface ThemeData {
+ palette: {
+ primaryHue: number;
+ primarySaturation: string;
+ primaryLightness: string;
+ primaryAlpha: number;
+ primaryColor: string;
+ };
+ }
+
+ interface MenubarOptions {
+ items: MenuItem[];
+ }
+
+ interface MenuItem {
+ label: string;
+ action?: () => void;
+ items?: MenuItem[];
+ }
+
+ interface FilePickerOptions {
+ multiple?: boolean;
+ accept?: string | string[];
+ }
+
+ interface AppConnection {
+ usesSDK: boolean;
+ on(eventName: 'message', handler: (message: any) => void): void;
+ on(eventName: 'close', handler: (data: { appInstanceID: string }) => void): void;
+ off(eventName: string, handler: Function): void;
+ postMessage(message: any): void;
+ close(): void;
+ }
+
+ // Workers Module
+ interface Workers {
+ create(workerName: string, filePath: string): Promise;
+ delete(workerName: string): Promise;
+ exec(workerURL: string, options?: WorkerExecOptions): Promise;
+ get(workerName: string): Promise;
+ list(): Promise;
+ }
+
+ interface WorkerDeployment {
+ success: boolean;
+ url: string;
+ errors: any[];
+ }
+
+ interface WorkerExecOptions extends RequestInit {
+ method?: string;
+ headers?: object;
+ body?: string | object;
+ cache?: RequestCache;
+ credentials?: RequestCredentials;
+ mode?: RequestMode;
+ redirect?: RequestRedirect;
+ referrer?: string;
+ signal?: AbortSignal;
+ }
+
+ interface WorkerInfo {
+ name: string;
+ url: string;
+ file_path: string;
+ file_uid: string;
+ created_at: string;
+ }
+}
+
+declare const puter: Puter.Puter;
+
+export = Puter;
\ No newline at end of file
diff --git a/src/puter-js/package.json b/src/puter-js/package.json
index 3b98559a..ba0a01c8 100644
--- a/src/puter-js/package.json
+++ b/src/puter-js/package.json
@@ -2,7 +2,13 @@
"name": "@heyputer/puterjs",
"version": "2.0.0",
"description": "Puter.js - A JavaScript library for interacting with Puter services.",
- "main": "index.js",
+ "main": "src/index.js",
+ "types": "index.d.ts",
+ "typings": "index.d.ts",
+ "files": [
+ "src/index.js",
+ "index.d.ts"
+ ],
"type": "module",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
@@ -11,13 +17,17 @@
"type": "git",
"url": "git+https://github.com/HeyPuter/puter.git"
},
+ "keywords": [
+ "puter",
+ "puter.js",
+ "puterjs"
+ ],
"scripts": {
"start-server": "npx http-server --cors -c-1",
"start-webpack": "webpack && webpack --output-filename puter.dev.js --watch --devtool source-map",
"start": "concurrently \"npm run start-server\" \"npm run start-webpack\"",
"build": "webpack && { echo \"// Copyright 2024-present Puter Technologies Inc. All rights reserved.\"; echo \"// Generated on $(date '+%Y-%m-%d %H:%M')\n\"; cat ./dist/puter.js; } > temp && mv temp ./dist/puter.js"
},
- "keywords": [],
"author": "Puter Technologies Inc.",
"license": "Apache-2.0",
"devDependencies": {
@@ -25,6 +35,7 @@
"webpack-cli": "^5.1.4"
},
"dependencies": {
- "@heyputer/kv.js": "^0.1.92"
+ "@heyputer/kv.js": "^0.1.92",
+ "@heyputer/putility": "^1.0.3"
}
}
\ No newline at end of file
diff --git a/src/puter-js/webpack.config.js b/src/puter-js/webpack.config.js
index 1eb4bd18..bacc727b 100644
--- a/src/puter-js/webpack.config.js
+++ b/src/puter-js/webpack.config.js
@@ -11,15 +11,15 @@ import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default {
- entry: './src/index.js',
- output: {
- filename: 'puter.js',
- path: path.resolve(__dirname, 'dist'),
- },
- plugins: [
- new webpack.DefinePlugin({
- 'globalThis.PUTER_ORIGIN': JSON.stringify(process.env.PUTER_ORIGIN || 'https://puter.com'),
- 'globalThis.PUTER_API_ORIGIN': JSON.stringify(process.env.PUTER_API_ORIGIN || 'https://api.puter.com'),
- }),
- ],
+ entry: './src/index.js',
+ output: {
+ filename: 'puter.js',
+ path: path.resolve(__dirname, 'dist'),
+ },
+ plugins: [
+ new webpack.DefinePlugin({
+ 'globalThis.PUTER_ORIGIN': JSON.stringify(process.env.PUTER_ORIGIN || 'https://puter.com'),
+ 'globalThis.PUTER_API_ORIGIN': JSON.stringify(process.env.PUTER_API_ORIGIN || 'https://api.puter.com'),
+ }),
+ ],
};
diff --git a/src/putility/package.json b/src/putility/package.json
index 8be27008..ec2eda38 100644
--- a/src/putility/package.json
+++ b/src/putility/package.json
@@ -1,6 +1,6 @@
{
"name": "@heyputer/putility",
- "version": "1.0.2",
+ "version": "1.0.3",
"description": "",
"main": "index.js",
"scripts": {
@@ -10,4 +10,4 @@
},
"author": "Puter Technologies Inc.",
"license": "AGPL-3.0-only"
-}
+}
\ No newline at end of file
diff --git a/src/putility/src/system/ServiceManager.js b/src/putility/src/system/ServiceManager.js
index 038ff4bf..8cf24b92 100644
--- a/src/putility/src/system/ServiceManager.js
+++ b/src/putility/src/system/ServiceManager.js
@@ -1,60 +1,33 @@
/*
* Copyright (C) 2024-present Puter Technologies Inc.
- *
+ *
* This file is part of Puter.
- *
+ *
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-const { AdvancedBase } = require("../AdvancedBase");
-const { TService } = require("../concepts/Service");
-const { TeePromise } = require("../libs/promise");
-
-const mkstatus = name => {
- const c = class {
- get label () { return name }
- describe () { return name }
- }
- c.name = `Status${
- name[0].toUpperCase() + name.slice(1)
- }`
- return c;
-}
+const { AdvancedBase } = require('../AdvancedBase');
+const { TService } = require('../concepts/Service');
+const StatusEnum = {
+ Registering: 'registering',
+ Pending: 'pending',
+ Initializing: 'initializing',
+ Running: 'running',
+};
class ServiceManager extends AdvancedBase {
- static StatusRegistering = mkstatus('registering');
- static StatusPending = class StatusPending {
- constructor ({ waiting_for }) {
- this.waiting_for = waiting_for;
- }
- get label () { return 'waiting'; }
- // TODO: trait?
- describe () {
- return `waiting for: ${this.waiting_for.join(', ')}`
- }
- }
- static StatusInitializing = mkstatus('initializing');
- static StatusRunning = class StatusRunning {
- constructor ({ start_ts }) {
- this.start_ts = start_ts;
- }
- get label () { return 'running'; }
- describe () {
- return `running (since ${this.start_ts})`;
- }
- }
- constructor ({ context } = {}) {
+ constructor({ context } = {}) {
super();
this.context = context;
@@ -68,7 +41,7 @@ class ServiceManager extends AdvancedBase {
// initialized; mapped like: waiting_[dependency] = Set(dependents)
this.waiting_ = {};
}
- async register (name, factory, options = {}) {
+ async register(name, factory, options = {}) {
await new Promise(rslv => setTimeout(rslv, 0));
const ins = factory.create({
@@ -78,25 +51,25 @@ class ServiceManager extends AdvancedBase {
const entry = {
name,
instance: ins,
- status: new this.constructor.StatusRegistering(),
+ status: StatusEnum.Registering,
};
this.services_l_.push(entry);
this.services_m_[name] = entry;
await this.maybe_init_(name);
}
- info (name) {
+ info(name) {
return this.services_m_[name];
}
- get (name) {
+ get(name) {
const info = this.services_m_[name];
if ( ! info ) throw new Error(`Service not registered: ${name}`);
- if ( ! (info.status instanceof this.constructor.StatusRunning ) ) {
+ if ( info.status !== StatusEnum.Running ) {
return undefined;
}
return info.instance;
}
- async aget (name) {
+ async aget(name) {
await this.wait_for_init([name]);
return this.get(name);
}
@@ -105,7 +78,7 @@ class ServiceManager extends AdvancedBase {
* Wait for the specified list of services to be initialized.
* @param {*} depends - list of services to wait for
*/
- async wait_for_init (depends) {
+ async wait_for_init(depends) {
let check;
await new Promise(rslv => {
@@ -134,7 +107,7 @@ class ServiceManager extends AdvancedBase {
});
};
- get_waiting_for_ (depends) {
+ get_waiting_for_(depends) {
const waiting_for = [];
for ( const depend of depends ) {
const depend_entry = this.services_m_[depend];
@@ -142,14 +115,14 @@ class ServiceManager extends AdvancedBase {
waiting_for.push(depend);
continue;
}
- if ( ! (depend_entry.status instanceof this.constructor.StatusRunning) ) {
+ if ( ( depend_entry.status !== StatusEnum.Running ) ) {
waiting_for.push(depend);
}
}
return waiting_for;
}
- async maybe_init_ (name) {
+ async maybe_init_(name) {
const entry = this.services_m_[name];
const depends = entry.instance.as(TService).get_depends();
const waiting_for = this.get_waiting_for_(depends);
@@ -160,34 +133,33 @@ class ServiceManager extends AdvancedBase {
}
for ( const dependency of waiting_for ) {
- /** @type Set */
- const waiting_set = this.waiting_[dependency] ||
- (this.waiting_[dependency] = new Set());
- waiting_set.add(name);
+ if ( !this.waiting_[dependency] ) {
+ this.waiting_[dependency] = new Set();
+ }
+ this.waiting_[dependency].add(name);
}
- entry.status = new this.constructor.StatusPending(
- { waiting_for });
+ entry.status = StatusEnum.Pending;
+ entry.statusWaitingFor = waiting_for;
}
// called when a service has all of its dependencies initialized
// and is ready to be initialized itself
- async init_service_ (name, modifiers = {}) {
+ async init_service_(name, modifiers = {}) {
const entry = this.services_m_[name];
- entry.status = new this.constructor.StatusInitializing();
+ entry.status = StatusEnum.Initializing;
const service_impl = entry.instance.as(TService);
await service_impl.init();
- entry.status = new this.constructor.StatusRunning({
- start_ts: new Date(),
- });
+ entry.status = StatusEnum.Running;
+ entry.statusStartTS = new Date();
/** @type Set */
const maybe_ready_set = this.waiting_[name];
const promises = [];
if ( maybe_ready_set ) {
for ( const dependent of maybe_ready_set.values() ) {
promises.push(this.maybe_init_(dependent, {
- no_init_listeners: true
+ no_init_listeners: true,
}));
}
}