@coeiro-operator/core 1.0.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.
Files changed (32) hide show
  1. package/README.md +11 -0
  2. package/dist/common/config-paths.d.ts +12 -0
  3. package/dist/common/config-paths.js +43 -0
  4. package/dist/dictionary/default-dictionaries.d.ts +20 -0
  5. package/dist/dictionary/default-dictionaries.js +48 -0
  6. package/dist/dictionary/dictionary-client.d.ts +73 -0
  7. package/dist/dictionary/dictionary-client.js +115 -0
  8. package/dist/dictionary/dictionary-persistence.d.ts +48 -0
  9. package/dist/dictionary/dictionary-persistence.js +82 -0
  10. package/dist/dictionary/dictionary-service.d.ts +32 -0
  11. package/dist/dictionary/dictionary-service.js +102 -0
  12. package/dist/environment/speaker-provider.d.ts +72 -0
  13. package/dist/environment/speaker-provider.js +174 -0
  14. package/dist/index.d.ts +19 -0
  15. package/dist/index.js +27 -0
  16. package/dist/operator/character-defaults.d.ts +20 -0
  17. package/dist/operator/character-defaults.js +128 -0
  18. package/dist/operator/character-info-service.d.ts +73 -0
  19. package/dist/operator/character-info-service.js +152 -0
  20. package/dist/operator/config-manager.d.ts +145 -0
  21. package/dist/operator/config-manager.js +232 -0
  22. package/dist/operator/file-operation-manager.d.ts +82 -0
  23. package/dist/operator/file-operation-manager.js +230 -0
  24. package/dist/operator/index.d.ts +128 -0
  25. package/dist/operator/index.js +353 -0
  26. package/dist/terminal/terminal-background.d.ts +37 -0
  27. package/dist/terminal/terminal-background.js +207 -0
  28. package/dist/test-utils/test-env.d.ts +10 -0
  29. package/dist/test-utils/test-env.js +13 -0
  30. package/dist/types.d.ts +58 -0
  31. package/dist/types.js +5 -0
  32. package/package.json +54 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * src/operator/config-manager.ts: 設定管理システム
