@pan-sec/notebooklm-mcp 2026.3.2 → 2026.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/auth-manager.d.ts +0 -1
- package/dist/auth/auth-manager.js +0 -1
- package/dist/auth/mcp-auth.d.ts +0 -1
- package/dist/auth/mcp-auth.js +0 -1
- package/dist/compliance/alert-manager.d.ts +6 -2
- package/dist/compliance/alert-manager.js +40 -10
- package/dist/compliance/breach-detection.d.ts +0 -1
- package/dist/compliance/breach-detection.js +0 -1
- package/dist/compliance/change-log.d.ts +13 -1
- package/dist/compliance/change-log.js +82 -16
- package/dist/compliance/compliance-logger.d.ts +29 -3
- package/dist/compliance/compliance-logger.js +90 -27
- package/dist/compliance/compliance-tools.d.ts +0 -1
- package/dist/compliance/compliance-tools.js +0 -1
- package/dist/compliance/consent-manager.d.ts +0 -1
- package/dist/compliance/consent-manager.js +0 -1
- package/dist/compliance/dashboard.d.ts +4 -3
- package/dist/compliance/dashboard.js +11 -8
- package/dist/compliance/data-classification.d.ts +0 -1
- package/dist/compliance/data-classification.js +0 -1
- package/dist/compliance/data-erasure.d.ts +0 -1
- package/dist/compliance/data-erasure.js +0 -1
- package/dist/compliance/data-export.d.ts +0 -1
- package/dist/compliance/data-export.js +0 -1
- package/dist/compliance/data-inventory.d.ts +0 -1
- package/dist/compliance/data-inventory.js +0 -1
- package/dist/compliance/dsar-handler.d.ts +0 -1
- package/dist/compliance/dsar-handler.js +0 -1
- package/dist/compliance/evidence-collector.d.ts +0 -1
- package/dist/compliance/evidence-collector.js +4 -2
- package/dist/compliance/health-monitor.d.ts +0 -1
- package/dist/compliance/health-monitor.js +0 -1
- package/dist/compliance/incident-manager.d.ts +0 -1
- package/dist/compliance/incident-manager.js +0 -1
- package/dist/compliance/index.d.ts +0 -1
- package/dist/compliance/index.js +0 -1
- package/dist/compliance/policy-docs.d.ts +0 -1
- package/dist/compliance/policy-docs.js +0 -1
- package/dist/compliance/privacy-notice-text.d.ts +0 -1
- package/dist/compliance/privacy-notice-text.js +0 -1
- package/dist/compliance/privacy-notice.d.ts +0 -1
- package/dist/compliance/privacy-notice.js +0 -1
- package/dist/compliance/report-generator.d.ts +7 -1
- package/dist/compliance/report-generator.js +116 -34
- package/dist/compliance/retention-engine.d.ts +0 -1
- package/dist/compliance/retention-engine.js +0 -1
- package/dist/compliance/siem-exporter.d.ts +26 -2
- package/dist/compliance/siem-exporter.js +89 -24
- package/dist/compliance/types.d.ts +0 -1
- package/dist/compliance/types.js +0 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +2 -3
- package/dist/errors.d.ts +0 -1
- package/dist/errors.js +0 -1
- package/dist/events/event-emitter.d.ts +9 -1
- package/dist/events/event-emitter.js +47 -8
- package/dist/events/event-types.d.ts +0 -1
- package/dist/events/event-types.js +8 -2
- package/dist/gemini/gemini-client.d.ts +0 -1
- package/dist/gemini/gemini-client.js +237 -45
- package/dist/gemini/index.d.ts +0 -1
- package/dist/gemini/index.js +0 -1
- package/dist/gemini/pdf-chunker.d.ts +0 -1
- package/dist/gemini/pdf-chunker.js +60 -35
- package/dist/gemini/types.d.ts +0 -1
- package/dist/gemini/types.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +74 -10
- package/dist/library/notebook-library.d.ts +30 -2
- package/dist/library/notebook-library.js +345 -85
- package/dist/library/types.d.ts +0 -1
- package/dist/library/types.js +0 -1
- package/dist/logging/index.d.ts +0 -1
- package/dist/logging/index.js +0 -1
- package/dist/logging/query-logger.d.ts +20 -1
- package/dist/logging/query-logger.js +104 -21
- package/dist/notebook-creation/audio-manager.d.ts +0 -1
- package/dist/notebook-creation/audio-manager.js +111 -20
- package/dist/notebook-creation/browser-options.d.ts +0 -1
- package/dist/notebook-creation/browser-options.js +0 -1
- package/dist/notebook-creation/data-table-manager.d.ts +7 -1
- package/dist/notebook-creation/data-table-manager.js +59 -3
- package/dist/notebook-creation/dom-scripts.d.ts +0 -1
- package/dist/notebook-creation/dom-scripts.js +0 -1
- package/dist/notebook-creation/errors.d.ts +0 -1
- package/dist/notebook-creation/errors.js +0 -1
- package/dist/notebook-creation/index.d.ts +0 -1
- package/dist/notebook-creation/index.js +0 -1
- package/dist/notebook-creation/notebook-creator.d.ts +9 -1
- package/dist/notebook-creation/notebook-creator.js +50 -1
- package/dist/notebook-creation/notebook-nav.d.ts +0 -1
- package/dist/notebook-creation/notebook-nav.js +21 -6
- package/dist/notebook-creation/notebook-sync.d.ts +14 -2
- package/dist/notebook-creation/notebook-sync.js +124 -35
- package/dist/notebook-creation/selectors.d.ts +0 -1
- package/dist/notebook-creation/selectors.js +6 -4
- package/dist/notebook-creation/source-manager.d.ts +29 -2
- package/dist/notebook-creation/source-manager.js +0 -0
- package/dist/notebook-creation/types.d.ts +0 -1
- package/dist/notebook-creation/types.js +0 -1
- package/dist/notebook-creation/video-manager.d.ts +0 -1
- package/dist/notebook-creation/video-manager.js +91 -15
- package/dist/observability/metrics.d.ts +0 -1
- package/dist/observability/metrics.js +0 -1
- package/dist/quota/index.d.ts +0 -1
- package/dist/quota/index.js +0 -1
- package/dist/quota/quota-manager.d.ts +59 -4
- package/dist/quota/quota-manager.js +195 -46
- package/dist/resources/resource-handlers.d.ts +0 -1
- package/dist/resources/resource-handlers.js +33 -3
- package/dist/session/browser-session.d.ts +0 -1
- package/dist/session/browser-session.js +0 -1
- package/dist/session/session-manager.d.ts +0 -1
- package/dist/session/session-manager.js +0 -1
- package/dist/session/session-timeout.d.ts +0 -1
- package/dist/session/session-timeout.js +0 -1
- package/dist/session/shared-context-manager.d.ts +0 -1
- package/dist/session/shared-context-manager.js +0 -1
- package/dist/tools/annotations.d.ts +0 -1
- package/dist/tools/annotations.js +0 -1
- package/dist/tools/definitions/ask-question.d.ts +6 -3
- package/dist/tools/definitions/ask-question.js +12 -8
- package/dist/tools/definitions/chat-history.d.ts +0 -1
- package/dist/tools/definitions/chat-history.js +1 -1
- package/dist/tools/definitions/data-tables.d.ts +0 -1
- package/dist/tools/definitions/data-tables.js +4 -1
- package/dist/tools/definitions/gemini.d.ts +0 -1
- package/dist/tools/definitions/gemini.js +14 -7
- package/dist/tools/definitions/notebook-management.d.ts +0 -1
- package/dist/tools/definitions/notebook-management.js +7 -2
- package/dist/tools/definitions/query-history.d.ts +0 -1
- package/dist/tools/definitions/query-history.js +0 -1
- package/dist/tools/definitions/session-management.d.ts +0 -1
- package/dist/tools/definitions/session-management.js +0 -1
- package/dist/tools/definitions/system.d.ts +0 -1
- package/dist/tools/definitions/system.js +32 -12
- package/dist/tools/definitions/video.d.ts +0 -1
- package/dist/tools/definitions/video.js +6 -3
- package/dist/tools/definitions.d.ts +0 -1
- package/dist/tools/definitions.js +0 -1
- package/dist/tools/handlers/ask-question.d.ts +0 -1
- package/dist/tools/handlers/ask-question.js +47 -18
- package/dist/tools/handlers/audio-video.d.ts +0 -1
- package/dist/tools/handlers/audio-video.js +0 -1
- package/dist/tools/handlers/auth.d.ts +0 -1
- package/dist/tools/handlers/auth.js +0 -1
- package/dist/tools/handlers/error-utils.d.ts +0 -1
- package/dist/tools/handlers/error-utils.js +0 -1
- package/dist/tools/handlers/gemini.d.ts +0 -1
- package/dist/tools/handlers/gemini.js +0 -1
- package/dist/tools/handlers/index.d.ts +0 -1
- package/dist/tools/handlers/index.js +0 -1
- package/dist/tools/handlers/notebook-creation.d.ts +0 -1
- package/dist/tools/handlers/notebook-creation.js +16 -1
- package/dist/tools/handlers/notebook-management.d.ts +0 -1
- package/dist/tools/handlers/notebook-management.js +7 -2
- package/dist/tools/handlers/session-management.d.ts +0 -1
- package/dist/tools/handlers/session-management.js +0 -1
- package/dist/tools/handlers/system.d.ts +0 -1
- package/dist/tools/handlers/system.js +0 -1
- package/dist/tools/handlers/types.d.ts +0 -1
- package/dist/tools/handlers/types.js +0 -1
- package/dist/tools/handlers/webhooks.d.ts +0 -1
- package/dist/tools/handlers/webhooks.js +0 -1
- package/dist/tools/icons.d.ts +0 -1
- package/dist/tools/icons.js +0 -1
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.js +0 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -1
- package/dist/utils/audit-logger.d.ts +11 -1
- package/dist/utils/audit-logger.js +189 -21
- package/dist/utils/cleanup-manager.d.ts +0 -1
- package/dist/utils/cleanup-manager.js +0 -1
- package/dist/utils/cli-handler.d.ts +0 -1
- package/dist/utils/cli-handler.js +0 -1
- package/dist/utils/crypto.d.ts +18 -9
- package/dist/utils/crypto.js +93 -28
- package/dist/utils/file-lock.d.ts +15 -1
- package/dist/utils/file-lock.js +67 -59
- package/dist/utils/file-permissions.d.ts +0 -1
- package/dist/utils/file-permissions.js +35 -7
- package/dist/utils/logger.d.ts +0 -1
- package/dist/utils/logger.js +0 -1
- package/dist/utils/page-utils.d.ts +0 -1
- package/dist/utils/page-utils.js +32 -28
- package/dist/utils/response-validator.d.ts +0 -1
- package/dist/utils/response-validator.js +18 -15
- package/dist/utils/secrets-scanner.d.ts +0 -1
- package/dist/utils/secrets-scanner.js +32 -7
- package/dist/utils/secure-memory.d.ts +34 -16
- package/dist/utils/secure-memory.js +40 -25
- package/dist/utils/security.d.ts +0 -1
- package/dist/utils/security.js +66 -39
- package/dist/utils/settings-manager.d.ts +9 -1
- package/dist/utils/settings-manager.js +45 -2
- package/dist/utils/stealth-utils.d.ts +0 -1
- package/dist/utils/stealth-utils.js +11 -9
- package/dist/webhooks/index.d.ts +0 -1
- package/dist/webhooks/index.js +0 -1
- package/dist/webhooks/types.d.ts +0 -1
- package/dist/webhooks/types.js +0 -1
- package/dist/webhooks/webhook-dispatcher.d.ts +0 -1
- package/dist/webhooks/webhook-dispatcher.js +0 -1
- package/package.json +5 -4
- package/dist/auth/auth-manager.d.ts.map +0 -1
- package/dist/auth/auth-manager.js.map +0 -1
- package/dist/auth/mcp-auth.d.ts.map +0 -1
- package/dist/auth/mcp-auth.js.map +0 -1
- package/dist/compliance/alert-manager.d.ts.map +0 -1
- package/dist/compliance/alert-manager.js.map +0 -1
- package/dist/compliance/breach-detection.d.ts.map +0 -1
- package/dist/compliance/breach-detection.js.map +0 -1
- package/dist/compliance/change-log.d.ts.map +0 -1
- package/dist/compliance/change-log.js.map +0 -1
- package/dist/compliance/compliance-logger.d.ts.map +0 -1
- package/dist/compliance/compliance-logger.js.map +0 -1
- package/dist/compliance/compliance-tools.d.ts.map +0 -1
- package/dist/compliance/compliance-tools.js.map +0 -1
- package/dist/compliance/consent-manager.d.ts.map +0 -1
- package/dist/compliance/consent-manager.js.map +0 -1
- package/dist/compliance/dashboard.d.ts.map +0 -1
- package/dist/compliance/dashboard.js.map +0 -1
- package/dist/compliance/data-classification.d.ts.map +0 -1
- package/dist/compliance/data-classification.js.map +0 -1
- package/dist/compliance/data-erasure.d.ts.map +0 -1
- package/dist/compliance/data-erasure.js.map +0 -1
- package/dist/compliance/data-export.d.ts.map +0 -1
- package/dist/compliance/data-export.js.map +0 -1
- package/dist/compliance/data-inventory.d.ts.map +0 -1
- package/dist/compliance/data-inventory.js.map +0 -1
- package/dist/compliance/dsar-handler.d.ts.map +0 -1
- package/dist/compliance/dsar-handler.js.map +0 -1
- package/dist/compliance/evidence-collector.d.ts.map +0 -1
- package/dist/compliance/evidence-collector.js.map +0 -1
- package/dist/compliance/health-monitor.d.ts.map +0 -1
- package/dist/compliance/health-monitor.js.map +0 -1
- package/dist/compliance/incident-manager.d.ts.map +0 -1
- package/dist/compliance/incident-manager.js.map +0 -1
- package/dist/compliance/index.d.ts.map +0 -1
- package/dist/compliance/index.js.map +0 -1
- package/dist/compliance/policy-docs.d.ts.map +0 -1
- package/dist/compliance/policy-docs.js.map +0 -1
- package/dist/compliance/privacy-notice-text.d.ts.map +0 -1
- package/dist/compliance/privacy-notice-text.js.map +0 -1
- package/dist/compliance/privacy-notice.d.ts.map +0 -1
- package/dist/compliance/privacy-notice.js.map +0 -1
- package/dist/compliance/report-generator.d.ts.map +0 -1
- package/dist/compliance/report-generator.js.map +0 -1
- package/dist/compliance/retention-engine.d.ts.map +0 -1
- package/dist/compliance/retention-engine.js.map +0 -1
- package/dist/compliance/siem-exporter.d.ts.map +0 -1
- package/dist/compliance/siem-exporter.js.map +0 -1
- package/dist/compliance/types.d.ts.map +0 -1
- package/dist/compliance/types.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/events/event-emitter.d.ts.map +0 -1
- package/dist/events/event-emitter.js.map +0 -1
- package/dist/events/event-types.d.ts.map +0 -1
- package/dist/events/event-types.js.map +0 -1
- package/dist/gemini/gemini-client.d.ts.map +0 -1
- package/dist/gemini/gemini-client.js.map +0 -1
- package/dist/gemini/index.d.ts.map +0 -1
- package/dist/gemini/index.js.map +0 -1
- package/dist/gemini/pdf-chunker.d.ts.map +0 -1
- package/dist/gemini/pdf-chunker.js.map +0 -1
- package/dist/gemini/types.d.ts.map +0 -1
- package/dist/gemini/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/library/notebook-library.d.ts.map +0 -1
- package/dist/library/notebook-library.js.map +0 -1
- package/dist/library/types.d.ts.map +0 -1
- package/dist/library/types.js.map +0 -1
- package/dist/logging/index.d.ts.map +0 -1
- package/dist/logging/index.js.map +0 -1
- package/dist/logging/query-logger.d.ts.map +0 -1
- package/dist/logging/query-logger.js.map +0 -1
- package/dist/notebook-creation/audio-manager.d.ts.map +0 -1
- package/dist/notebook-creation/audio-manager.js.map +0 -1
- package/dist/notebook-creation/browser-options.d.ts.map +0 -1
- package/dist/notebook-creation/browser-options.js.map +0 -1
- package/dist/notebook-creation/data-table-manager.d.ts.map +0 -1
- package/dist/notebook-creation/data-table-manager.js.map +0 -1
- package/dist/notebook-creation/discover-creation-flow.d.ts +0 -2
- package/dist/notebook-creation/discover-creation-flow.d.ts.map +0 -1
- package/dist/notebook-creation/discover-creation-flow.js +0 -177
- package/dist/notebook-creation/discover-creation-flow.js.map +0 -1
- package/dist/notebook-creation/discover-quota.d.ts +0 -2
- package/dist/notebook-creation/discover-quota.d.ts.map +0 -1
- package/dist/notebook-creation/discover-quota.js +0 -194
- package/dist/notebook-creation/discover-quota.js.map +0 -1
- package/dist/notebook-creation/discover-source-dialog.d.ts +0 -8
- package/dist/notebook-creation/discover-source-dialog.d.ts.map +0 -1
- package/dist/notebook-creation/discover-source-dialog.js +0 -134
- package/dist/notebook-creation/discover-source-dialog.js.map +0 -1
- package/dist/notebook-creation/discover-sources.d.ts +0 -8
- package/dist/notebook-creation/discover-sources.d.ts.map +0 -1
- package/dist/notebook-creation/discover-sources.js +0 -272
- package/dist/notebook-creation/discover-sources.js.map +0 -1
- package/dist/notebook-creation/discover-text-input.d.ts +0 -7
- package/dist/notebook-creation/discover-text-input.d.ts.map +0 -1
- package/dist/notebook-creation/discover-text-input.js +0 -135
- package/dist/notebook-creation/discover-text-input.js.map +0 -1
- package/dist/notebook-creation/dom-scripts.d.ts.map +0 -1
- package/dist/notebook-creation/dom-scripts.js.map +0 -1
- package/dist/notebook-creation/errors.d.ts.map +0 -1
- package/dist/notebook-creation/errors.js.map +0 -1
- package/dist/notebook-creation/index.d.ts.map +0 -1
- package/dist/notebook-creation/index.js.map +0 -1
- package/dist/notebook-creation/notebook-creator.d.ts.map +0 -1
- package/dist/notebook-creation/notebook-creator.js.map +0 -1
- package/dist/notebook-creation/notebook-nav.d.ts.map +0 -1
- package/dist/notebook-creation/notebook-nav.js.map +0 -1
- package/dist/notebook-creation/notebook-sync.d.ts.map +0 -1
- package/dist/notebook-creation/notebook-sync.js.map +0 -1
- package/dist/notebook-creation/run-discovery.d.ts +0 -11
- package/dist/notebook-creation/run-discovery.d.ts.map +0 -1
- package/dist/notebook-creation/run-discovery.js +0 -151
- package/dist/notebook-creation/run-discovery.js.map +0 -1
- package/dist/notebook-creation/selector-discovery.d.ts +0 -65
- package/dist/notebook-creation/selector-discovery.d.ts.map +0 -1
- package/dist/notebook-creation/selector-discovery.js +0 -414
- package/dist/notebook-creation/selector-discovery.js.map +0 -1
- package/dist/notebook-creation/selectors.d.ts.map +0 -1
- package/dist/notebook-creation/selectors.js.map +0 -1
- package/dist/notebook-creation/selectors.ts +0 -112
- package/dist/notebook-creation/source-manager.d.ts.map +0 -1
- package/dist/notebook-creation/source-manager.js.map +0 -1
- package/dist/notebook-creation/test-create.d.ts +0 -8
- package/dist/notebook-creation/test-create.d.ts.map +0 -1
- package/dist/notebook-creation/test-create.js +0 -72
- package/dist/notebook-creation/test-create.js.map +0 -1
- package/dist/notebook-creation/types.d.ts.map +0 -1
- package/dist/notebook-creation/types.js.map +0 -1
- package/dist/notebook-creation/video-manager.d.ts.map +0 -1
- package/dist/notebook-creation/video-manager.js.map +0 -1
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/metrics.js.map +0 -1
- package/dist/quota/index.d.ts.map +0 -1
- package/dist/quota/index.js.map +0 -1
- package/dist/quota/quota-manager.d.ts.map +0 -1
- package/dist/quota/quota-manager.js.map +0 -1
- package/dist/resources/resource-handlers.d.ts.map +0 -1
- package/dist/resources/resource-handlers.js.map +0 -1
- package/dist/session/browser-session.d.ts.map +0 -1
- package/dist/session/browser-session.js.map +0 -1
- package/dist/session/session-manager.d.ts.map +0 -1
- package/dist/session/session-manager.js.map +0 -1
- package/dist/session/session-timeout.d.ts.map +0 -1
- package/dist/session/session-timeout.js.map +0 -1
- package/dist/session/shared-context-manager.d.ts.map +0 -1
- package/dist/session/shared-context-manager.js.map +0 -1
- package/dist/tools/annotations.d.ts.map +0 -1
- package/dist/tools/annotations.js.map +0 -1
- package/dist/tools/definitions/ask-question.d.ts.map +0 -1
- package/dist/tools/definitions/ask-question.js.map +0 -1
- package/dist/tools/definitions/chat-history.d.ts.map +0 -1
- package/dist/tools/definitions/chat-history.js.map +0 -1
- package/dist/tools/definitions/data-tables.d.ts.map +0 -1
- package/dist/tools/definitions/data-tables.js.map +0 -1
- package/dist/tools/definitions/gemini.d.ts.map +0 -1
- package/dist/tools/definitions/gemini.js.map +0 -1
- package/dist/tools/definitions/notebook-management.d.ts.map +0 -1
- package/dist/tools/definitions/notebook-management.js.map +0 -1
- package/dist/tools/definitions/query-history.d.ts.map +0 -1
- package/dist/tools/definitions/query-history.js.map +0 -1
- package/dist/tools/definitions/session-management.d.ts.map +0 -1
- package/dist/tools/definitions/session-management.js.map +0 -1
- package/dist/tools/definitions/system.d.ts.map +0 -1
- package/dist/tools/definitions/system.js.map +0 -1
- package/dist/tools/definitions/video.d.ts.map +0 -1
- package/dist/tools/definitions/video.js.map +0 -1
- package/dist/tools/definitions.d.ts.map +0 -1
- package/dist/tools/definitions.js.map +0 -1
- package/dist/tools/handlers/ask-question.d.ts.map +0 -1
- package/dist/tools/handlers/ask-question.js.map +0 -1
- package/dist/tools/handlers/audio-video.d.ts.map +0 -1
- package/dist/tools/handlers/audio-video.js.map +0 -1
- package/dist/tools/handlers/auth.d.ts.map +0 -1
- package/dist/tools/handlers/auth.js.map +0 -1
- package/dist/tools/handlers/error-utils.d.ts.map +0 -1
- package/dist/tools/handlers/error-utils.js.map +0 -1
- package/dist/tools/handlers/gemini.d.ts.map +0 -1
- package/dist/tools/handlers/gemini.js.map +0 -1
- package/dist/tools/handlers/index.d.ts.map +0 -1
- package/dist/tools/handlers/index.js.map +0 -1
- package/dist/tools/handlers/notebook-creation.d.ts.map +0 -1
- package/dist/tools/handlers/notebook-creation.js.map +0 -1
- package/dist/tools/handlers/notebook-management.d.ts.map +0 -1
- package/dist/tools/handlers/notebook-management.js.map +0 -1
- package/dist/tools/handlers/session-management.d.ts.map +0 -1
- package/dist/tools/handlers/session-management.js.map +0 -1
- package/dist/tools/handlers/system.d.ts.map +0 -1
- package/dist/tools/handlers/system.js.map +0 -1
- package/dist/tools/handlers/types.d.ts.map +0 -1
- package/dist/tools/handlers/types.js.map +0 -1
- package/dist/tools/handlers/webhooks.d.ts.map +0 -1
- package/dist/tools/handlers/webhooks.js.map +0 -1
- package/dist/tools/handlers.d.ts +0 -666
- package/dist/tools/handlers.d.ts.map +0 -1
- package/dist/tools/handlers.js +0 -2929
- package/dist/tools/handlers.js.map +0 -1
- package/dist/tools/icons.d.ts.map +0 -1
- package/dist/tools/icons.js.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils/audit-logger.d.ts.map +0 -1
- package/dist/utils/audit-logger.js.map +0 -1
- package/dist/utils/cert-pinning.d.ts +0 -97
- package/dist/utils/cert-pinning.d.ts.map +0 -1
- package/dist/utils/cert-pinning.js +0 -328
- package/dist/utils/cert-pinning.js.map +0 -1
- package/dist/utils/cleanup-manager.d.ts.map +0 -1
- package/dist/utils/cleanup-manager.js.map +0 -1
- package/dist/utils/cli-handler.d.ts.map +0 -1
- package/dist/utils/cli-handler.js.map +0 -1
- package/dist/utils/crypto.d.ts.map +0 -1
- package/dist/utils/crypto.js.map +0 -1
- package/dist/utils/file-lock.d.ts.map +0 -1
- package/dist/utils/file-lock.js.map +0 -1
- package/dist/utils/file-permissions.d.ts.map +0 -1
- package/dist/utils/file-permissions.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/page-utils.d.ts.map +0 -1
- package/dist/utils/page-utils.js.map +0 -1
- package/dist/utils/response-validator.d.ts.map +0 -1
- package/dist/utils/response-validator.js.map +0 -1
- package/dist/utils/secrets-scanner.d.ts.map +0 -1
- package/dist/utils/secrets-scanner.js.map +0 -1
- package/dist/utils/secure-memory.d.ts.map +0 -1
- package/dist/utils/secure-memory.js.map +0 -1
- package/dist/utils/security.d.ts.map +0 -1
- package/dist/utils/security.js.map +0 -1
- package/dist/utils/settings-manager.d.ts.map +0 -1
- package/dist/utils/settings-manager.js.map +0 -1
- package/dist/utils/stealth-utils.d.ts.map +0 -1
- package/dist/utils/stealth-utils.js.map +0 -1
- package/dist/utils/tool-validation.d.ts +0 -93
- package/dist/utils/tool-validation.d.ts.map +0 -1
- package/dist/utils/tool-validation.js +0 -277
- package/dist/utils/tool-validation.js.map +0 -1
- package/dist/webhooks/index.d.ts.map +0 -1
- package/dist/webhooks/index.js.map +0 -1
- package/dist/webhooks/types.d.ts.map +0 -1
- package/dist/webhooks/types.js.map +0 -1
- package/dist/webhooks/webhook-dispatcher.d.ts.map +0 -1
- package/dist/webhooks/webhook-dispatcher.js.map +0 -1
- package/docs/COMPLIANCE-SPEC.md +0 -1452
- package/docs/MCP-DIRECTORY-LISTINGS.md +0 -91
- package/docs/SECURITY-FORK-OPPORTUNITIES.md +0 -79
- package/docs/SECURITY_IMPLEMENTATION_PLAN.md +0 -437
- package/docs/archive/ISSUES-legacy-2026-04-24.md +0 -644
- package/docs/configuration.md +0 -94
- package/docs/dependency-risk.md +0 -25
- package/docs/improvement-sprint-2026.2.10.md +0 -210
- package/docs/testing-runbook.md +0 -166
- package/docs/tools.md +0 -34
- package/docs/troubleshooting.md +0 -59
- package/docs/usage-guide.md +0 -246
|
@@ -16,6 +16,29 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { log } from "../utils/logger.js";
|
|
18
18
|
import { randomDelay } from "../utils/stealth-utils.js";
|
|
19
|
+
/**
|
|
20
|
+
* Allowlisted style values. Single source of truth used to validate untrusted
|
|
21
|
+
* input before it is passed into the page context (prevents attribute-selector
|
|
22
|
+
* injection in selectStyle).
|
|
23
|
+
*/
|
|
24
|
+
const VALID_VIDEO_STYLES = [
|
|
25
|
+
"auto-select",
|
|
26
|
+
"custom",
|
|
27
|
+
"classic",
|
|
28
|
+
"whiteboard",
|
|
29
|
+
"kawaii",
|
|
30
|
+
"anime",
|
|
31
|
+
"watercolour",
|
|
32
|
+
"retro-print",
|
|
33
|
+
"heritage",
|
|
34
|
+
"paper-craft",
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Allowlisted format values. Single source of truth used to validate untrusted
|
|
38
|
+
* input before it is passed into the page context (prevents attribute-selector
|
|
39
|
+
* injection in selectFormat).
|
|
40
|
+
*/
|
|
41
|
+
const VALID_VIDEO_FORMATS = ["explainer", "brief"];
|
|
19
42
|
export class VideoManager {
|
|
20
43
|
authManager;
|
|
21
44
|
contextManager;
|
|
@@ -117,6 +140,18 @@ export class VideoManager {
|
|
|
117
140
|
item.classList?.contains("shimmer-green")) {
|
|
118
141
|
return { status: "generating", progress: 0 };
|
|
119
142
|
}
|
|
143
|
+
// Detect an explicit failure state on THIS artifact before assuming ready.
|
|
144
|
+
// A failed generation leaves a non-shimmer artifact, which would otherwise be
|
|
145
|
+
// misreported as "ready". Scope the check to the matched item only — a page-global
|
|
146
|
+
// alert query could match unrelated UI. Class names are best-effort (unconfirmed
|
|
147
|
+
// by live inspection); [role="alert"]/error child is the locale-independent signal.
|
|
148
|
+
const hasErrorChild = !!item.querySelector('[role="alert"], .error-state, .artifact-error');
|
|
149
|
+
if (hasErrorChild ||
|
|
150
|
+
item.classList?.contains("error-state") ||
|
|
151
|
+
item.classList?.contains("artifact-error") ||
|
|
152
|
+
item.classList?.contains("failed")) {
|
|
153
|
+
return { status: "failed" };
|
|
154
|
+
}
|
|
120
155
|
// Otherwise it's ready
|
|
121
156
|
return { status: "ready" };
|
|
122
157
|
}
|
|
@@ -181,17 +216,28 @@ export class VideoManager {
|
|
|
181
216
|
* Select a video format in the dialog (Explainer or Brief)
|
|
182
217
|
*/
|
|
183
218
|
async selectFormat(page, format) {
|
|
219
|
+
// Validate against the allowlist BEFORE the value crosses into the page
|
|
220
|
+
// context. Without this, a value containing `"]` could break out of the
|
|
221
|
+
// attribute selector below (selector injection).
|
|
222
|
+
if (!VALID_VIDEO_FORMATS.includes(format)) {
|
|
223
|
+
log.warning(`video-manager: ignoring non-allowlisted format "${format}"`);
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
184
226
|
return await page.evaluate((fmt) => {
|
|
185
227
|
const browser = globalThis;
|
|
186
228
|
// Format is in mat-radio-group.tile-group
|
|
187
229
|
const radioGroup = browser.document.querySelector("mat-radio-group.tile-group");
|
|
188
230
|
if (!radioGroup)
|
|
189
231
|
return false;
|
|
190
|
-
// Primary: value attribute (locale-independent if Angular Material uses stable values)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
232
|
+
// Primary: value attribute (locale-independent if Angular Material uses stable values).
|
|
233
|
+
// Iterate radio options and compare values with === rather than building a
|
|
234
|
+
// selector from the value, so untrusted text can never alter the selector.
|
|
235
|
+
const options = Array.from(radioGroup.querySelectorAll("[value]"));
|
|
236
|
+
for (const option of options) {
|
|
237
|
+
if (option.getAttribute?.("value") === fmt) {
|
|
238
|
+
option.click();
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
195
241
|
}
|
|
196
242
|
// Fallback: text match (English only — may not work in non-English locales,
|
|
197
243
|
// but selectFormat is best-effort; generation will use default format if this fails)
|
|
@@ -210,17 +256,28 @@ export class VideoManager {
|
|
|
210
256
|
* Select a video style in the dialog carousel
|
|
211
257
|
*/
|
|
212
258
|
async selectStyle(page, style) {
|
|
259
|
+
// Validate against the allowlist BEFORE the value crosses into the page
|
|
260
|
+
// context. Without this, a value containing `"]` could break out of the
|
|
261
|
+
// attribute selector below (selector injection).
|
|
262
|
+
if (!VALID_VIDEO_STYLES.includes(style)) {
|
|
263
|
+
log.warning(`video-manager: ignoring non-allowlisted style "${style}"`);
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
213
266
|
return await page.evaluate((styleName) => {
|
|
214
267
|
const browser = globalThis;
|
|
215
268
|
// Style is in mat-radio-group.carousel-group
|
|
216
269
|
const radioGroup = browser.document.querySelector("mat-radio-group.carousel-group");
|
|
217
270
|
if (!radioGroup)
|
|
218
271
|
return false;
|
|
219
|
-
// Primary: value attribute (locale-independent)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
272
|
+
// Primary: value attribute (locale-independent).
|
|
273
|
+
// Iterate radio options and compare values with === rather than building a
|
|
274
|
+
// selector from the value, so untrusted text can never alter the selector.
|
|
275
|
+
const options = Array.from(radioGroup.querySelectorAll("[value]"));
|
|
276
|
+
for (const option of options) {
|
|
277
|
+
if (option.getAttribute?.("value") === styleName) {
|
|
278
|
+
option.click();
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
224
281
|
}
|
|
225
282
|
// Fallback: text match (English only — style labels are translated in non-English UIs,
|
|
226
283
|
// but selectStyle is best-effort; generation will use default style if this fails)
|
|
@@ -243,14 +300,26 @@ export class VideoManager {
|
|
|
243
300
|
async clickDialogGenerate(page) {
|
|
244
301
|
return await page.evaluate(() => {
|
|
245
302
|
const browser = globalThis;
|
|
246
|
-
// Primary: button
|
|
303
|
+
// Primary: the primary-color action button inside mat-dialog-actions.
|
|
304
|
+
// NEVER blindly click the FIRST button — Material dialogs conventionally place
|
|
305
|
+
// Cancel/Close first and the primary action last, so clicking [0] can hit Cancel
|
|
306
|
+
// and silently abort generation. Match the primary-color class/attribute first,
|
|
307
|
+
// then fall back to the LAST enabled button within the actions container.
|
|
247
308
|
const dialogActions = browser.document.querySelector("mat-dialog-actions");
|
|
248
309
|
if (dialogActions) {
|
|
249
|
-
const
|
|
250
|
-
if (
|
|
251
|
-
|
|
310
|
+
const primaryInActions = dialogActions.querySelector('button.button-color--primary, button[color="primary"]');
|
|
311
|
+
if (primaryInActions) {
|
|
312
|
+
primaryInActions.click();
|
|
252
313
|
return true;
|
|
253
314
|
}
|
|
315
|
+
const actionButtons = Array.from(dialogActions.querySelectorAll("button"));
|
|
316
|
+
for (let i = actionButtons.length - 1; i >= 0; i--) {
|
|
317
|
+
const button = actionButtons[i];
|
|
318
|
+
if (!button.disabled) {
|
|
319
|
+
button.click();
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
254
323
|
}
|
|
255
324
|
// Fallback: button with primary color in any dialog
|
|
256
325
|
const primaryBtn = browser.document.querySelector('.dialog-actions button, button.button-color--primary');
|
|
@@ -341,6 +410,14 @@ export class VideoManager {
|
|
|
341
410
|
await randomDelay(500, 800);
|
|
342
411
|
// Check if generation started
|
|
343
412
|
const newStatus = await this.checkVideoStatusInternal(page);
|
|
413
|
+
if (newStatus.status === "failed") {
|
|
414
|
+
log.warning(" Video generation reported a failed state");
|
|
415
|
+
return {
|
|
416
|
+
success: false,
|
|
417
|
+
status: newStatus,
|
|
418
|
+
error: "Video generation failed.",
|
|
419
|
+
};
|
|
420
|
+
}
|
|
344
421
|
if (newStatus.status === "generating" || newStatus.status === "ready") {
|
|
345
422
|
log.success(` Video generation ${newStatus.status === "ready" ? "completed" : "started"}`);
|
|
346
423
|
return { success: true, status: newStatus };
|
|
@@ -388,4 +465,3 @@ export class VideoManager {
|
|
|
388
465
|
}
|
|
389
466
|
}
|
|
390
467
|
}
|
|
391
|
-
//# sourceMappingURL=video-manager.js.map
|
package/dist/quota/index.d.ts
CHANGED
package/dist/quota/index.js
CHANGED
|
@@ -31,6 +31,17 @@ export declare class QuotaManager {
|
|
|
31
31
|
* Load settings from disk or create defaults
|
|
32
32
|
*/
|
|
33
33
|
private loadSettings;
|
|
34
|
+
/**
|
|
35
|
+
* Validate and sanitise an untrusted (user-writable) settings object.
|
|
36
|
+
*
|
|
37
|
+
* The quota.json file is user-writable, so a tampered or stale file must not
|
|
38
|
+
* be able to disable enforcement (e.g. by setting limits to 1e12/0/strings or
|
|
39
|
+
* omitting usage fields, which would otherwise yield NaN comparisons). Tier is
|
|
40
|
+
* constrained to a known key (falls back to "unknown"); limits are ALWAYS
|
|
41
|
+
* derived from TIER_LIMITS[tier] and never trusted from disk; usage fields are
|
|
42
|
+
* coerced to finite numbers and defaulted when missing.
|
|
43
|
+
*/
|
|
44
|
+
private validateSettings;
|
|
34
45
|
/**
|
|
35
46
|
* Get default settings
|
|
36
47
|
*/
|
|
@@ -40,9 +51,17 @@ export declare class QuotaManager {
|
|
|
40
51
|
*/
|
|
41
52
|
private saveSettings;
|
|
42
53
|
/**
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
* Effective (rolled-over) query count for TODAY, computed WITHOUT mutating or
|
|
55
|
+
* persisting settings. If the stored lastQueryDate is not today, the count is
|
|
56
|
+
* treated as 0 (the day has rolled over) but no write occurs — persisting the
|
|
57
|
+
* rollover is the exclusive responsibility of incrementQueryCountAtomic /
|
|
58
|
+
* checkAndReserveQuery (see I285). Shared by all readers (getStatus,
|
|
59
|
+
* getDetailedStatus, updateQuotaMetrics, canMakeQuery) so they never report a
|
|
60
|
+
* stale pre-rollover count.
|
|
61
|
+
*/
|
|
62
|
+
private effectiveQueriesUsedToday;
|
|
63
|
+
/** Percentage guard: avoid NaN/Infinity when the limit is zero or invalid. */
|
|
64
|
+
private static safePercent;
|
|
46
65
|
private evaluateWithTimeout;
|
|
47
66
|
/**
|
|
48
67
|
* Detect license tier from NotebookLM UI
|
|
@@ -106,6 +125,16 @@ export declare class QuotaManager {
|
|
|
106
125
|
getUsage(): QuotaUsage;
|
|
107
126
|
/**
|
|
108
127
|
* Increment notebook count
|
|
128
|
+
*
|
|
129
|
+
* Uses the same withLock(settingsPath) transaction as
|
|
130
|
+
* incrementQueryCountAtomic (reload-under-lock → increment → persist) so the
|
|
131
|
+
* notebook counter shares ONE concurrency mechanism with the query counters
|
|
132
|
+
* (no separate ad-hoc promise queue). The lock provides mutual exclusion and
|
|
133
|
+
* the reload-under-lock prevents lost updates across concurrent callers;
|
|
134
|
+
* strict FIFO ordering is not required for a counter.
|
|
135
|
+
*
|
|
136
|
+
* Fail-soft contract preserved: this method logs and resolves on error rather
|
|
137
|
+
* than rejecting, since external callers may not catch.
|
|
109
138
|
*/
|
|
110
139
|
incrementNotebookCount(): Promise<void>;
|
|
111
140
|
/**
|
|
@@ -120,6 +149,33 @@ export declare class QuotaManager {
|
|
|
120
149
|
* It reloads settings from disk before incrementing to ensure accuracy.
|
|
121
150
|
*/
|
|
122
151
|
incrementQueryCountAtomic(): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Atomically check the daily quota and reserve (increment) a slot in a single
|
|
154
|
+
* locked, disk-reloaded transaction.
|
|
155
|
+
*
|
|
156
|
+
* This closes the TOCTOU window where concurrent sessions/processes all pass a
|
|
157
|
+
* stale in-memory check (canMakeQuery) and then increment only after the slow
|
|
158
|
+
* browser query completes, collectively exceeding the daily limit. The slot is
|
|
159
|
+
* reserved up front, BEFORE the query runs.
|
|
160
|
+
*
|
|
161
|
+
* Returns { allowed, reason? }. Callers MUST run the query only when allowed,
|
|
162
|
+
* and call releaseReservation() if the query subsequently fails.
|
|
163
|
+
*/
|
|
164
|
+
checkAndReserveQuery(): Promise<{
|
|
165
|
+
allowed: boolean;
|
|
166
|
+
reason?: string;
|
|
167
|
+
}>;
|
|
168
|
+
/**
|
|
169
|
+
* Release a previously reserved query slot (e.g. when the query failed after
|
|
170
|
+
* reservation in checkAndReserveQuery). Atomic and floored at zero so it can
|
|
171
|
+
* never underflow.
|
|
172
|
+
*/
|
|
173
|
+
releaseReservation(): Promise<void>;
|
|
174
|
+
/**
|
|
175
|
+
* Persist current settings to disk while a file lock is already held.
|
|
176
|
+
* Mirrors the write performed inside incrementQueryCountAtomic.
|
|
177
|
+
*/
|
|
178
|
+
private persistWithLockHeld;
|
|
123
179
|
/**
|
|
124
180
|
* Refresh settings from disk with file locking
|
|
125
181
|
*
|
|
@@ -194,4 +250,3 @@ export declare class QuotaManager {
|
|
|
194
250
|
};
|
|
195
251
|
}
|
|
196
252
|
export declare function getQuotaManager(): QuotaManager;
|
|
197
|
-
//# sourceMappingURL=quota-manager.d.ts.map
|
|
@@ -39,8 +39,16 @@ const TIER_LIMITS = {
|
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
41
|
const MAX_REASONABLE_QUERIES = 10000;
|
|
42
|
+
const MAX_REASONABLE_NOTEBOOKS = 100000;
|
|
42
43
|
const PAGE_EVALUATE_TIMEOUT_MS = 30000;
|
|
43
|
-
|
|
44
|
+
/** Type guard: is the given string a known license tier? */
|
|
45
|
+
function isKnownTier(tier) {
|
|
46
|
+
return typeof tier === "string" && Object.prototype.hasOwnProperty.call(TIER_LIMITS, tier);
|
|
47
|
+
}
|
|
48
|
+
/** Always derive limits from the authoritative tier table (never trust on-disk limits). */
|
|
49
|
+
function deriveLimitsForTier(tier) {
|
|
50
|
+
return { ...TIER_LIMITS[tier] };
|
|
51
|
+
}
|
|
44
52
|
export class QuotaManager {
|
|
45
53
|
settings;
|
|
46
54
|
settingsPath;
|
|
@@ -55,9 +63,10 @@ export class QuotaManager {
|
|
|
55
63
|
try {
|
|
56
64
|
if (fs.existsSync(this.settingsPath)) {
|
|
57
65
|
const data = fs.readFileSync(this.settingsPath, "utf-8");
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
const parsed = JSON.parse(data);
|
|
67
|
+
const validated = this.validateSettings(parsed);
|
|
68
|
+
log.info(`📊 Loaded quota settings (tier: ${validated.tier})`);
|
|
69
|
+
return validated;
|
|
61
70
|
}
|
|
62
71
|
}
|
|
63
72
|
catch (error) {
|
|
@@ -66,6 +75,57 @@ export class QuotaManager {
|
|
|
66
75
|
// Return defaults
|
|
67
76
|
return this.getDefaultSettings();
|
|
68
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Validate and sanitise an untrusted (user-writable) settings object.
|
|
80
|
+
*
|
|
81
|
+
* The quota.json file is user-writable, so a tampered or stale file must not
|
|
82
|
+
* be able to disable enforcement (e.g. by setting limits to 1e12/0/strings or
|
|
83
|
+
* omitting usage fields, which would otherwise yield NaN comparisons). Tier is
|
|
84
|
+
* constrained to a known key (falls back to "unknown"); limits are ALWAYS
|
|
85
|
+
* derived from TIER_LIMITS[tier] and never trusted from disk; usage fields are
|
|
86
|
+
* coerced to finite numbers and defaulted when missing.
|
|
87
|
+
*/
|
|
88
|
+
validateSettings(parsed) {
|
|
89
|
+
if (!parsed || typeof parsed !== "object") {
|
|
90
|
+
log.warning("⚠️ Quota settings file is not an object; using defaults");
|
|
91
|
+
return this.getDefaultSettings();
|
|
92
|
+
}
|
|
93
|
+
const obj = parsed;
|
|
94
|
+
const defaults = this.getDefaultSettings();
|
|
95
|
+
// Tier must be a known key, otherwise fall back to a safe default.
|
|
96
|
+
let tier = "unknown";
|
|
97
|
+
if (isKnownTier(obj.tier)) {
|
|
98
|
+
tier = obj.tier;
|
|
99
|
+
}
|
|
100
|
+
else if (obj.tier !== undefined) {
|
|
101
|
+
log.warning(`⚠️ Unknown tier "${String(obj.tier)}" in quota settings; falling back to "unknown"`);
|
|
102
|
+
}
|
|
103
|
+
// CRUCIAL: derive limits from the tier table, never trust on-disk values.
|
|
104
|
+
const limits = deriveLimitsForTier(tier);
|
|
105
|
+
const rawUsage = obj.usage && typeof obj.usage === "object"
|
|
106
|
+
? obj.usage
|
|
107
|
+
: {};
|
|
108
|
+
const coerceCount = (value, max) => {
|
|
109
|
+
const n = Number(value);
|
|
110
|
+
if (!Number.isFinite(n) || n < 0)
|
|
111
|
+
return 0;
|
|
112
|
+
return Math.min(Math.floor(n), max);
|
|
113
|
+
};
|
|
114
|
+
const queriesUsedToday = coerceCount(rawUsage.queriesUsedToday, MAX_REASONABLE_QUERIES);
|
|
115
|
+
const notebooks = coerceCount(rawUsage.notebooks, MAX_REASONABLE_NOTEBOOKS);
|
|
116
|
+
const lastQueryDate = typeof rawUsage.lastQueryDate === "string" && rawUsage.lastQueryDate.length > 0
|
|
117
|
+
? rawUsage.lastQueryDate
|
|
118
|
+
: defaults.usage.lastQueryDate;
|
|
119
|
+
const lastUpdated = typeof rawUsage.lastUpdated === "string" && rawUsage.lastUpdated.length > 0
|
|
120
|
+
? rawUsage.lastUpdated
|
|
121
|
+
: defaults.usage.lastUpdated;
|
|
122
|
+
return {
|
|
123
|
+
tier,
|
|
124
|
+
limits,
|
|
125
|
+
usage: { notebooks, queriesUsedToday, lastQueryDate, lastUpdated },
|
|
126
|
+
autoDetected: typeof obj.autoDetected === "boolean" ? obj.autoDetected : false,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
69
129
|
/**
|
|
70
130
|
* Get default settings
|
|
71
131
|
*/
|
|
@@ -100,18 +160,25 @@ export class QuotaManager {
|
|
|
100
160
|
}
|
|
101
161
|
}
|
|
102
162
|
/**
|
|
103
|
-
*
|
|
163
|
+
* Effective (rolled-over) query count for TODAY, computed WITHOUT mutating or
|
|
164
|
+
* persisting settings. If the stored lastQueryDate is not today, the count is
|
|
165
|
+
* treated as 0 (the day has rolled over) but no write occurs — persisting the
|
|
166
|
+
* rollover is the exclusive responsibility of incrementQueryCountAtomic /
|
|
167
|
+
* checkAndReserveQuery (see I285). Shared by all readers (getStatus,
|
|
168
|
+
* getDetailedStatus, updateQuotaMetrics, canMakeQuery) so they never report a
|
|
169
|
+
* stale pre-rollover count.
|
|
104
170
|
*/
|
|
105
|
-
|
|
171
|
+
effectiveQueriesUsedToday() {
|
|
106
172
|
const today = new Date().toISOString().split("T")[0];
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
173
|
+
return this.settings.usage.lastQueryDate === today
|
|
174
|
+
? this.settings.usage.queriesUsedToday
|
|
175
|
+
: 0;
|
|
176
|
+
}
|
|
177
|
+
/** Percentage guard: avoid NaN/Infinity when the limit is zero or invalid. */
|
|
178
|
+
static safePercent(used, limit) {
|
|
179
|
+
if (!Number.isFinite(limit) || limit <= 0)
|
|
180
|
+
return 0;
|
|
181
|
+
return Math.round((used / limit) * 100);
|
|
115
182
|
}
|
|
116
183
|
async evaluateWithTimeout(page, fn, timeoutMs = PAGE_EVALUATE_TIMEOUT_MS) {
|
|
117
184
|
let timeout;
|
|
@@ -203,11 +270,15 @@ export class QuotaManager {
|
|
|
203
270
|
async extractSourceLimitFromDialog(page) {
|
|
204
271
|
const limitInfo = await this.evaluateWithTimeout(page, () => {
|
|
205
272
|
const browser = globalThis;
|
|
206
|
-
// Look for X/Y pattern
|
|
273
|
+
// Look for the "X / Y" source-count pattern, but ONLY accept a KNOWN
|
|
274
|
+
// source limit (50/300/600). A broad /\d+\/\d+/ matches any unrelated
|
|
275
|
+
// fraction on the page (timestamps, "3/5 steps", etc.), which previously
|
|
276
|
+
// let an arbitrary number through as the source limit and misdetected the
|
|
277
|
+
// tier upward. Mirror the whitelist used by detectTierFromPage.
|
|
207
278
|
const allText = browser.document.body.innerText;
|
|
208
|
-
const match = allText.match(
|
|
279
|
+
const match = allText.match(/\b(\d+)\s*\/\s*(50|300|600)\b/);
|
|
209
280
|
if (match) {
|
|
210
|
-
return parseInt(match[2], 10); // Return the limit (Y in X/Y)
|
|
281
|
+
return parseInt(match[2], 10); // Return the whitelisted limit (Y in X/Y)
|
|
211
282
|
}
|
|
212
283
|
return null;
|
|
213
284
|
});
|
|
@@ -381,11 +452,16 @@ export class QuotaManager {
|
|
|
381
452
|
// Try to extract query usage from UI
|
|
382
453
|
const queryUsage = await this.extractQueryUsageFromUI(page);
|
|
383
454
|
if (queryUsage) {
|
|
384
|
-
// Update local tracking with Google's numbers
|
|
455
|
+
// Update local tracking with Google's numbers.
|
|
385
456
|
this.settings.usage.queriesUsedToday = Math.min(queryUsage.used, MAX_REASONABLE_QUERIES);
|
|
386
|
-
|
|
457
|
+
// Scraped page numbers are untrusted: a spoofed/injected page (e.g.
|
|
458
|
+
// "0/999999") must never raise the enforced daily limit above the
|
|
459
|
+
// documented value for the detected tier. Treat the scraped limit only as
|
|
460
|
+
// a hint and clamp it to the tier's authoritative ceiling.
|
|
461
|
+
const tierCeiling = deriveLimitsForTier(this.settings.tier).queriesPerDay;
|
|
462
|
+
this.settings.limits.queriesPerDay = Math.min(Math.max(1, queryUsage.limit), tierCeiling);
|
|
387
463
|
this.settings.usage.lastQueryDate = new Date().toISOString().split("T")[0];
|
|
388
|
-
log.info(` Synced query usage from Google: ${this.settings.usage.queriesUsedToday}/${
|
|
464
|
+
log.info(` Synced query usage from Google: ${this.settings.usage.queriesUsedToday}/${this.settings.limits.queriesPerDay}`);
|
|
389
465
|
}
|
|
390
466
|
// Check for rate limit
|
|
391
467
|
const rateLimitDetected = await this.checkForRateLimitError(page);
|
|
@@ -451,24 +527,29 @@ export class QuotaManager {
|
|
|
451
527
|
}
|
|
452
528
|
/**
|
|
453
529
|
* Increment notebook count
|
|
530
|
+
*
|
|
531
|
+
* Uses the same withLock(settingsPath) transaction as
|
|
532
|
+
* incrementQueryCountAtomic (reload-under-lock → increment → persist) so the
|
|
533
|
+
* notebook counter shares ONE concurrency mechanism with the query counters
|
|
534
|
+
* (no separate ad-hoc promise queue). The lock provides mutual exclusion and
|
|
535
|
+
* the reload-under-lock prevents lost updates across concurrent callers;
|
|
536
|
+
* strict FIFO ordering is not required for a counter.
|
|
537
|
+
*
|
|
538
|
+
* Fail-soft contract preserved: this method logs and resolves on error rather
|
|
539
|
+
* than rejecting, since external callers may not catch.
|
|
454
540
|
*/
|
|
455
|
-
incrementNotebookCount() {
|
|
456
|
-
|
|
457
|
-
.catch((error) => {
|
|
458
|
-
log.error(`❌ Notebook increment queue recovered from prior failure: ${error}`);
|
|
459
|
-
})
|
|
460
|
-
.then(async () => {
|
|
541
|
+
async incrementNotebookCount() {
|
|
542
|
+
try {
|
|
461
543
|
await withLock(this.settingsPath, async () => {
|
|
462
544
|
this.settings = this.loadSettings();
|
|
463
545
|
this.settings.usage.notebooks++;
|
|
464
546
|
this.settings.usage.lastUpdated = new Date().toISOString();
|
|
465
547
|
this.saveSettings();
|
|
466
548
|
});
|
|
467
|
-
}
|
|
468
|
-
|
|
549
|
+
}
|
|
550
|
+
catch (error) {
|
|
469
551
|
log.error(`❌ Could not increment notebook count: ${error}`);
|
|
470
|
-
}
|
|
471
|
-
return notebookIncrementQueue;
|
|
552
|
+
}
|
|
472
553
|
}
|
|
473
554
|
/**
|
|
474
555
|
* Increment query count (synchronous, for backwards compatibility)
|
|
@@ -520,6 +601,71 @@ export class QuotaManager {
|
|
|
520
601
|
}
|
|
521
602
|
});
|
|
522
603
|
}
|
|
604
|
+
/**
|
|
605
|
+
* Atomically check the daily quota and reserve (increment) a slot in a single
|
|
606
|
+
* locked, disk-reloaded transaction.
|
|
607
|
+
*
|
|
608
|
+
* This closes the TOCTOU window where concurrent sessions/processes all pass a
|
|
609
|
+
* stale in-memory check (canMakeQuery) and then increment only after the slow
|
|
610
|
+
* browser query completes, collectively exceeding the daily limit. The slot is
|
|
611
|
+
* reserved up front, BEFORE the query runs.
|
|
612
|
+
*
|
|
613
|
+
* Returns { allowed, reason? }. Callers MUST run the query only when allowed,
|
|
614
|
+
* and call releaseReservation() if the query subsequently fails.
|
|
615
|
+
*/
|
|
616
|
+
async checkAndReserveQuery() {
|
|
617
|
+
return await withLock(this.settingsPath, async () => {
|
|
618
|
+
// Reload latest settings from disk (another process may have updated).
|
|
619
|
+
this.settings = this.loadSettings();
|
|
620
|
+
const today = new Date().toISOString().split("T")[0];
|
|
621
|
+
// Reset if new day (mirror incrementQueryCountAtomic rollover idiom).
|
|
622
|
+
if (this.settings.usage.lastQueryDate !== today) {
|
|
623
|
+
this.settings.usage.queriesUsedToday = 0;
|
|
624
|
+
this.settings.usage.lastQueryDate = today;
|
|
625
|
+
}
|
|
626
|
+
// CRUCIAL: derive the limit from the tier table, never trust on-disk limit.
|
|
627
|
+
const limit = deriveLimitsForTier(this.settings.tier).queriesPerDay;
|
|
628
|
+
if (this.settings.usage.queriesUsedToday >= limit) {
|
|
629
|
+
getMetricsRegistry().increment("quota_query_denials_total", { tier: this.settings.tier });
|
|
630
|
+
this.updateQuotaMetrics();
|
|
631
|
+
return {
|
|
632
|
+
allowed: false,
|
|
633
|
+
reason: `Daily query limit reached (${this.settings.usage.queriesUsedToday}/${limit}). Try again tomorrow or upgrade your plan.`,
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
// Reserve the slot now, before the query runs.
|
|
637
|
+
this.settings.usage.queriesUsedToday += 1;
|
|
638
|
+
this.settings.usage.lastUpdated = new Date().toISOString();
|
|
639
|
+
this.updateQuotaMetrics();
|
|
640
|
+
this.persistWithLockHeld();
|
|
641
|
+
return { allowed: true };
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Release a previously reserved query slot (e.g. when the query failed after
|
|
646
|
+
* reservation in checkAndReserveQuery). Atomic and floored at zero so it can
|
|
647
|
+
* never underflow.
|
|
648
|
+
*/
|
|
649
|
+
async releaseReservation() {
|
|
650
|
+
await withLock(this.settingsPath, async () => {
|
|
651
|
+
this.settings = this.loadSettings();
|
|
652
|
+
this.settings.usage.queriesUsedToday = Math.max(0, this.settings.usage.queriesUsedToday - 1);
|
|
653
|
+
this.settings.usage.lastUpdated = new Date().toISOString();
|
|
654
|
+
this.updateQuotaMetrics();
|
|
655
|
+
this.persistWithLockHeld();
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Persist current settings to disk while a file lock is already held.
|
|
660
|
+
* Mirrors the write performed inside incrementQueryCountAtomic.
|
|
661
|
+
*/
|
|
662
|
+
persistWithLockHeld() {
|
|
663
|
+
const dir = path.dirname(this.settingsPath);
|
|
664
|
+
if (!fs.existsSync(dir)) {
|
|
665
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
666
|
+
}
|
|
667
|
+
fs.writeFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2), { mode: 0o600 });
|
|
668
|
+
}
|
|
523
669
|
/**
|
|
524
670
|
* Refresh settings from disk with file locking
|
|
525
671
|
*
|
|
@@ -568,10 +714,7 @@ export class QuotaManager {
|
|
|
568
714
|
canMakeQuery() {
|
|
569
715
|
// Pure read: determine effective count without mutating settings.
|
|
570
716
|
// Rollover mutation is handled exclusively in incrementQueryCountAtomic (I285).
|
|
571
|
-
const
|
|
572
|
-
const queriesUsedToday = this.settings.usage.lastQueryDate === today
|
|
573
|
-
? this.settings.usage.queriesUsedToday
|
|
574
|
-
: 0; // New day — treat count as 0 without persisting
|
|
717
|
+
const queriesUsedToday = this.effectiveQueriesUsedToday();
|
|
575
718
|
const { queriesPerDay: limit } = this.settings.limits;
|
|
576
719
|
if (queriesUsedToday >= limit) {
|
|
577
720
|
getMetricsRegistry().increment("quota_query_denials_total", { tier: this.settings.tier });
|
|
@@ -588,32 +731,35 @@ export class QuotaManager {
|
|
|
588
731
|
this.updateQuotaMetrics(queriesUsedToday);
|
|
589
732
|
return { allowed: true };
|
|
590
733
|
}
|
|
591
|
-
updateQuotaMetrics(queriesUsedToday = this.
|
|
734
|
+
updateQuotaMetrics(queriesUsedToday = this.effectiveQueriesUsedToday()) {
|
|
592
735
|
const { tier, limits } = this.settings;
|
|
593
736
|
const registry = getMetricsRegistry();
|
|
594
737
|
registry.setGauge("quota_queries_used", queriesUsedToday, { tier });
|
|
595
738
|
registry.setGauge("quota_queries_limit", limits.queriesPerDay, { tier });
|
|
596
|
-
registry.setGauge("quota_queries_percent",
|
|
739
|
+
registry.setGauge("quota_queries_percent", QuotaManager.safePercent(queriesUsedToday, limits.queriesPerDay), { tier });
|
|
597
740
|
}
|
|
598
741
|
/**
|
|
599
742
|
* Get quota status summary
|
|
600
743
|
*/
|
|
601
744
|
getStatus() {
|
|
602
745
|
const { tier, limits, usage } = this.settings;
|
|
746
|
+
// Use the effective (rolled-over) count so getStatus never reports a stale
|
|
747
|
+
// pre-rollover figure; guard all percentages against a zero/invalid limit.
|
|
748
|
+
const queriesUsedToday = this.effectiveQueriesUsedToday();
|
|
603
749
|
return {
|
|
604
750
|
tier,
|
|
605
751
|
notebooks: {
|
|
606
752
|
used: usage.notebooks,
|
|
607
753
|
limit: limits.notebooks,
|
|
608
|
-
percent:
|
|
754
|
+
percent: QuotaManager.safePercent(usage.notebooks, limits.notebooks),
|
|
609
755
|
},
|
|
610
756
|
sources: {
|
|
611
757
|
limit: limits.sourcesPerNotebook,
|
|
612
758
|
},
|
|
613
759
|
queries: {
|
|
614
|
-
used:
|
|
760
|
+
used: queriesUsedToday,
|
|
615
761
|
limit: limits.queriesPerDay,
|
|
616
|
-
percent:
|
|
762
|
+
percent: QuotaManager.safePercent(queriesUsedToday, limits.queriesPerDay),
|
|
617
763
|
},
|
|
618
764
|
};
|
|
619
765
|
}
|
|
@@ -622,12 +768,16 @@ export class QuotaManager {
|
|
|
622
768
|
* Used to provide visibility to users about when to stop querying for the day
|
|
623
769
|
*/
|
|
624
770
|
getDetailedStatus() {
|
|
625
|
-
|
|
771
|
+
// Pure read of the effective (rolled-over) count — consistent with
|
|
772
|
+
// getStatus/canMakeQuery. Rollover is NOT persisted here; that is the
|
|
773
|
+
// exclusive responsibility of incrementQueryCountAtomic/checkAndReserveQuery
|
|
774
|
+
// (I285), so this reader no longer mutates+persists the rollover.
|
|
626
775
|
const { tier, limits, usage } = this.settings;
|
|
627
|
-
const
|
|
628
|
-
const
|
|
776
|
+
const queriesUsedToday = this.effectiveQueriesUsedToday();
|
|
777
|
+
const queriesRemaining = limits.queriesPerDay - queriesUsedToday;
|
|
778
|
+
const queriesPercentUsed = QuotaManager.safePercent(queriesUsedToday, limits.queriesPerDay);
|
|
629
779
|
const notebooksRemaining = limits.notebooks - usage.notebooks;
|
|
630
|
-
const notebooksPercentUsed =
|
|
780
|
+
const notebooksPercentUsed = QuotaManager.safePercent(usage.notebooks, limits.notebooks);
|
|
631
781
|
// Calculate next reset time (midnight local time)
|
|
632
782
|
const tomorrow = new Date();
|
|
633
783
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
@@ -635,7 +785,7 @@ export class QuotaManager {
|
|
|
635
785
|
// Build warnings list
|
|
636
786
|
const warnings = [];
|
|
637
787
|
if (queriesRemaining <= 0) {
|
|
638
|
-
warnings.push(`CRITICAL: Daily query limit reached (${
|
|
788
|
+
warnings.push(`CRITICAL: Daily query limit reached (${queriesUsedToday}/${limits.queriesPerDay}). Wait until tomorrow or upgrade your plan.`);
|
|
639
789
|
}
|
|
640
790
|
else if (queriesRemaining <= 5) {
|
|
641
791
|
warnings.push(`CRITICAL: Only ${queriesRemaining} queries remaining today! Consider stopping soon.`);
|
|
@@ -652,7 +802,7 @@ export class QuotaManager {
|
|
|
652
802
|
return {
|
|
653
803
|
tier,
|
|
654
804
|
queries: {
|
|
655
|
-
used:
|
|
805
|
+
used: queriesUsedToday,
|
|
656
806
|
limit: limits.queriesPerDay,
|
|
657
807
|
remaining: queriesRemaining,
|
|
658
808
|
percentUsed: queriesPercentUsed,
|
|
@@ -680,4 +830,3 @@ export function getQuotaManager() {
|
|
|
680
830
|
}
|
|
681
831
|
return quotaManagerInstance;
|
|
682
832
|
}
|
|
683
|
-
//# sourceMappingURL=quota-manager.js.map
|