diff --git a/doc/contributors/extensions/events.json.js b/doc/contributors/extensions/events.json.js index 2f3c9a21e..82aaedf2f 100644 --- a/doc/contributors/extensions/events.json.js +++ b/doc/contributors/extensions/events.json.js @@ -1,4 +1,170 @@ export default [ + { + id: 'core.ai.prompt.check-usage', + description: ` + This event is emitted for ai prompt check usage operations. + `, + properties: { + allow: { + type: 'boolean', + mutability: 'mutable', + summary: 'whether the operation is allowed', + notes: [], + }, + intended_service: { + type: 'any', + mutability: 'mutable', + summary: 'intended service', + notes: [], + }, + parameters: { + type: 'any', + mutability: 'mutable', + summary: 'parameters', + notes: [], + } + }, + }, + { + id: 'core.ai.prompt.complete', + description: ` + This event is emitted for ai prompt complete operations. + `, + properties: { + username: { + type: 'string', + mutability: 'mutable', + summary: 'username', + notes: [], + }, + intended_service: { + type: 'any', + mutability: 'mutable', + summary: 'intended service', + notes: [], + }, + parameters: { + type: 'any', + mutability: 'mutable', + summary: 'parameters', + notes: [], + }, + result: { + type: 'any', + mutability: 'mutable', + summary: 'result', + notes: [], + }, + model_used: { + type: 'any', + mutability: 'mutable', + summary: 'model used', + notes: [], + }, + service_used: { + type: 'any', + mutability: 'mutable', + summary: 'service used', + notes: [], + } + }, + }, + { + id: 'core.ai.prompt.report-usage', + description: ` + This event is emitted for ai prompt report usage operations. + `, + }, + { + id: 'core.ai.prompt.validate', + description: ` + This event is emitted when a validate is being validated. + The event can be used to block certain validates from being validated. + `, + properties: { + allow: { + type: 'boolean', + mutability: 'mutable', + summary: 'whether the operation is allowed', + notes: [ + 'If set to false, the ai will be considered invalid.', + ], + }, + intended_service: { + type: 'any', + mutability: 'mutable', + summary: 'intended service', + notes: [], + }, + parameters: { + type: 'any', + mutability: 'mutable', + summary: 'parameters', + notes: [], + } + }, + }, + { + id: 'core.app.new-icon', + description: ` + This event is emitted for app new icon operations. + `, + properties: { + app_uid: { + type: 'string', + mutability: 'no-effect', + summary: 'app uid', + notes: [], + }, + data_url: { + type: 'any', + mutability: 'no-effect', + summary: 'data url', + notes: [], + } + }, + }, + { + id: 'core.app.rename', + description: ` + This event is emitted for app rename operations. + `, + properties: { + app_uid: { + type: 'string', + mutability: 'no-effect', + summary: 'app uid', + notes: [], + }, + data_url: { + type: 'any', + mutability: 'no-effect', + summary: 'data url', + notes: [], + } + }, + }, + { + id: 'core.apps.invalidate', + description: ` + This event is emitted when a invalidate is being validated. + The event can be used to block certain invalidates from being validated. + `, + properties: { + options: { + type: 'any', + mutability: 'no-effect', + summary: 'options', + notes: [], + }, + apps: { + type: 'any', + mutability: 'no-effect', + summary: 'apps', + notes: [], + } + }, + }, { id: 'core.email.validate', description: ` @@ -11,7 +177,7 @@ export default [ mutability: 'no-effect', summary: 'the email being validated', notes: [ - 'The email may have already been cleaned.', + 'The email may have already been cleaned.' ] }, allow: { @@ -19,11 +185,386 @@ export default [ mutability: 'mutable', summary: 'whether the email is allowed', notes: [ - 'If set to false, the email will be considered invalid.', + 'If set to false, the email will be considered invalid.' ] - }, + } }, }, + { + id: 'core.fs.create.directory', + description: ` + This event is emitted when a directory is created. + `, + properties: { + node: { + type: 'FSNodeContext', + mutability: 'no-effect', + summary: 'the directory that was created' + }, + context: { + type: 'Context', + mutability: 'no-effect', + summary: 'current context' + } + }, + }, + { + id: 'core.fs.create.file', + description: ` + This event is emitted when a file is created. + `, + properties: { + node: { + type: 'FSNodeContext', + mutability: 'no-effect', + summary: 'the file that was affected', + notes: [], + }, + context: { + type: 'Context', + mutability: 'no-effect', + summary: 'current context', + notes: [], + } + }, + }, + { + id: 'core.fs.create.shortcut', + description: ` + This event is emitted when a shortcut is created. + `, + }, + { + id: 'core.fs.create.symlink', + description: ` + This event is emitted when a symlink is created. + `, + }, + { + id: 'core.fs.move.file', + description: ` + This event is emitted for fs move file operations. + `, + properties: { + context: { + type: 'Context', + mutability: 'no-effect', + summary: 'current context', + notes: [], + }, + moved: { + type: 'any', + mutability: 'no-effect', + summary: 'moved', + notes: [], + }, + old_path: { + type: 'string', + mutability: 'no-effect', + summary: 'path to the affected resource', + notes: [], + } + }, + }, + { + id: 'core.fs.pending.file', + description: ` + This event is emitted for fs pending file operations. + `, + }, + { + id: 'core.fs.storage.progress.copy', + description: ` + This event reports progress of a copy operation. + `, + properties: { + upload_tracker: { + type: 'ProgressTracker', + mutability: 'no-effect', + summary: 'tracks progress of the operation', + notes: [], + }, + context: { + type: 'Context', + mutability: 'no-effect', + summary: 'current context', + notes: [], + }, + meta: { + type: 'object', + mutability: 'no-effect', + summary: 'additional metadata for the operation', + notes: [], + }, + item_path: { + type: 'string', + mutability: 'no-effect', + summary: 'path to the affected resource', + notes: [], + } + }, + }, + { + id: 'core.fs.storage.upload-progress', + description: ` + This event reports progress of a upload-progress operation. + `, + }, + { + id: 'core.fs.write.file', + description: ` + This event is emitted when a file is updated. + `, + properties: { + node: { + type: 'FSNodeContext', + mutability: 'no-effect', + summary: 'the file that was affected', + notes: [], + }, + context: { + type: 'Context', + mutability: 'no-effect', + summary: 'current context', + notes: [], + } + }, + }, + { + id: 'core.ip.validate', + description: ` + This event is emitted when a validate is being validated. + The event can be used to block certain validates from being validated. + `, + properties: { + allow: { + type: 'boolean', + mutability: 'mutable', + summary: 'whether the operation is allowed', + notes: [ + 'If set to false, the ip will be considered invalid.', + ], + }, + ip: { + type: 'any', + mutability: 'mutable', + summary: 'ip', + notes: [], + } + }, + }, + { + id: 'core.outer.fs.write-hash', + description: ` + This event is emitted when a write-hash is updated. + `, + properties: { + hash: { + type: 'any', + mutability: 'no-effect', + summary: 'hash', + notes: [], + }, + uuid: { + type: 'string', + mutability: 'no-effect', + summary: 'uuid', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.item.added', + description: ` + This event is emitted for outer gui item added operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.item.moved', + description: ` + This event is emitted for outer gui item moved operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.item.pending', + description: ` + This event is emitted for outer gui item pending operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.item.updated', + description: ` + This event is emitted when a updated is updated. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.notif.ack', + description: ` + This event is emitted for outer gui notif ack operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.notif.message', + description: ` + This event is emitted for outer gui notif message operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + }, + notification: { + type: 'any', + mutability: 'no-effect', + summary: 'notification', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.notif.persisted', + description: ` + This event is emitted for outer gui notif persisted operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.notif.unreads', + description: ` + This event is emitted for outer gui notif unreads operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.outer.gui.submission.done', + description: ` + This event is emitted for outer gui submission done operations. + `, + properties: { + user_id_list: { + type: 'string', + mutability: 'no-effect', + summary: 'user id list', + notes: [], + }, + response: { + type: 'any', + mutability: 'no-effect', + summary: 'response', + notes: [], + } + }, + }, + { + id: 'core.puter-exec.submission.done', + description: ` + This event is emitted for puter-exec submission done operations. + `, + }, { id: 'core.request.measured', description: ` @@ -39,30 +580,174 @@ export default [ const actor = data.actor; // instance of Actor - console.log('\\x1B[36;1m === MEASUREMENT ===\\x1B[0m\\n', { + console.log('\x1B[36;1m === MEASUREMENT ===\x1B[0m\n', { actor: data.actor.uid, measurements: data.measurements }); }); ` - } + }, }, { - id: 'core.fs.create.directory', + id: 'core.sns', description: ` - This event is emitted when a directory is created. + This event is emitted for sns operations. `, properties: { - node: { - type: 'FSNodeContext', + message: { + type: 'any', mutability: 'no-effect', - summary: 'the directory that was created', - }, - context: { - type: 'Context', - mutability: 'no-effect', - summary: 'current context' - }, - } + summary: 'message', + notes: [], + } + }, }, + { + id: 'core.template-service.hello', + description: ` + This event is emitted for template-service hello operations. + `, + properties: { + message: { + type: 'any', + mutability: 'no-effect', + summary: 'message', + notes: [], + } + }, + }, + { + id: 'core.usages.query', + description: ` + This event is emitted for usages query operations. + `, + properties: { + actor: { + type: 'any', + mutability: 'no-effect', + summary: 'actor', + notes: [], + }, + usages: { + type: 'any', + mutability: 'no-effect', + summary: 'usages', + notes: [], + } + }, + }, + { + id: 'core.user.email-changed', + description: ` + This event is emitted for user email changed operations. + `, + properties: { + user_id: { + type: 'string', + mutability: 'no-effect', + summary: 'user id', + notes: [], + }, + new_email: { + type: 'any', + mutability: 'no-effect', + summary: 'new email', + notes: [], + } + }, + }, + { + id: 'core.user.email-confirmed', + description: ` + This event is emitted for user email confirmed operations. + `, + properties: { + user_uid: { + type: 'string', + mutability: 'no-effect', + summary: 'user uid', + notes: [], + }, + email: { + type: 'any', + mutability: 'no-effect', + summary: 'email', + notes: [], + } + }, + }, + { + id: 'core.user.save_account', + description: ` + This event is emitted for user save_account operations. + `, + properties: { + user: { + type: 'User', + mutability: 'no-effect', + summary: 'user associated with the operation', + notes: [], + } + }, + }, + { + id: 'core.web.socket.connected', + description: ` + This event is emitted for web socket connected operations. + `, + properties: { + socket: { + type: 'any', + mutability: 'mutable', + summary: 'socket', + notes: [], + }, + user: { + type: 'User', + mutability: 'mutable', + summary: 'user associated with the operation', + notes: [], + } + }, + }, + { + id: 'core.web.socket.user-connected', + description: ` + This event is emitted for web socket user connected operations. + `, + properties: { + socket: { + type: 'any', + mutability: 'mutable', + summary: 'socket', + notes: [], + }, + user: { + type: 'User', + mutability: 'mutable', + summary: 'user associated with the operation', + notes: [], + } + }, + }, + { + id: 'core.wisp.get-policy', + description: ` + This event is emitted for wisp get policy operations. + `, + properties: { + allow: { + type: 'boolean', + mutability: 'mutable', + summary: 'whether the operation is allowed', + notes: [], + }, + policy: { + type: 'Policy', + mutability: 'mutable', + summary: 'policy information for the operation', + notes: [], + } + }, + } ]; diff --git a/doc/contributors/extensions/events.md b/doc/contributors/extensions/events.md index 8b2d2f6c1..a158fee35 100644 --- a/doc/contributors/extensions/events.md +++ b/doc/contributors/extensions/events.md @@ -19,7 +19,6 @@ whether the email is allowed - **Notes**: - If set to false, the email will be considered invalid. - ### `core.request.measured` This event is emitted when a requests incoming and outgoing bytes @@ -57,4 +56,654 @@ current context - **Type**: Context - **Mutability**: no-effect +### `core.ai.prompt.check-usage` + +This event is emitted for ai prompt check usage operations. + +#### Property `allow` + +whether the operation is allowed +- **Type**: boolean +- **Mutability**: mutable +- **Notes**: + +#### Property `intended_service` + +intended service +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `parameters` + +parameters +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +### `core.ai.prompt.complete` + +This event is emitted for ai prompt complete operations. + +#### Property `username` + +username +- **Type**: string +- **Mutability**: mutable +- **Notes**: + +#### Property `intended_service` + +intended service +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `parameters` + +parameters +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `result` + +result +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `model_used` + +model used +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `service_used` + +service used +- **Type**: any +- **Mutability**: mutable +- **Notes**: + + +### `core.ai.prompt.report-usage` + +This event is emitted for ai prompt report usage operations. + + +### `core.ai.prompt.validate` + +This event is emitted when a validate is being validated. +The event can be used to block certain validates from being validated. + +#### Property `allow` + +whether the operation is allowed +- **Type**: boolean +- **Mutability**: mutable +- **Notes**: + - If set to false, the ai will be considered invalid. + +#### Property `intended_service` + +intended service +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `parameters` + +parameters +- **Type**: any +- **Mutability**: mutable +- **Notes**: + + +### `core.app.new-icon` + +This event is emitted for app new icon operations. + +#### Property `app_uid` + +app uid +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `data_url` + +data url +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.app.rename` + +This event is emitted for app rename operations. + +#### Property `app_uid` + +app uid +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `data_url` + +data url +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.apps.invalidate` + +This event is emitted when a invalidate is being validated. +The event can be used to block certain invalidates from being validated. + +#### Property `options` + +options +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + +#### Property `apps` + +apps +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + +### `core.fs.create.file` + +This event is emitted when a file is created. + +#### Property `node` + +the file that was affected +- **Type**: FSNodeContext +- **Mutability**: no-effect +- **Notes**: + +#### Property `context` + +current context +- **Type**: Context +- **Mutability**: no-effect +- **Notes**: + + +### `core.fs.create.shortcut` + +This event is emitted when a shortcut is created. + + +### `core.fs.create.symlink` + +This event is emitted when a symlink is created. + + +### `core.fs.move.file` + +This event is emitted for fs move file operations. + +#### Property `context` + +current context +- **Type**: Context +- **Mutability**: no-effect +- **Notes**: + +#### Property `moved` + +moved +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + +#### Property `old_path` + +path to the affected resource +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + + +### `core.fs.pending.file` + +This event is emitted for fs pending file operations. + + +### `core.fs.storage.progress.copy` + +This event reports progress of a copy operation. + +#### Property `upload_tracker` + +tracks progress of the operation +- **Type**: ProgressTracker +- **Mutability**: no-effect +- **Notes**: + +#### Property `context` + +current context +- **Type**: Context +- **Mutability**: no-effect +- **Notes**: + +#### Property `meta` + +additional metadata for the operation +- **Type**: object +- **Mutability**: no-effect +- **Notes**: + +#### Property `item_path` + +path to the affected resource +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + + +### `core.fs.storage.upload-progress` + +This event reports progress of a upload-progress operation. + + +### `core.fs.write.file` + +This event is emitted when a file is updated. + +#### Property `node` + +the file that was affected +- **Type**: FSNodeContext +- **Mutability**: no-effect +- **Notes**: + +#### Property `context` + +current context +- **Type**: Context +- **Mutability**: no-effect +- **Notes**: + + +### `core.ip.validate` + +This event is emitted when a validate is being validated. +The event can be used to block certain validates from being validated. + +#### Property `allow` + +whether the operation is allowed +- **Type**: boolean +- **Mutability**: mutable +- **Notes**: + - If set to false, the ip will be considered invalid. + +#### Property `ip` + +ip +- **Type**: any +- **Mutability**: mutable +- **Notes**: + + +### `core.outer.fs.write-hash` + +This event is emitted when a write-hash is updated. + +#### Property `hash` + +hash +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + +#### Property `uuid` + +uuid +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.item.added` + +This event is emitted for outer gui item added operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.item.moved` + +This event is emitted for outer gui item moved operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.item.pending` + +This event is emitted for outer gui item pending operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.item.updated` + +This event is emitted when a updated is updated. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.notif.ack` + +This event is emitted for outer gui notif ack operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.notif.message` + +This event is emitted for outer gui notif message operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + +#### Property `notification` + +notification +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.notif.persisted` + +This event is emitted for outer gui notif persisted operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.notif.unreads` + +This event is emitted for outer gui notif unreads operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.outer.gui.submission.done` + +This event is emitted for outer gui submission done operations. + +#### Property `user_id_list` + +user id list +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `response` + +response +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.puter-exec.submission.done` + +This event is emitted for puter-exec submission done operations. + +### `core.sns` + +This event is emitted for sns operations. + +#### Property `message` + +message +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.template-service.hello` + +This event is emitted for template-service hello operations. + +#### Property `message` + +message +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.usages.query` + +This event is emitted for usages query operations. + +#### Property `actor` + +actor +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + +#### Property `usages` + +usages +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.user.email-changed` + +This event is emitted for user email changed operations. + +#### Property `user_id` + +user id +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `new_email` + +new email +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.user.email-confirmed` + +This event is emitted for user email confirmed operations. + +#### Property `user_uid` + +user uid +- **Type**: string +- **Mutability**: no-effect +- **Notes**: + +#### Property `email` + +email +- **Type**: any +- **Mutability**: no-effect +- **Notes**: + + +### `core.user.save_account` + +This event is emitted for user save_account operations. + +#### Property `user` + +user associated with the operation +- **Type**: User +- **Mutability**: no-effect +- **Notes**: + + +### `core.web.socket.connected` + +This event is emitted for web socket connected operations. + +#### Property `socket` + +socket +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `user` + +user associated with the operation +- **Type**: User +- **Mutability**: mutable +- **Notes**: + + +### `core.web.socket.user-connected` + +This event is emitted for web socket user connected operations. + +#### Property `socket` + +socket +- **Type**: any +- **Mutability**: mutable +- **Notes**: + +#### Property `user` + +user associated with the operation +- **Type**: User +- **Mutability**: mutable +- **Notes**: + + +### `core.wisp.get-policy` + +This event is emitted for wisp get policy operations. + +#### Property `allow` + +whether the operation is allowed +- **Type**: boolean +- **Mutability**: mutable +- **Notes**: + +#### Property `policy` + +policy information for the operation +- **Type**: Policy +- **Mutability**: mutable +- **Notes**: + diff --git a/doc/contributors/extensions/manual_overrides.json.js b/doc/contributors/extensions/manual_overrides.json.js new file mode 100644 index 000000000..b036fee38 --- /dev/null +++ b/doc/contributors/extensions/manual_overrides.json.js @@ -0,0 +1,68 @@ +export default [ + { + id: 'core.email.validate', + description: ` + This event is emitted when an email is being validated. + The event can be used to block certain emails from being validated. + `, + properties: { + email: { + type: 'string', + mutability: 'no-effect', + summary: 'the email being validated', + notes: [ + 'The email may have already been cleaned.', + ] + }, + allow: { + type: 'boolean', + mutability: 'mutable', + summary: 'whether the email is allowed', + notes: [ + 'If set to false, the email will be considered invalid.', + ] + }, + }, + }, + { + id: 'core.request.measured', + description: ` + This event is emitted when a requests incoming and outgoing bytes + have been measured. + `, + example: { + language: 'javascript', + code: /*javascript*/` + extension.on('core.request.measured', data => { + const measurements = data.measurements; + // measurements = { sz_incoming: integer, sz_outgoing: integer } + + const actor = data.actor; // instance of Actor + + console.log('\\x1B[36;1m === MEASUREMENT ===\\x1B[0m\\n', { + actor: data.actor.uid, + measurements: data.measurements + }); + }); + ` + } + }, + { + id: 'core.fs.create.directory', + description: ` + This event is emitted when a directory is created. + `, + properties: { + node: { + type: 'FSNodeContext', + mutability: 'no-effect', + summary: 'the directory that was created', + }, + context: { + type: 'Context', + mutability: 'no-effect', + summary: 'current context' + }, + } + }, +]; \ No newline at end of file diff --git a/extensions/testex.js b/extensions/testex.js new file mode 100644 index 000000000..ce1c9bf56 --- /dev/null +++ b/extensions/testex.js @@ -0,0 +1,158 @@ +// Test extension for event listeners + +extension.on('core.ai.prompt.check-usage', event => { + console.log('GOT AI.PROMPT.CHECK-USAGE EVENT', event); +}); + +extension.on('core.ai.prompt.complete', event => { + console.log('GOT AI.PROMPT.COMPLETE EVENT', event); +}); + +extension.on('core.ai.prompt.report-usage', event => { + console.log('GOT AI.PROMPT.REPORT-USAGE EVENT', event); +}); + +extension.on('core.ai.prompt.validate', event => { + console.log('GOT AI.PROMPT.VALIDATE EVENT', event); +}); + +extension.on('core.app.new-icon', event => { + console.log('GOT APP.NEW-ICON EVENT', event); +}); + +extension.on('core.app.rename', event => { + console.log('GOT APP.RENAME EVENT', event); +}); + +extension.on('core.apps.invalidate', event => { + console.log('GOT APPS.INVALIDATE EVENT', event); +}); + +extension.on('core.email.validate', event => { + console.log('GOT EMAIL.VALIDATE EVENT', event); +}); + +extension.on('core.fs.create.directory', event => { + console.log('GOT FS.CREATE.DIRECTORY EVENT', event); +}); + +extension.on('core.fs.create.file', event => { + console.log('GOT FS.CREATE.FILE EVENT', event); +}); + +extension.on('core.fs.create.shortcut', event => { + console.log('GOT FS.CREATE.SHORTCUT EVENT', event); +}); + +extension.on('core.fs.create.symlink', event => { + console.log('GOT FS.CREATE.SYMLINK EVENT', event); +}); + +extension.on('core.fs.move.file', event => { + console.log('GOT FS.MOVE.FILE EVENT', event); +}); + +extension.on('core.fs.pending.file', event => { + console.log('GOT FS.PENDING.FILE EVENT', event); +}); + +extension.on('core.fs.storage.progress.copy', event => { + console.log('GOT FS.STORAGE.PROGRESS.COPY EVENT', event); +}); + +extension.on('core.fs.storage.upload-progress', event => { + console.log('GOT FS.STORAGE.UPLOAD-PROGRESS EVENT', event); +}); + +extension.on('core.fs.write.file', event => { + console.log('GOT FS.WRITE.FILE EVENT', event); +}); + +extension.on('core.ip.validate', event => { + console.log('GOT IP.VALIDATE EVENT', event); +}); + +extension.on('core.outer.fs.write-hash', event => { + console.log('GOT OUTER.FS.WRITE-HASH EVENT', event); +}); + +extension.on('core.outer.gui.item.added', event => { + console.log('GOT OUTER.GUI.ITEM.ADDED EVENT', event); +}); + +extension.on('core.outer.gui.item.moved', event => { + console.log('GOT OUTER.GUI.ITEM.MOVED EVENT', event); +}); + +extension.on('core.outer.gui.item.pending', event => { + console.log('GOT OUTER.GUI.ITEM.PENDING EVENT', event); +}); + +extension.on('core.outer.gui.item.updated', event => { + console.log('GOT OUTER.GUI.ITEM.UPDATED EVENT', event); +}); + +extension.on('core.outer.gui.notif.ack', event => { + console.log('GOT OUTER.GUI.NOTIF.ACK EVENT', event); +}); + +extension.on('core.outer.gui.notif.message', event => { + console.log('GOT OUTER.GUI.NOTIF.MESSAGE EVENT', event); +}); + +extension.on('core.outer.gui.notif.persisted', event => { + console.log('GOT OUTER.GUI.NOTIF.PERSISTED EVENT', event); +}); + +extension.on('core.outer.gui.notif.unreads', event => { + console.log('GOT OUTER.GUI.NOTIF.UNREADS EVENT', event); +}); + +extension.on('core.outer.gui.submission.done', event => { + console.log('GOT OUTER.GUI.SUBMISSION.DONE EVENT', event); +}); + +extension.on('core.puter-exec.submission.done', event => { + console.log('GOT PUTER-EXEC.SUBMISSION.DONE EVENT', event); +}); + +extension.on('core.request.measured', event => { + console.log('GOT REQUEST.MEASURED EVENT', event); +}); + +extension.on('core.sns', event => { + console.log('GOT SNS EVENT', event); +}); + +extension.on('core.template-service.hello', event => { + console.log('GOT TEMPLATE-SERVICE.HELLO EVENT', event); +}); + +extension.on('core.usages.query', event => { + console.log('GOT USAGES.QUERY EVENT', event); +}); + +extension.on('core.user.email-changed', event => { + console.log('GOT USER.EMAIL-CHANGED EVENT', event); +}); + +extension.on('core.user.email-confirmed', event => { + console.log('GOT USER.EMAIL-CONFIRMED EVENT', event); +}); + +extension.on('core.user.save_account', event => { + console.log('GOT USER.SAVE_ACCOUNT EVENT', event); +}); + +extension.on('core.web.socket.connected', event => { + console.log('GOT WEB.SOCKET.CONNECTED EVENT', event); +}); + +extension.on('core.web.socket.user-connected', event => { + console.log('GOT WEB.SOCKET.USER-CONNECTED EVENT', event); +}); + +extension.on('core.wisp.get-policy', event => { + console.log('GOT WISP.GET-POLICY EVENT', event); +}); + diff --git a/package.json b/package.json index 817be9657..6ccee3915 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ ] }, "dependencies": { - "@heyputer/putility": "^1.0.2", "dedent": "^1.5.3", "javascript-time-ago": "^2.5.11", "json-colorizer": "^3.0.1", diff --git a/tools/doc_helper.js b/tools/doc_helper.js new file mode 100644 index 000000000..d285676e7 --- /dev/null +++ b/tools/doc_helper.js @@ -0,0 +1,475 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import manualOverrides from '../doc/contributors/extensions/manual_overrides.json.js'; + +// Get the directory name in ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Create a map of manual overrides for quick lookup +const manualOverridesMap = new Map(); +manualOverrides.forEach(override => { + manualOverridesMap.set(override.id, override); +}); + +// Array to collect all warnings +const warnings = []; + +// Add a function to detect and collect duplicate events +function checkForDuplicateEvent(eventId, filePath, seenEvents) { + if (seenEvents.has(eventId)) { + const existing = seenEvents.get(eventId); + if (existing.fromManualOverride) { + warnings.push(`Event ${eventId} found in ${filePath} but already defined in manual overrides. Using manual override.`); + } else { + warnings.push(`Duplicate event ${eventId} found in ${filePath}. First seen in ${existing.filename}.`); + } + return true; + } + return false; +} + +function extractEventsFromFile(filePath, seenEvents, debugMode) { + const content = fs.readFileSync(filePath, 'utf-8'); + + // Use a more general regex to capture all event emissions + // This captures the event name and whatever is passed as the second argument + const regex = /svc_event\.emit\(['"]([^'"]+)['"]\s*,\s*([^)]+)\)/g; + let match; + + while ((match = regex.exec(content)) !== null) { + const eventName = match[1]; + const eventId = `core.${eventName}`; + const eventArg = match[2].trim(); + + // Check if this file contains code that might affect event.allow + const hasAllowEffect = content.includes('event.allow') || + content.includes('.allow =') || + content.includes('.allow='); + + // Check for duplicate events and collect warnings + if (checkForDuplicateEvent(eventId, filePath, seenEvents)) { + continue; // Skip this event if it's a duplicate + } + + // Check if this event has a manual override + if (manualOverridesMap.has(eventId)) { + // Use the manual override instead of generating a new definition + const override = manualOverridesMap.get(eventId); + // Mark this as coming from manual override for later reference + override.fromManualOverride = true; + seenEvents.set(eventId, override); + continue; + } + + // Generate description based on event name + let description = generateDescription(eventName); + let propertyDetails = {}; + + // Case 1: Inline object - extract properties directly + if (eventArg.startsWith('{')) { + // Extract properties from inline object + const propertiesMatch = eventArg.match(/{([^}]*)}/); + if (propertiesMatch) { + const propertiesText = propertiesMatch[1]; + extractProperties(propertiesText, propertyDetails, hasAllowEffect, eventName); + } + } + // Case 2: Variable reference - find variable definition + else { + const varName = eventArg.trim(); + // Look for variable definition patterns like: const event = { prop1: value1 }; + const varDefRegex = new RegExp(`(?:const|let|var)\\s+${varName}\\s*=\\s*{([^}]*)}`, 'g'); + let varMatch; + + if ((varMatch = varDefRegex.exec(content)) !== null) { + const propertiesText = varMatch[1]; + extractProperties(propertiesText, propertyDetails, hasAllowEffect, eventName); + } + } + + // Add the event to our collection + seenEvents.set(eventId, { + id: eventId, + event: eventName, + filename: path.basename(filePath), + description: description, + properties: propertyDetails, + fromManualOverride: false + }); + } +} + +// Helper function to extract properties from a properties text string +function extractProperties(propertiesText, propertyDetails, hasAllowEffect, eventName) { + const properties = propertiesText + .split(/\s*,\s*/) + .map(prop => prop.split(':')[0].trim()) + .filter(prop => prop); + + // Generate property details + properties.forEach(prop => { + propertyDetails[prop] = { + type: guessType(prop), + mutability: hasAllowEffect ? 'effect' : 'no-effect', + summary: guessSummary(prop, eventName) + }; + }); +} + +function generateDescription(eventName) { + const parts = eventName.split('.'); + + if (parts.length >= 2) { + const system = parts[0]; + const action = parts.slice(1).join('.'); + + if (action.includes('create')) { + return `This event is emitted when a ${parts[parts.length - 1]} is created.`; + } else if (action.includes('update') || action.includes('write')) { + return `This event is emitted when a ${parts[parts.length - 1]} is updated.`; + } else if (action.includes('delete') || action.includes('remove')) { + return `This event is emitted when a ${parts[parts.length - 1]} is deleted.`; + } else if (action.includes('progress')) { + return `This event reports progress of a ${parts[parts.length - 1]} operation.`; + } else if (action.includes('validate')) { + return `This event is emitted when a ${parts[parts.length - 1]} is being validated.\nThe event can be used to block certain ${parts[parts.length - 1]}s from being validated.`; + } else { + return `This event is emitted for ${system} ${action.replace(/[-\.]/g, ' ')} operations.`; + } + } + + return `This event is emitted for ${eventName} operations.`; +} + +function guessType(propertyName) { + // Guess the type based on property name + if (propertyName === 'node') return 'FSNodeContext'; + if (propertyName === 'context') return 'Context'; + if (propertyName === 'user') return 'User'; + if (propertyName.includes('path')) return 'string'; + if (propertyName.includes('id')) return 'string'; + if (propertyName.includes('name')) return 'string'; + if (propertyName.includes('progress')) return 'number'; + if (propertyName.includes('tracker')) return 'ProgressTracker'; + if (propertyName.includes('meta')) return 'object'; + if (propertyName.includes('policy')) return 'Policy'; + if (propertyName.includes('allow')) return 'boolean'; + + return 'any'; +} + +function guessSummary(propertyName, eventName) { + // Generate summary based on property name and event context + if (propertyName === 'node') { + const entityType = eventName.split('.').pop(); + return `the ${entityType} that was affected`; + } + if (propertyName === 'context') return 'current context'; + if (propertyName === 'user') return 'user associated with the operation'; + if (propertyName.includes('path')) return 'path to the affected resource'; + if (propertyName.includes('tracker')) return 'tracks progress of the operation'; + if (propertyName.includes('meta')) return 'additional metadata for the operation'; + if (propertyName.includes('policy')) return 'policy information for the operation'; + if (propertyName.includes('allow')) return 'whether the operation is allowed'; + + // Default summary based on property name + return propertyName.replace(/_/g, ' '); +} + +function scanDirectory(directory, seenEvents, debugMode) { + const files = fs.readdirSync(directory); + + for (const file of files) { + const filePath = path.join(directory, file); + const stat = fs.statSync(filePath); + + if (stat.isDirectory()) { + scanDirectory(filePath, seenEvents, debugMode); + } else if (file.endsWith('.js')) { + try { + extractEventsFromFile(filePath, seenEvents, debugMode); + } catch (error) { + warnings.push(`Error processing file ${filePath}: ${error.message}`); + } + } + } +} + +function generateTestExtension(events) { + let code = `// Test extension for event listeners\n\n`; + + events.forEach(event => { + const eventId = event.id; + const eventName = event.event ? event.event.toUpperCase() : eventId.split('.').slice(1).join('.').toUpperCase(); + + code += `extension.on('${eventId}', event => {\n`; + code += ` console.log('GOT ${eventName} EVENT', event);\n`; + code += `});\n\n`; + }); + + return code; +} + +function main() { + const args = process.argv.slice(2); + if (args.length < 1) { + console.error('Usage: node doc_helper.js [output_file] [--generate-test] [--test-dir=] [--debug]'); + process.exit(1); + } + + // Resolve directory path relative to project root + const directory = path.resolve(path.join(path.dirname(__dirname), args[0])); + let outputFile = null; + let generateTest = false; + let testOutputDir = "./extensions/"; + let debugMode = false; + + // Parse arguments + for (let i = 1; i < args.length; i++) { + if (args[i] === '--generate-test') { + generateTest = true; + } else if (args[i].startsWith('--test-dir=')) { + testOutputDir = args[i].substring('--test-dir='.length); + } else if (args[i] === '--debug') { + debugMode = true; + } else if (!args[i].startsWith('--')) { + // Only treat non-flag arguments as output file + outputFile = path.resolve(path.join(path.dirname(__dirname), args[i])); + } + } + + // Resolve test output directory relative to project root if it's not an absolute path + if (!path.isAbsolute(testOutputDir)) { + testOutputDir = path.resolve(path.join(path.dirname(__dirname), testOutputDir)); + } + + const seenEvents = new Map(); + + // First, add all manual overrides to the seenEvents map + manualOverrides.forEach(override => { + // Mark this as coming from manual override for later reference + override.fromManualOverride = true; + seenEvents.set(override.id, override); + }); + + // Then scan the directory for additional events + scanDirectory(directory, seenEvents, debugMode); + + // Check for any manual overrides that weren't used + manualOverrides.forEach(override => { + const event = seenEvents.get(override.id); + if (!event || !event.fromManualOverride) { + warnings.push(`Manual override for ${override.id} exists but no matching event was found in the codebase.`); + } + }); + + const result = Array.from(seenEvents.values()); + + // Sort events alphabetically by ID + result.sort((a, b) => a.id.localeCompare(b.id)); + + // Format the output to match events.json.js + const formattedOutput = formatEventsOutput(result); + + // Output the result + if (outputFile) { + fs.writeFileSync(outputFile, formattedOutput); + console.log(`Event metadata written to ${outputFile}`); + } else { + console.log(formattedOutput); + } + + // Generate test extension file if requested + if (generateTest) { + const testCode = generateTestExtension(result); + + // Ensure the output directory exists + if (!fs.existsSync(testOutputDir)) { + fs.mkdirSync(testOutputDir, { recursive: true }); + } + + const testFilePath = path.join(testOutputDir, 'testex.js'); + fs.writeFileSync(testFilePath, testCode); + console.log(`Test extension file generated: ${testFilePath}`); + } + + // Print warnings in the requested format + if (warnings.length > 0) { + // Collect duplicate events + const duplicateEvents = new Set(); + const overrideEvents = new Set(); + const otherWarnings = []; + + warnings.forEach(warning => { + if (warning.includes("Duplicate event")) { + // Extract event ID from the warning message + const match = warning.match(/Duplicate event (core\.[^ ]+)/); + if (match && match[1]) { + duplicateEvents.add(match[1]); + } + } else if (warning.includes("already defined in manual overrides")) { + // Extract event ID from the warning message + const match = warning.match(/Event (core\.[^ ]+) found/); + if (match && match[1]) { + overrideEvents.add(match[1]); + } + } else { + otherWarnings.push(warning); + } + }); + + // Output in the requested format + console.log(`\nduplicate events: ${Array.from(duplicateEvents).join(', ')}`); + console.log(`Override events: ${Array.from(overrideEvents).join(', ')}`); + + // If there are any other warnings, print them too + if (otherWarnings.length > 0) { + console.log("\nOther warnings:"); + otherWarnings.forEach(warning => { + console.log(`- ${warning}`); + }); + } + } +} + +/** + * Format the events data to match the events.json.js format + */ +function formatEventsOutput(events) { + let output = 'export default [\n'; + + events.forEach((event, index) => { + // Check if this is a manual override + if (event.fromManualOverride) { + // This is a manual override, output it exactly as defined + output += ' {\n'; + output += ` id: '${event.id}',\n`; + output += ` description: \``; + + // Format the description with proper indentation, preserving original formatting + // Don't add extra newlines before or after the description + output += event.description; + + output += `\`,\n`; + + // Add properties if they exist, preserving exact format + if (event.properties && Object.keys(event.properties).length > 0) { + output += ' properties: {\n'; + + Object.entries(event.properties).forEach(([propName, propDetails], propIndex) => { + output += ` ${propName}: {\n`; + output += ` type: '${propDetails.type}',\n`; + output += ` mutability: '${propDetails.mutability}',\n`; + output += ` summary: '${propDetails.summary}'`; + + // Add notes array if it exists + if (propDetails.notes && propDetails.notes.length > 0) { + output += `,\n notes: [\n`; + propDetails.notes.forEach((note, noteIndex) => { + output += ` '${note}'`; + if (noteIndex < propDetails.notes.length - 1) { + output += ','; + } + output += '\n'; + }); + output += ` ]`; + } + + output += '\n }'; + + // Add comma if not the last property + if (propIndex < Object.keys(event.properties).length - 1) { + output += ','; + } + + output += '\n'; + }); + + output += ' },\n'; + } + + // Add example if it exists + if (event.example) { + output += ' example: {\n'; + output += ` language: '${event.example.language}',\n`; + output += ` code: /*${event.example.language}*/\``; + + // Preserve the exact formatting of the example code + // Don't add extra newlines and preserve escape sequences exactly as they are + output += event.example.code; + + output += `\`\n`; + output += ' },\n'; + } + + output += ' }'; + } else { + // This is an auto-generated event + output += ' {\n'; + output += ` id: '${event.id}',\n`; + output += ` description: \`\n`; + + // Format the description with proper indentation + const descriptionLines = event.description.split('\n'); + descriptionLines.forEach(line => { + output += ` ${line}\n`; + }); + + output += ` \`,\n`; + + // Add properties if they exist + if (Object.keys(event.properties).length > 0) { + output += ' properties: {\n'; + + Object.entries(event.properties).forEach(([propName, propDetails], propIndex) => { + output += ` ${propName}: {\n`; + output += ` type: '${propDetails.type}',\n`; + output += ` mutability: '${propDetails.mutability === 'effect' ? 'mutable' : 'no-effect'}',\n`; + output += ` summary: '${propDetails.summary}',\n`; + + // Add notes array with appropriate content + if (propName === 'allow' && event.event.includes('validate')) { + output += ` notes: [\n`; + output += ` 'If set to false, the ${event.event.split('.')[0]} will be considered invalid.',\n`; + output += ` ],\n`; + } else if (propName === 'email' && event.event.includes('validate')) { + output += ` notes: [\n`; + output += ` 'The email may have already been cleaned.',\n`; + output += ` ],\n`; + } else { + output += ` notes: [],\n`; + } + + output += ' }'; + + // Add comma if not the last property + if (propIndex < Object.keys(event.properties).length - 1) { + output += ','; + } + + output += '\n'; + }); + + output += ' },\n'; + } + + output += ' }'; + } + + // Add comma if not the last event + if (index < events.length - 1) { + output += ','; + } + + output += '\n'; + }); + + output += '];\n'; + + return output; +} + +main(); +// Updated Sun Mar 9 23:52:51 EDT 2025