3
+ * 動的音声フォント取得、設定マージ、キャッシュ管理を担当
4
+ */
5
+ import { BaseCharacterConfig, CharacterConfig } from './character-defaults.js';
6
+ import { AudioConfig, FullConfig as BaseFullConfig } from '../types.js';
7
+ export interface FullConfig extends Omit<BaseFullConfig, 'characters'> {
8
+ characters: Record<string, BaseCharacterConfig | CharacterConfig>;
9
+ }
10
+ export interface TerminalBackgroundConfig {
11
+ enabled: boolean;
12
+ backgroundImages?: {
13
+ [characterId: string]: string;
14
+ };
15
+ operatorImage?: {
16
+ display: 'api' | 'file' | 'none';
17
+ position: 'top-right' | 'bottom-right';
18
+ opacity: number;
19
+ filePath?: string;
20
+ };
21
+ }
22
+ interface Config {
23
+ connection: {
24
+ host: string;
25
+ port: string;
26
+ };
27
+ audio: AudioConfig;
28
+ operator: {
29
+ rate: number;
30
+ timeout: number;
31
+ assignmentStrategy: 'random';
32
+ };
33
+ terminal: {
34
+ background: TerminalBackgroundConfig;
35
+ };
36
+ characters: Record<string, Partial<BaseCharacterConfig> & {
37
+ speakerId?: string;
38
+ disabled?: boolean;
39
+ }>;
40
+ }
41
+ type UserConfig = Partial<Config>;
42
+ declare const DEFAULT_CONFIG: {
43
+ readonly connection: {
44
+ readonly host: "localhost";
45
+ readonly port: "50032";
46
+ };
47
+ readonly operator: {
48
+ readonly rate: 200;
49
+ readonly timeout: 14400000;
50
+ readonly assignmentStrategy: "random";
51
+ };
52
+ readonly terminal: {
53
+ readonly background: {
54
+ readonly enabled: true;
55
+ readonly operatorImage: {
56
+ readonly display: "api";
57
+ readonly position: "bottom-right";
58
+ readonly opacity: 0.3;
59
+ };
60
+ };
61
+ };
62
+ };
63
+ interface MergedConfig {
64
+ characters: Record<string, CharacterConfig>;
65
+ operatorTimeout: number;
66
+ characterSettings: {
67
+ assignmentStrategy: 'random';
68
+ };
69
+ }
70
+ export declare class ConfigManager {
71
+ private configDir;
72
+ private configFile;
73
+ private mergedConfig;
74
+ private speakerProvider;
75
+ constructor(configDir: string);
76
+ /**
77
+ * JSONファイルを安全に読み込み
78
+ */
79
+ readJsonFile<T>(filePath: string, defaultValue: T): Promise<T>;
80
+ /**
81
+ * JSONファイルを安全に書き込み
82
+ */
83
+ writeJsonFile(filePath: string, data: unknown): Promise<void>;
84
+ /**
85
+ * 統一設定ファイルを読み込み
86
+ */
87
+ loadConfig(): Promise<UserConfig>;
88
+ /**
89
+ * 接続設定を更新して音声プロバイダを再設定
90
+ */
91
+ private updateVoiceProviderConnection;
92
+ /**
93
+ * 動的設定を構築してマージ
94
+ */
95
+ buildDynamicConfig(): Promise<void>;
96
+ /**
97
+ * マージ済み設定を取得
98
+ */
99
+ getMergedConfig(): MergedConfig | null;
100
+ /**
101
+ * キャラクター設定を取得
102
+ */
103
+ getCharacterConfig(characterId: string): Promise<CharacterConfig | null>;
104
+ /**
105
+ * 利用可能なキャラクターIDを取得
106
+ */
107
+ getAvailableCharacterIds(): Promise<string[]>;
108
+ /**
109
+ * オペレータのタイムアウト時間を取得
110
+ */
111
+ getOperatorTimeout(): Promise<number>;
112
+ /**
113
+ * 設定ディレクトリの存在確認と作成
114
+ */
115
+ ensureConfigDir(): Promise<void>;
116
+ /**
117
+ * 話速(rate)を取得
118
+ */
119
+ getRate(): Promise<number>;
120
+ /**
121
+ * ターミナル背景設定を取得
122
+ */
123
+ getTerminalBackgroundConfig(): Promise<TerminalBackgroundConfig>;
124
+ /**
125
+ * 接続設定を取得
126
+ */
127
+ getConnectionConfig(): Promise<{
128
+ host: string;
129
+ port: string;
130
+ }>;
131
+ /**
132
+ * 音声設定を取得
133
+ */
134
+ getAudioConfig(): Promise<AudioConfig>;
135
+ /**
136
+ * オペレータ設定を取得
137
+ */
138
+ getOperatorConfig(): Promise<typeof DEFAULT_CONFIG.operator>;
139
+ /**
140
+ * 完全なConfig型を取得(SayCoeiroink用)
141
+ */
142
+ getFullConfig(): Promise<FullConfig>;
143
+ }
144
+ export default ConfigManager;
145
+ //# sourceMappingURL=config-manager.d.ts.map
@@ -0,0 +1,232 @@
1
+ /**
2
+ * src/operator/config-manager.ts: 設定管理システム
3
+ * 動的音声フォント取得、設定マージ、キャッシュ管理を担当
4
+ */
5
+ import { readFile, writeFile, mkdir, access } from 'fs/promises';
6
+ import { constants } from 'fs';
7
+ import { join } from 'path';
8
+ import { BUILTIN_CHARACTER_CONFIGS, } from './character-defaults.js';
9
+ import { getSpeakerProvider } from '../environment/speaker-provider.js';
10
+ import { deepMerge } from '@coeiro-operator/common';
11
+ // デフォルト設定の定義(必須フィールドのみ)
12
+ const DEFAULT_CONFIG = {
13
+ connection: {
14
+ host: 'localhost',
15
+ port: '50032',
16
+ },
17
+ operator: {
18
+ rate: 200,
19
+ timeout: 14400000, // 4時間
20
+ assignmentStrategy: 'random',
21
+ },
22
+ terminal: {
23
+ background: {
24
+ enabled: true,
25
+ operatorImage: {
26
+ display: 'api',
27
+ position: 'bottom-right',
28
+ opacity: 0.3,
29
+ },
30
+ },
31
+ },
32
+ // audio と characters はオプショナルなので、実装で必要に応じて設定
33
+ };
34
+ export class ConfigManager {
35
+ configDir;
36
+ configFile;
37
+ mergedConfig = null;
38
+ speakerProvider = getSpeakerProvider();
39
+ constructor(configDir) {
40
+ this.configDir = configDir;
41
+ this.configFile = join(configDir, 'config.json');
42
+ }
43
+ /**
44
+ * JSONファイルを安全に読み込み
45
+ */
46
+ async readJsonFile(filePath, defaultValue) {
47
+ try {
48
+ await access(filePath, constants.F_OK);
49
+ const content = await readFile(filePath, 'utf8');
50
+ return JSON.parse(content);
51
+ }
52
+ catch {
53
+ return defaultValue;
54
+ }
55
+ }
56
+ /**
57
+ * JSONファイルを安全に書き込み
58
+ */
59
+ async writeJsonFile(filePath, data) {
60
+ const tempFile = `${filePath}.tmp`;
61
+ await writeFile(tempFile, JSON.stringify(data, null, 2), 'utf8');
62
+ try {
63
+ const fs = await import('fs');
64
+ await fs.promises.rename(tempFile, filePath);
65
+ }
66
+ catch (error) {
67
+ console.error(`設定ファイル書き込みエラー: ${error.message}`);
68
+ throw error;
69
+ }
70
+ }
71
+ /**
72
+ * 統一設定ファイルを読み込み
73
+ */
74
+ async loadConfig() {
75
+ return await this.readJsonFile(this.configFile, {});
76
+ }
77
+ /**
78
+ * 接続設定を更新して音声プロバイダを再設定
79
+ */
80
+ async updateVoiceProviderConnection() {
81
+ try {
82
+ const connectionConfig = await this.getConnectionConfig();
83
+ this.speakerProvider.updateConnection(connectionConfig);
84
+ }
85
+ catch (error) {
86
+ console.error(`接続設定更新エラー: ${error.message}`);
87
+ }
88
+ }
89
+ /**
90
+ * 動的設定を構築してマージ
91
+ */
92
+ async buildDynamicConfig() {
93
+ await this.updateVoiceProviderConnection();
94
+ const config = await this.loadConfig();
95
+ try {
96
+ const speakers = await this.speakerProvider.getSpeakers();
97
+ const dynamicCharacters = {};
98
+ // speakersがundefinedまたは配列でない場合は空の配列として扱う
99
+ const availableSpeakers = Array.isArray(speakers) ? speakers : [];
100
+ for (const [characterId, builtinConfig] of Object.entries(BUILTIN_CHARACTER_CONFIGS)) {
101
+ // speakerIdでCOEIROINKのSpeakerとマッチング
102
+ const speaker = availableSpeakers.find(s => s.speakerUuid === builtinConfig.speakerId);
103
+ if (!speaker)
104
+ continue; // 利用可能なspeakerがない場合はスキップ
105
+ // ユーザー設定はcharacterIdで管理
106
+ const userCharacterConfig = config.characters?.[characterId] || {};
107
+ if (userCharacterConfig.disabled)
108
+ continue;
109
+ // 利用可能なスタイル一覧を追加
110
+ const availableStyles = speaker.styles?.map(s => s.styleName) || [];
111
+ dynamicCharacters[characterId] = {
112
+ ...builtinConfig,
113
+ availableStyles,
114
+ ...userCharacterConfig,
115
+ };
116
+ }
117
+ const operatorConfig = await this.getOperatorConfig();
118
+ this.mergedConfig = {
119
+ characters: dynamicCharacters,
120
+ operatorTimeout: operatorConfig.timeout,
121
+ characterSettings: {
122
+ assignmentStrategy: operatorConfig.assignmentStrategy,
123
+ },
124
+ };
125
+ }
126
+ catch (error) {
127
+ console.error(`動的設定構築エラー:`, error);
128
+ // サーバーから取得できなかった場合は空の設定を使用
129
+ const staticCharacters = {};
130
+ this.mergedConfig = {
131
+ characters: staticCharacters,
132
+ operatorTimeout: config.operator?.timeout || 14400000,
133
+ characterSettings: {
134
+ assignmentStrategy: config.operator?.assignmentStrategy || 'random',
135
+ },
136
+ };
137
+ }
138
+ }
139
+ /**
140
+ * マージ済み設定を取得
141
+ */
142
+ getMergedConfig() {
143
+ return this.mergedConfig;
144
+ }
145
+ /**
146
+ * キャラクター設定を取得
147
+ */
148
+ async getCharacterConfig(characterId) {
149
+ if (!this.mergedConfig) {
150
+ await this.buildDynamicConfig();
151
+ }
152
+ return this.mergedConfig?.characters[characterId] || null;
153
+ }
154
+ /**
155
+ * 利用可能なキャラクターIDを取得
156
+ */
157
+ async getAvailableCharacterIds() {
158
+ if (!this.mergedConfig) {
159
+ await this.buildDynamicConfig();
160
+ }
161
+ return Object.keys(this.mergedConfig?.characters || {});
162
+ }
163
+ /**
164
+ * オペレータのタイムアウト時間を取得
165
+ */
166
+ async getOperatorTimeout() {
167
+ const operatorConfig = await this.getOperatorConfig();
168
+ return operatorConfig.timeout;
169
+ }
170
+ /**
171
+ * 設定ディレクトリの存在確認と作成
172
+ */
173
+ async ensureConfigDir() {
174
+ try {
175
+ await mkdir(this.configDir, { recursive: true });
176
+ }
177
+ catch (error) {
178
+ console.error(`設定ディレクトリ作成エラー: ${error.message}`);
179
+ }
180
+ }
181
+ /**
182
+ * 話速(rate)を取得
183
+ */
184
+ async getRate() {
185
+ const operatorConfig = await this.getOperatorConfig();
186
+ return operatorConfig.rate;
187
+ }
188
+ /**
189
+ * ターミナル背景設定を取得
190
+ */
191
+ async getTerminalBackgroundConfig() {
192
+ const config = await this.loadConfig();
193
+ return deepMerge(DEFAULT_CONFIG.terminal.background, config.terminal?.background);
194
+ }
195
+ /**
196
+ * 接続設定を取得
197
+ */
198
+ async getConnectionConfig() {
199
+ const config = await this.loadConfig();
200
+ return deepMerge(DEFAULT_CONFIG.connection, config.connection);
201
+ }
202
+ /**
203
+ * 音声設定を取得
204
+ */
205
+ async getAudioConfig() {
206
+ const config = await this.loadConfig();
207
+ return config.audio || {};
208
+ }
209
+ /**
210
+ * オペレータ設定を取得
211
+ */
212
+ async getOperatorConfig() {
213
+ const config = await this.loadConfig();
214
+ return deepMerge(DEFAULT_CONFIG.operator, config.operator);
215
+ }
216
+ /**
217
+ * 完全なConfig型を取得(SayCoeiroink用)
218
+ */
219
+ async getFullConfig() {
220
+ if (!this.mergedConfig) {
221
+ await this.buildDynamicConfig();
222
+ }
223
+ return {
224
+ connection: await this.getConnectionConfig(),
225
+ audio: await this.getAudioConfig(),
226
+ operator: await this.getOperatorConfig(),
227
+ characters: this.mergedConfig?.characters || {},
228
+ };
229
+ }
230
+ }
231
+ export default ConfigManager;
232
+ //# sourceMappingURL=config-manager.js.map
@@ -0,0 +1,82 @@
1
+ /**
2
+ * src/operator/file-operation-manager.ts: 汎用期限付きキーバリューストア
3
+ * 任意のデータTを期限付きで管理する汎用ファイル操作システム
4
+ */
5
+ interface StorageEntry<T> {
6
+ data: T;
7
+ updated_at: string;
8
+ }
9
+ export interface TimedStorage<T> {
10
+ storage: Record<string, StorageEntry<T>>;
11
+ }
12
+ export declare class FileOperationManager<T> {
13
+ private filePath;
14
+ private key;
15
+ private timeoutMs;
16
+ private readonly maxLockRetries;
17
+ private readonly lockRetryDelay;
18
+ private readonly lockTimeout;
19
+ constructor(filePath: string, key: string, timeoutMs?: number);
20
+ /**
21
+ * JSONファイルを安全に読み込み
22
+ */
23
+ readJsonFile<U>(filePath: string, defaultValue?: U): Promise<U>;
24
+ /**
25
+ * JSONファイルを安全に書き込み(アトミック操作)
26
+ */
27
+ writeJsonFile<U = unknown>(filePath: string, data: U): Promise<void>;
28
+ /**
29
+ * ファイルの存在確認
30
+ */
31
+ fileExists(filePath: string): Promise<boolean>;
32
+ /**
33
+ * ファイルを削除(存在しない場合はエラーを無視)
34
+ */
35
+ deleteFile(filePath: string): Promise<void>;
36
+ /**
37
+ * ファイルロックを取得してコールバック実行
38
+ */
39
+ withFileLock<R>(callback: () => Promise<R>): Promise<R>;
40
+ /**
41
+ * ストレージの読み取り
42
+ */
43
+ private read;
44
+ /**
45
+ * ストレージの書き込み
46
+ */
47
+ private write;
48
+ /**
49
+ * 期限切れエントリのクリーンアップ
50
+ */
51
+ private cleanupExpired;
52
+ /**
53
+ * ロック付きで操作を実行
54
+ */
55
+ private withLock;
56
+ /**
57
+ * データの保存(期限付き)
58
+ */
59
+ store(data: T): Promise<void>;
60
+ /**
61
+ * データの復元
62
+ */
63
+ restore(): Promise<T | null>;
64
+ /**
65
+ * 期限の更新(現在時刻に延長)
66
+ */
67
+ refresh(): Promise<boolean>;
68
+ /**
69
+ * 自分以外の全データを取得
70
+ */
71
+ getOtherEntries(): Promise<Record<string, T>>;
72
+ /**
73
+ * 現在のキーのエントリを削除
74
+ */
75
+ remove(): Promise<boolean>;
76
+ /**
77
+ * 全データをクリア
78
+ */
79
+ clear(): Promise<void>;
80
+ }
81
+ export default FileOperationManager;
82
+ //# sourceMappingURL=file-operation-manager.d.ts.map
@@ -0,0 +1,230 @@
1
+ /**
2
+ * src/operator/file-operation-manager.ts: 汎用期限付きキーバリューストア
3
+ * 任意のデータTを期限付きで管理する汎用ファイル操作システム
4
+ */
5
+ import { readFile, writeFile, stat, unlink, rename, access } from 'fs/promises';
6
+ import { constants } from 'fs';
7
+ export class FileOperationManager {
8
+ filePath;
9
+ key;
10
+ timeoutMs;
11
+ // ファイルロック設定
12
+ maxLockRetries = 50;
13
+ lockRetryDelay = 20; // ms
14
+ lockTimeout = 2000; // ms
15
+ constructor(filePath, key, timeoutMs = 4 * 60 * 60 * 1000 // デフォルト4時間
16
+ ) {
17
+ this.filePath = filePath;
18
+ this.key = key;
19
+ this.timeoutMs = timeoutMs;
20
+ }
21
+ /**
22
+ * JSONファイルを安全に読み込み
23
+ */
24
+ async readJsonFile(filePath, defaultValue = {}) {
25
+ try {
26
+ await access(filePath, constants.F_OK);
27
+ const content = await readFile(filePath, 'utf8');
28
+ return JSON.parse(content);
29
+ }
30
+ catch (error) {
31
+ console.error(`ファイル読み込みエラー: ${filePath}, ${error.message}`);
32
+ return defaultValue;
33
+ }
34
+ }
35
+ /**
36
+ * JSONファイルを安全に書き込み(アトミック操作)
37
+ */
38
+ async writeJsonFile(filePath, data) {
39
+ const tempFile = `${filePath}.tmp`;
40
+ await writeFile(tempFile, JSON.stringify(data, null, 2), 'utf8');
41
+ // ファイルが存在する場合のみ削除を試行
42
+ try {
43
+ await access(filePath, constants.F_OK);
44
+ await unlink(filePath);
45
+ }
46
+ catch {
47
+ // ファイルが存在しない場合は何もしない
48
+ }
49
+ await rename(tempFile, filePath);
50
+ }
51
+ /**
52
+ * ファイルの存在確認
53
+ */
54
+ async fileExists(filePath) {
55
+ try {
56
+ await access(filePath, constants.F_OK);
57
+ return true;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }
63
+ /**
64
+ * ファイルを削除(存在しない場合はエラーを無視)
65
+ */
66
+ async deleteFile(filePath) {
67
+ try {
68
+ await unlink(filePath);
69
+ }
70
+ catch {
71
+ // ファイルが存在しない場合は無視
72
+ }
73
+ }
74
+ /**
75
+ * ファイルロックを取得してコールバック実行
76
+ */
77
+ async withFileLock(callback) {
78
+ const lockFile = `${this.filePath}.lock`;
79
+ for (let i = 0; i < this.maxLockRetries; i++) {
80
+ try {
81
+ // 古いロックファイルのクリーンアップ(タイムアウト処理)
82
+ try {
83
+ const stats = await stat(lockFile);
84
+ const lockAge = Date.now() - stats.mtime.getTime();
85
+ if (lockAge > this.lockTimeout) {
86
+ console.warn(`Removing stale lock file: ${lockFile} (age: ${lockAge}ms)`);
87
+ await this.deleteFile(lockFile);
88
+ }
89
+ }
90
+ catch {
91
+ // ロックファイルが存在しない場合は正常
92
+ }
93
+ // ロックファイル作成(排他的)
94
+ await writeFile(lockFile, process.pid.toString(), { flag: 'wx' });
95
+ try {
96
+ // コールバック実行
97
+ const result = await callback();
98
+ return result;
99
+ }
100
+ finally {
101
+ // ロック解除
102
+ await this.deleteFile(lockFile);
103
+ }
104
+ }
105
+ catch (error) {
106
+ if (error.code === 'EEXIST') {
107
+ // ロック競合 - 指数バックオフでリトライ
108
+ const backoffDelay = this.lockRetryDelay * Math.min(Math.pow(1.5, i), 10);
109
+ await new Promise(resolve => setTimeout(resolve, backoffDelay + Math.random() * 10));
110
+ continue;
111
+ }
112
+ throw error;
113
+ }
114
+ }
115
+ throw new Error(`Failed to acquire file lock after ${this.maxLockRetries} retries: ${this.filePath}`);
116
+ }
117
+ /**
118
+ * ストレージの読み取り
119
+ */
120
+ async read(defaultValue) {
121
+ return this.readJsonFile(this.filePath, defaultValue);
122
+ }
123
+ /**
124
+ * ストレージの書き込み
125
+ */
126
+ async write(data) {
127
+ await this.writeJsonFile(this.filePath, data);
128
+ }
129
+ /**
130
+ * 期限切れエントリのクリーンアップ
131
+ */
132
+ cleanupExpired(state) {
133
+ const now = Date.now();
134
+ const validStorage = {};
135
+ for (const [k, entry] of Object.entries(state.storage)) {
136
+ const age = now - new Date(entry.updated_at).getTime();
137
+ if (age <= this.timeoutMs) {
138
+ validStorage[k] = entry;
139
+ }
140
+ }
141
+ return { storage: validStorage };
142
+ }
143
+ /**
144
+ * ロック付きで操作を実行
145
+ */
146
+ async withLock(callback) {
147
+ return this.withFileLock(async () => {
148
+ const state = await this.read({ storage: {} });
149
+ return callback(state);
150
+ });
151
+ }
152
+ /**
153
+ * データの保存(期限付き)
154
+ */
155
+ async store(data) {
156
+ await this.withLock(async (state) => {
157
+ const cleaned = this.cleanupExpired(state);
158
+ cleaned.storage[this.key] = {
159
+ data,
160
+ updated_at: new Date().toISOString(),
161
+ };
162
+ await this.write(cleaned);
163
+ });
164
+ }
165
+ /**
166
+ * データの復元
167
+ */
168
+ async restore() {
169
+ return this.withLock(async (state) => {
170
+ const cleaned = this.cleanupExpired(state);
171
+ await this.write(cleaned);
172
+ const entry = cleaned.storage[this.key];
173
+ return entry ? entry.data : null;
174
+ });
175
+ }
176
+ /**
177
+ * 期限の更新(現在時刻に延長)
178
+ */
179
+ async refresh() {
180
+ return this.withLock(async (state) => {
181
+ const cleaned = this.cleanupExpired(state);
182
+ const entry = cleaned.storage[this.key];
183
+ if (entry) {
184
+ entry.updated_at = new Date().toISOString();
185
+ await this.write(cleaned);
186
+ return true;
187
+ }
188
+ await this.write(cleaned);
189
+ return false;
190
+ });
191
+ }
192
+ /**
193
+ * 自分以外の全データを取得
194
+ */
195
+ async getOtherEntries() {
196
+ return this.withLock(async (state) => {
197
+ const cleaned = this.cleanupExpired(state);
198
+ await this.write(cleaned);
199
+ const result = {};
200
+ for (const [k, entry] of Object.entries(cleaned.storage)) {
201
+ if (k !== this.key) {
202
+ result[k] = entry.data;
203
+ }
204
+ }
205
+ return result;
206
+ });
207
+ }
208
+ /**
209
+ * 現在のキーのエントリを削除
210
+ */
211
+ async remove() {
212
+ return this.withLock(async (state) => {
213
+ const cleaned = this.cleanupExpired(state);
214
+ const existed = !!cleaned.storage[this.key];
215
+ delete cleaned.storage[this.key];
216
+ await this.write(cleaned);
217
+ return existed;
218
+ });
219
+ }
220
+ /**
221
+ * 全データをクリア
222
+ */
223
+ async clear() {
224
+ await this.withLock(async () => {
225
+ await this.write({ storage: {} });
226
+ });
227
+ }
228
+ }
229
+ export default FileOperationManager;
230
+ //# sourceMappingURL=file-operation-manager.js.map