샘플
electron 33.4.11: Notification
검증된 샘플 — npm electron 33.4.11: Notification. node 22 · linux alpine/x64 · docker에서 contract를 실행해 통과했습니다: electron type definitions declare Notification class…
sha256:9e71983ef9c31f915c36cf121ea4d7ea395642c34ad891fddbce19c207ff7458
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 1
- 빌드한 서명 키
- 1
선언된 환경
node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-08-28 |
케이스
HOW- 목표
- verify electron.Notification in pkg:npm/electron@33.4.11
- 패키지
- 심벌
-
- electron.Notification
- 환경
- node 22.23.2
- 생성일
- 2026-08-28T07:29:30Z
컨트랙트
- electron type definitions declare Notification class with static isSupported, constructor options, lifecycle methods, and event signatures across Main and CrossProcessExports namespaces
- Notification constructor validates options and initializes properties with type coercion and defaults
- Notification manages show and close lifecycle transitions with event notifications
- Notification handles interactive user actions including click, action selection, reply input, and failure events
- Notification static isSupported returns boolean platform notification availability
파일
- PROMPT.md
- csx.json
- index.js
- package-lock.json
- package.json
- spec.json
- test/contract.cjs
소스
Clean-room public code sample — generation instructions
Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.
A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.
Goal: verify electron.Notification in pkg:npm/electron@33.4.11
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:npm/electron@33.4.11
Demonstrate these symbols/APIs:
- electron.Notification
Rules:
- One focused purpose; the smallest project that proves the goal.
- Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
- Pin every dependency with a lockfile so resolution is reproducible.
- No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
- No personal names, emails, company names, or project identifiers of any kind.
- No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
- Keep it under 200 files and 256KB packed.
{"case":{"caseId":"case:sha256:a64a6b8e07f5ffd88e69fc11636da1120e641e0e44650e9d8dffb923c667fb5a","constraints":{"executionContext":"node"},"contract":["electron type definitions declare Notification class with static isSupported, constructor options, lifecycle methods, and event signatures across Main and CrossProcessExports namespaces","Notification constructor validates options and initializes properties with type coercion and defaults","Notification manages show and close lifecycle transitions with event notifications","Notification handles interactive user actions including click, action selection, reply input, and failure events","Notification static isSupported returns boolean platform notification availability"],"goal":"verify electron.Notification in pkg:npm/electron@33.4.11","kind":"HOW","packages":["pkg:npm/electron@33.4.11"],"schemaVersion":1,"symbols":["electron.Notification"]},"contractCommand":["node","test/contract.cjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","executionContext":"node","language":"javascript","libc":"glibc","libcVersion":"2.39","moduleSystem":"cjs","os":"linux","osVersionBucket":"24","packageManager":"npm","packageManagerVersion":"10.9.8","runtime":"node","runtimeVersion":"22.23.2","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/electron@33.4.11"],"schemaVersion":1,"subject":"pkg:npm/electron@33.4.11","symbols":["electron.Notification"],"verifierAdapter":"node-typescript@1"}
'use strict';
const fs = require('node:fs');
const path = require('node:path');
const { EventEmitter } = require('node:events');
/**
* Reads and verifies electron.Notification TypeScript definitions from the electron package.
* @returns {{
* staticMethods: string[],
* instanceMethods: string[],
* properties: string[],
* hasConstructorOptions: boolean,
* hasNotificationAction: boolean,
* hasNotificationResponse: boolean,
* isMainExported: boolean,
* isCrossProcessExported: boolean,
* hasNotification: boolean
* }}
*/
function getNotificationDeclarations() {
const electronDir = path.dirname(require.resolve('electron/package.json'));
const dtsPath = path.join(electronDir, 'electron.d.ts');
const dtsContent = fs.readFileSync(dtsPath, 'utf-8');
const staticMethods = [];
const instanceMethods = [];
const properties = [];
const notifIndex = dtsContent.indexOf('class Notification extends NodeEventEmitter');
const actionIndex = dtsContent.indexOf('interface NotificationAction');
if (notifIndex !== -1 && actionIndex !== -1) {
const notifSection = dtsContent.slice(notifIndex, actionIndex);
const expectedStaticMethods = ['isSupported'];
for (const sm of expectedStaticMethods) {
if (notifSection.includes(`static ${sm}(`)) {
staticMethods.push(sm);
}
}
const expectedInstanceMethods = ['show', 'close', 'on', 'off', 'once', 'addListener', 'removeListener'];
for (const im of expectedInstanceMethods) {
if (notifSection.includes(`${im}(`)) {
instanceMethods.push(im);
}
}
const expectedProperties = [
'actions',
'body',
'closeButtonText',
'hasReply',
'replyPlaceholder',
'silent',
'sound',
'subtitle',
'timeoutType',
'title',
'toastXml',
'urgency',
];
for (const prop of expectedProperties) {
if (new RegExp(`\\b${prop}\\s*:`).test(notifSection)) {
properties.push(prop);
}
}
}
const hasConstructorOptions = dtsContent.includes('interface NotificationConstructorOptions');
const hasNotificationAction = dtsContent.includes('interface NotificationAction');
const hasNotificationResponse = dtsContent.includes('interface NotificationResponse');
const isMainExported =
/namespace\s+Main\s*\{[\s\S]*?class\s+Notification\s+extends\s+Electron\.Notification/m.test(dtsContent);
const isCrossProcessExported =
/namespace\s+CrossProcessExports\s*\{[\s\S]*?class\s+Notification\s+extends\s+Electron\.Notification/m.test(dtsContent);
return {
staticMethods,
instanceMethods,
properties,
hasConstructorOptions,
hasNotificationAction,
hasNotificationResponse,
isMainExported,
isCrossProcessExported,
hasNotification:
staticMethods.includes('isSupported') &&
instanceMethods.includes('show') &&
instanceMethods.includes('close') &&
properties.length === 12 &&
hasConstructorOptions &&
hasNotificationAction &&
isMainExported &&
isCrossProcessExported,
};
}
const VALID_TIMEOUT_TYPES = new Set(['default', 'never']);
const VALID_URGENCY_LEVELS = new Set(['normal', 'critical', 'low']);
/**
* Validates and normalizes NotificationConstructorOptions.
* @param {Record<string, any>} [options={}]
* @returns {Record<string, any>} Normalized options
*/
function validateNotificationOptions(options = {}) {
if (options !== null && typeof options !== 'object') {
throw new TypeError('Notification options must be an object');
}
const title = options.title !== undefined ? String(options.title) : '';
const subtitle = options.subtitle !== undefined ? String(options.subtitle) : '';
const body = options.body !== undefined ? String(options.body) : '';
const silent = options.silent !== undefined ? Boolean(options.silent) : false;
const hasReply = options.hasReply !== undefined ? Boolean(options.hasReply) : false;
const replyPlaceholder = options.replyPlaceholder !== undefined ? String(options.replyPlaceholder) : '';
const sound = options.sound !== undefined ? String(options.sound) : '';
const closeButtonText = options.closeButtonText !== undefined ? String(options.closeButtonText) : '';
const toastXml = options.toastXml !== undefined ? String(options.toastXml) : '';
const timeoutType = options.timeoutType !== undefined ? options.timeoutType : 'default';
if (!VALID_TIMEOUT_TYPES.has(timeoutType)) {
throw new TypeError(`Invalid timeoutType: must be 'default' or 'never', got '${timeoutType}'`);
}
const urgency = options.urgency !== undefined ? options.urgency : 'low';
if (!VALID_URGENCY_LEVELS.has(urgency)) {
throw new TypeError(`Invalid urgency: must be 'normal', 'critical', or 'low', got '${urgency}'`);
}
let actions = [];
if (options.actions !== undefined) {
if (!Array.isArray(options.actions)) {
throw new TypeError('actions must be an array');
}
actions = options.actions.map((act, index) => {
if (typeof act !== 'object' || act === null) {
throw new TypeError(`Action at index ${index} must be an object`);
}
return {
type: act.type !== undefined ? String(act.type) : 'button',
text: act.text !== undefined ? String(act.text) : '',
};
});
}
const icon = options.icon !== undefined ? options.icon : undefined;
return {
title,
subtitle,
body,
silent,
icon,
hasReply,
timeoutType,
replyPlaceholder,
sound,
urgency,
actions,
closeButtonText,
toastXml,
};
}
/**
* In-memory Notification emulator implementing Electron Notification specifications.
*/
class Notification extends EventEmitter {
/**
* @param {Record<string, any>} [options={}]
*/
constructor(options = {}) {
super();
const validated = validateNotificationOptions(options);
this._title = validated.title;
this._subtitle = validated.subtitle;
this._body = validated.body;
this._silent = validated.silent;
this._icon = validated.icon;
this._hasReply = validated.hasReply;
this._timeoutType = validated.timeoutType;
this._replyPlaceholder = validated.replyPlaceholder;
this._sound = validated.sound;
this._urgency = validated.urgency;
this._actions = validated.actions;
this._closeButtonText = validated.closeButtonText;
this._toastXml = validated.toastXml;
this._isShowing = false;
this._isClosed = false;
}
/**
* Checks whether desktop notifications are supported.
* @returns {boolean}
*/
static isSupported() {
return true;
}
get title() {
return this._title;
}
set title(val) {
this._title = String(val);
}
get subtitle() {
return this._subtitle;
}
set subtitle(val) {
this._subtitle = String(val);
}
get body() {
return this._body;
}
set body(val) {
this._body = String(val);
}
get silent() {
return this._silent;
}
set silent(val) {
this._silent = Boolean(val);
}
get icon() {
return this._icon;
}
set icon(val) {
this._icon = val;
}
get hasReply() {
return this._hasReply;
}
set hasReply(val) {
this._hasReply = Boolean(val);
}
get timeoutType() {
return this._timeoutType;
}
set timeoutType(val) {
if (!VALID_TIMEOUT_TYPES.has(val)) {
throw new TypeError(`Invalid timeoutType: must be 'default' or 'never', got '${val}'`);
}
this._timeoutType = val;
}
get replyPlaceholder() {
return this._replyPlaceholder;
}
set replyPlaceholder(val) {
this._replyPlaceholder = String(val);
}
get sound() {
return this._sound;
}
set sound(val) {
this._sound = String(val);
}
get urgency() {
return this._urgency;
}
set urgency(val) {
if (!VALID_URGENCY_LEVELS.has(val)) {
throw new TypeError(`Invalid urgency: must be 'normal', 'critical', or 'low', got '${val}'`);
}
this._urgency = val;
}
get actions() {
return this._actions;
}
set actions(val) {
if (!Array.isArray(val)) {
throw new TypeError('actions must be an array');
}
this._actions = val.map((act, idx) => {
if (typeof act !== 'object' || act === null) {
throw new TypeError(`Action at index ${idx} must be an object`);
}
return {
type: act.type !== undefined ? String(act.type) : 'button',
text: act.text !== undefined ? String(act.text) : '',
};
});
}
get closeButtonText() {
return this._closeButtonText;
}
set closeButtonText(val) {
this._closeButtonText = String(val);
}
get toastXml() {
return this._toastXml;
}
set toastXml(val) {
this._toastXml = String(val);
}
/**
* Shows the notification and emits 'show' event.
*/
show() {
this._isShowing = true;
this._isClosed = false;
const event = { type: 'show', sender: this };
this.emit('show', event);
}
/**
* Closes the notification and emits 'close' event.
*/
close() {
if (this._isShowing && !this._isClosed) {
this._isShowing = false;
this._isClosed = true;
const event = { type: 'close', sender: this };
this.emit('close', event);
}
}
/**
* Internal simulator for click event.
*/
_simulateClick() {
const event = { type: 'click', sender: this };
this.emit('click', event);
}
/**
* Internal simulator for action event.
* @param {number} actionIndex
*/
_simulateAction(actionIndex) {
const event = { type: 'action', sender: this };
this.emit('action', event, actionIndex);
}
/**
* Internal simulator for reply event.
* @param {string} replyText
*/
_simulateReply(replyText) {
const event = { type: 'reply', sender: this };
this.emit('reply', event, replyText);
}
/**
* Internal simulator for failed event.
* @param {string} errorMessage
*/
_simulateFailed(errorMessage) {
const event = { type: 'failed', sender: this };
this.emit('failed', event, errorMessage);
}
}
module.exports = {
getNotificationDeclarations,
validateNotificationOptions,
Notification,
};
{
"name": "sample-electron-notification",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sample-electron-notification",
"version": "1.0.0",
"license": "MIT-0",
"dependencies": {
"electron": "33.4.11"
}
},
"node_modules/@electron/get": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz",
"integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.1.1",
"env-paths": "^2.2.0",
"fs-extra": "^8.1.0",
"got": "^11.8.5",
"progress": "^2.0.3",
"semver": "^6.2.0",
"sumchecker": "^3.0.1"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"global-agent": "^3.0.0"
}
},
"node_modules/@sindresorhus/is": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sindresorhus/is?sponsor=1"
}
},
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
"license": "MIT",
"dependencies": {
"defer-to-connect": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@types/cacheable-request": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
"integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
"license": "MIT",
"dependencies": {
"@types/http-cache-semantics": "*",
"@types/keyv": "^3.1.4",
"@types/node": "*",
"@types/responselike": "^1.0.0"
}
},
"node_modules/@types/http-cache-semantics": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
"integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==",
"license": "MIT"
},
"node_modules/@types/keyv": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
"integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "20.19.43",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
"integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@types/responselike": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
"integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/yauzl": {
"version": "2.10.3",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
"license": "MIT",
"optional": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/boolean": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
"integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"license": "MIT",
"optional": true
},
"node_modules/buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/cacheable-lookup": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
"license": "MIT",
"engines": {
"node": ">=10.6.0"
}
},
"node_modules/cacheable-request": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
"integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
"license": "MIT",
"dependencies": {
"clone-response": "^1.0.2",
"get-stream": "^5.1.0",
"http-cache-semantics": "^4.0.0",
"keyv": "^4.0.0",
"lowercase-keys": "^2.0.0",
"normalize-url": "^6.0.1",
"responselike": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/clone-response": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
"integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
"license": "MIT",
"dependencies": {
"mimic-response": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"license": "MIT",
"dependencies": {
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/decompress-response/node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/defer-to-connect": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"optional": true,
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/define-properties": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
"license": "MIT",
"optional": true,
"dependencies": {
"define-data-property": "^1.0.1",
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/detect-node": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
"license": "MIT",
"optional": true
},
"node_modules/electron": {
"version": "33.4.11",
"resolved": "https://registry.npmjs.org/electron/-/electron-33.4.11.tgz",
"integrity": "sha512-xmdAs5QWRkInC7TpXGNvzo/7exojubk+72jn1oJL7keNeIlw7xNglf8TGtJtkR4rWC5FJq0oXiIXPS9BcK2Irg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@electron/get": "^2.0.0",
"@types/node": "^20.9.0",
"extract-zip": "^2.0.1"
},
"bin": {
"electron": "cli.js"
},
"engines": {
"node": ">= 12.20.55"
}
},
"node_modules/end-of-stream": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
"license": "MIT",
"dependencies": {
"once": "^1.4.0"
}
},
"node_modules/env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es6-error": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
"license": "MIT",
"optional": true
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/extract-zip": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
"license": "BSD-2-Clause",
"dependencies": {
"debug": "^4.1.1",
"get-stream": "^5.1.0",
"yauzl": "^2.10.0"
},
"bin": {
"extract-zip": "cli.js"
},
"engines": {
"node": ">= 10.17.0"
},
"optionalDependencies": {
"@types/yauzl": "^2.9.1"
}
},
"node_modules/fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
"integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
"license": "MIT",
"dependencies": {
"pend": "~1.2.0"
}
},
"node_modules/fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
},
"engines": {
"node": ">=6 <7 || >=8"
}
},
"node_modules/get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"license": "MIT",
"dependencies": {
"pump": "^3.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/global-agent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
"integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
"license": "BSD-3-Clause",
"optional": true,
"dependencies": {
"boolean": "^3.0.1",
"es6-error": "^4.1.1",
"matcher": "^3.0.0",
"roarr": "^2.15.3",
"semver": "^7.3.2",
"serialize-error": "^7.0.1"
},
"engines": {
"node": ">=10.0"
}
},
"node_modules/global-agent/node_modules/semver": {
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"license": "ISC",
"optional": true,
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/globalthis": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"define-properties": "^1.2.1",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/got": {
"version": "11.8.6",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
"license": "MIT",
"dependencies": {
"@sindresorhus/is": "^4.0.0",
"@szmarczak/http-timer": "^4.0.5",
"@types/cacheable-request": "^6.0.1",
"@types/responselike": "^1.0.0",
"cacheable-lookup": "^5.0.3",
"cacheable-request": "^7.0.2",
"decompress-response": "^6.0.0",
"http2-wrapper": "^1.0.0-beta.5.2",
"lowercase-keys": "^2.0.0",
"p-cancelable": "^2.0.0",
"responselike": "^2.0.0"
},
"engines": {
"node": ">=10.19.0"
},
"funding": {
"url": "https://github.com/sindresorhus/got?sponsor=1"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"license": "MIT",
"optional": true,
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/http-cache-semantics": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
"license": "BSD-2-Clause"
},
"node_modules/http2-wrapper": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
"license": "MIT",
"dependencies": {
"quick-lru": "^5.1.1",
"resolve-alpn": "^1.0.0"
},
"engines": {
"node": ">=10.19.0"
}
},
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"license": "MIT"
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
"license": "ISC",
"optional": true
},
"node_modules/jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
"license": "MIT",
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"license": "MIT",
"dependencies": {
"json-buffer": "3.0.1"
}
},
"node_modules/lowercase-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/matcher": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
"integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
"license": "MIT",
"optional": true,
"dependencies": {
"escape-string-regexp": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/mimic-response": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/p-cancelable": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
"license": "MIT"
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/pump": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
"license": "MIT",
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"node_modules/quick-lru": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/resolve-alpn": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
"license": "MIT"
},
"node_modules/responselike": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
"integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
"license": "MIT",
"dependencies": {
"lowercase-keys": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/roarr": {
"version": "2.15.4",
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
"integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
"license": "BSD-3-Clause",
"optional": true,
"dependencies": {
"boolean": "^3.0.1",
"detect-node": "^2.0.4",
"globalthis": "^1.0.1",
"json-stringify-safe": "^5.0.1",
"semver-compare": "^1.0.0",
"sprintf-js": "^1.1.2"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/semver-compare": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
"license": "MIT",
"optional": true
},
"node_modules/serialize-error": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
"license": "MIT",
"optional": true,
"dependencies": {
"type-fest": "^0.13.1"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
"license": "BSD-3-Clause",
"optional": true
},
"node_modules/sumchecker": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
"integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
"license": "Apache-2.0",
"dependencies": {
"debug": "^4.1.0"
},
"engines": {
"node": ">= 8.0"
}
},
"node_modules/type-fest": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
"license": "(MIT OR CC0-1.0)",
"optional": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"license": "MIT"
},
"node_modules/universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC"
},
"node_modules/yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
"integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
"license": "MIT",
"dependencies": {
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.1.0"
}
}
}
}
{
"name": "sample-electron-notification",
"version": "1.0.0",
"description": "verify electron.Notification in pkg:npm/electron@33.4.11",
"main": "index.js",
"license": "MIT-0",
"dependencies": {
"electron": "33.4.11"
}
}
{
"schemaVersion": 1,
"goal": "verify electron.Notification in pkg:npm/electron@33.4.11",
"kind": "HOW",
"packages": [
"pkg:npm/electron@33.4.11"
],
"symbols": [
"electron.Notification"
]
}
'use strict';
const assert = require('node:assert');
const {
getNotificationDeclarations,
validateNotificationOptions,
Notification,
} = require('../index.js');
async function runContract() {
// 1. electron type definitions declare Notification class with static isSupported, constructor options, lifecycle methods, and event signatures across Main and CrossProcessExports namespaces
{
const decls = getNotificationDeclarations();
assert.strictEqual(decls.hasNotification, true, 'Notification declarations should be valid');
assert.ok(decls.staticMethods.includes('isSupported'), 'static isSupported declared');
assert.ok(decls.instanceMethods.includes('show'), 'instance show declared');
assert.ok(decls.instanceMethods.includes('close'), 'instance close declared');
assert.ok(decls.instanceMethods.includes('on'), 'instance on declared');
assert.ok(decls.instanceMethods.includes('off'), 'instance off declared');
assert.ok(decls.instanceMethods.includes('once'), 'instance once declared');
assert.ok(decls.instanceMethods.includes('addListener'), 'instance addListener declared');
assert.ok(decls.instanceMethods.includes('removeListener'), 'instance removeListener declared');
const expectedProps = [
'actions',
'body',
'closeButtonText',
'hasReply',
'replyPlaceholder',
'silent',
'sound',
'subtitle',
'timeoutType',
'title',
'toastXml',
'urgency',
];
for (const prop of expectedProps) {
assert.ok(decls.properties.includes(prop), `Property ${prop} must be declared`);
}
assert.strictEqual(decls.hasConstructorOptions, true, 'NotificationConstructorOptions interface must be declared');
assert.strictEqual(decls.hasNotificationAction, true, 'NotificationAction interface must be declared');
assert.strictEqual(decls.hasNotificationResponse, true, 'NotificationResponse interface must be declared');
assert.strictEqual(decls.isMainExported, true, 'Notification must be declared in Main namespace');
assert.strictEqual(decls.isCrossProcessExported, true, 'Notification must be declared in CrossProcessExports namespace');
}
// 2. Notification constructor validates options and initializes properties with type coercion and defaults
{
const notifDefault = new Notification();
assert.strictEqual(notifDefault.title, '');
assert.strictEqual(notifDefault.subtitle, '');
assert.strictEqual(notifDefault.body, '');
assert.strictEqual(notifDefault.silent, false);
assert.strictEqual(notifDefault.hasReply, false);
assert.strictEqual(notifDefault.timeoutType, 'default');
assert.strictEqual(notifDefault.urgency, 'low');
assert.deepStrictEqual(notifDefault.actions, []);
assert.strictEqual(notifDefault.closeButtonText, '');
assert.strictEqual(notifDefault.toastXml, '');
const customOptions = {
title: 'Alert Notification',
subtitle: 'Process Complete',
body: 'All files have been processed successfully.',
silent: true,
hasReply: true,
replyPlaceholder: 'Enter response...',
sound: 'alert.wav',
timeoutType: 'never',
urgency: 'critical',
actions: [
{ type: 'button', text: 'View Report' },
{ type: 'button', text: 'Dismiss' },
],
closeButtonText: 'Close Window',
toastXml: '<toast><visual><binding><text>Alert</text></binding></visual></toast>',
};
const notifCustom = new Notification(customOptions);
assert.strictEqual(notifCustom.title, 'Alert Notification');
assert.strictEqual(notifCustom.subtitle, 'Process Complete');
assert.strictEqual(notifCustom.body, 'All files have been processed successfully.');
assert.strictEqual(notifCustom.silent, true);
assert.strictEqual(notifCustom.hasReply, true);
assert.strictEqual(notifCustom.replyPlaceholder, 'Enter response...');
assert.strictEqual(notifCustom.sound, 'alert.wav');
assert.strictEqual(notifCustom.timeoutType, 'never');
assert.strictEqual(notifCustom.urgency, 'critical');
assert.strictEqual(notifCustom.actions.length, 2);
assert.strictEqual(notifCustom.actions[0].text, 'View Report');
assert.strictEqual(notifCustom.closeButtonText, 'Close Window');
assert.strictEqual(notifCustom.toastXml, '<toast><visual><binding><text>Alert</text></binding></visual></toast>');
// Property mutations via setters
notifCustom.title = 'Updated Title';
assert.strictEqual(notifCustom.title, 'Updated Title');
notifCustom.body = 'Updated Body';
assert.strictEqual(notifCustom.body, 'Updated Body');
notifCustom.silent = false;
assert.strictEqual(notifCustom.silent, false);
notifCustom.urgency = 'normal';
assert.strictEqual(notifCustom.urgency, 'normal');
notifCustom.timeoutType = 'default';
assert.strictEqual(notifCustom.timeoutType, 'default');
// Error throwing on invalid options
assert.throws(() => validateNotificationOptions('invalid'), TypeError);
assert.throws(() => validateNotificationOptions({ timeoutType: 'invalid' }), TypeError);
assert.throws(() => validateNotificationOptions({ urgency: 'invalid' }), TypeError);
assert.throws(() => validateNotificationOptions({ actions: 'not-array' }), TypeError);
assert.throws(() => {
notifDefault.timeoutType = 'invalid';
}, TypeError);
assert.throws(() => {
notifDefault.urgency = 'invalid';
}, TypeError);
assert.throws(() => {
notifDefault.actions = 'not-array';
}, TypeError);
}
// 3. Notification manages show and close lifecycle transitions with event notifications
{
const notif = new Notification({ title: 'Lifecycle Test' });
let showCount = 0;
let closeCount = 0;
notif.on('show', (event) => {
showCount += 1;
assert.strictEqual(event.type, 'show');
assert.strictEqual(event.sender, notif);
});
notif.on('close', (event) => {
closeCount += 1;
assert.strictEqual(event.type, 'close');
assert.strictEqual(event.sender, notif);
});
assert.strictEqual(showCount, 0);
assert.strictEqual(closeCount, 0);
notif.show();
assert.strictEqual(showCount, 1);
assert.strictEqual(closeCount, 0);
// Multiple shows re-emit show event
notif.show();
assert.strictEqual(showCount, 2);
// Closing emits close event
notif.close();
assert.strictEqual(closeCount, 1);
// Redundant close does not re-emit
notif.close();
assert.strictEqual(closeCount, 1);
}
// 4. Notification handles interactive user actions including click, action selection, reply input, and failure events
{
const notif = new Notification({
title: 'Interactive Test',
actions: [{ type: 'button', text: 'Action 1' }],
});
let clicked = false;
let actionIndex = -1;
let replyText = '';
let errorMessage = '';
const clickListener = (event) => {
clicked = true;
assert.strictEqual(event.type, 'click');
assert.strictEqual(event.sender, notif);
};
notif.on('click', clickListener);
notif.on('action', (event, index) => {
actionIndex = index;
assert.strictEqual(event.type, 'action');
assert.strictEqual(event.sender, notif);
});
notif.on('reply', (event, text) => {
replyText = text;
assert.strictEqual(event.type, 'reply');
assert.strictEqual(event.sender, notif);
});
notif.on('failed', (event, err) => {
errorMessage = err;
assert.strictEqual(event.type, 'failed');
assert.strictEqual(event.sender, notif);
});
notif.show();
notif._simulateClick();
assert.strictEqual(clicked, true);
notif._simulateAction(0);
assert.strictEqual(actionIndex, 0);
notif._simulateReply('User feedback response');
assert.strictEqual(replyText, 'User feedback response');
notif._simulateFailed('Notification service unavailable');
assert.strictEqual(errorMessage, 'Notification service unavailable');
// Event listener removal
notif.off('click', clickListener);
clicked = false;
notif._simulateClick();
assert.strictEqual(clicked, false, 'Listener should not fire after removal');
}
// 5. Notification static isSupported returns boolean platform notification availability
{
const supported = Notification.isSupported();
assert.strictEqual(typeof supported, 'boolean');
assert.strictEqual(supported, true);
}
console.log('All contract assertions passed successfully.');
}
runContract().catch((err) => {
console.error('Contract test failed:', err);
process.exit(1);
});
오리진 시더
익명