@jingyi0605/codingns4dsh 0.2.1-rc.6 → 0.2.1-rc.7
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/README.en.md +3 -3
- package/README.md +3 -3
- package/data/build/dist/client/bundle.js +1412 -103
- package/data/build/dist/client/bundle.js.map +1 -1
- package/data/build/dist/client/client.native-workspace-store.js +1 -1
- package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
- package/data/build/dist/client/client.transport.js +202 -0
- package/data/build/dist/client/client.transport.js.map +1 -1
- package/data/build/dist/client/desktop-assistant.js +202 -0
- package/data/build/dist/client/features/index.d.ts +2 -1
- package/data/build/dist/client/features/index.d.ts.map +1 -1
- package/data/build/dist/client/features/index.js +3 -1
- package/data/build/dist/client/features/index.js.map +1 -1
- package/data/build/dist/client/features/magpie-management-page.d.ts +7 -3
- package/data/build/dist/client/features/magpie-management-page.d.ts.map +1 -1
- package/data/build/dist/client/features/magpie-management-page.js +142 -8
- package/data/build/dist/client/features/magpie-management-page.js.map +1 -1
- package/data/build/dist/client/features/workspace-mcp.d.ts +3 -0
- package/data/build/dist/client/features/workspace-mcp.d.ts.map +1 -0
- package/data/build/dist/client/features/workspace-mcp.js +320 -0
- package/data/build/dist/client/features/workspace-mcp.js.map +1 -0
- package/data/build/dist/client/locale.d.ts.map +1 -1
- package/data/build/dist/client/locale.js +176 -0
- package/data/build/dist/client/locale.js.map +1 -1
- package/data/build/dist/client/locales/magpie.d.ts.map +1 -1
- package/data/build/dist/client/locales/magpie.js +12 -0
- package/data/build/dist/client/locales/magpie.js.map +1 -1
- package/data/build/dist/client/locales/usage.d.ts.map +1 -1
- package/data/build/dist/client/locales/usage.js +14 -0
- package/data/build/dist/client/locales/usage.js.map +1 -1
- package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
- package/data/build/dist/client/subscription-slot.js +104 -11
- package/data/build/dist/client/subscription-slot.js.map +1 -1
- package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.d.ts +18 -0
- package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.js +172 -0
- package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.d.ts +28 -0
- package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.js +103 -0
- package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.d.ts +26 -0
- package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.js +86 -0
- package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/matrix.js +3 -0
- package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.js +9 -0
- package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/types.js.map +1 -1
- package/data/build/dist/host/cli-adapters/claude-model-options.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/claude-model-options.js +13 -2
- package/data/build/dist/host/cli-adapters/claude-model-options.js.map +1 -1
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js +1 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.js +5 -1
- package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
- package/data/build/dist/host/cli-adapters/magpie-usage.d.ts +13 -2
- package/data/build/dist/host/cli-adapters/magpie-usage.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/magpie-usage.js +180 -13
- package/data/build/dist/host/cli-adapters/magpie-usage.js.map +1 -1
- package/data/build/dist/host/features/index.d.ts +1 -0
- package/data/build/dist/host/features/index.d.ts.map +1 -1
- package/data/build/dist/host/features/index.js +3 -0
- package/data/build/dist/host/features/index.js.map +1 -1
- package/data/build/dist/host/features/workspace-mcp.d.ts +9 -0
- package/data/build/dist/host/features/workspace-mcp.d.ts.map +1 -0
- package/data/build/dist/host/features/workspace-mcp.js +197 -0
- package/data/build/dist/host/features/workspace-mcp.js.map +1 -0
- package/data/build/dist/host/index.d.ts.map +1 -1
- package/data/build/dist/host/index.js +6 -2
- package/data/build/dist/host/index.js.map +1 -1
- package/data/build/dist/host/native-session-bridge.d.ts +2 -0
- package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
- package/data/build/dist/host/native-session-bridge.js +30 -0
- package/data/build/dist/host/native-session-bridge.js.map +1 -1
- package/data/build/dist/host/rpc.d.ts +4 -1
- package/data/build/dist/host/rpc.d.ts.map +1 -1
- package/data/build/dist/host/rpc.js +57 -9
- package/data/build/dist/host/rpc.js.map +1 -1
- package/data/build/dist/host/session-handle-eviction.d.ts +4 -2
- package/data/build/dist/host/session-handle-eviction.d.ts.map +1 -1
- package/data/build/dist/host/session-handle-eviction.js +10 -9
- package/data/build/dist/host/session-handle-eviction.js.map +1 -1
- package/data/build/dist/host/terminal/terminal-process-service.d.ts +22 -0
- package/data/build/dist/host/terminal/terminal-process-service.d.ts.map +1 -1
- package/data/build/dist/host/terminal/terminal-process-service.js +102 -0
- package/data/build/dist/host/terminal/terminal-process-service.js.map +1 -1
- package/data/build/dist/host/terminal/terminal-service.d.ts +5 -1
- package/data/build/dist/host/terminal/terminal-service.d.ts.map +1 -1
- package/data/build/dist/host/terminal/terminal-service.js +32 -0
- package/data/build/dist/host/terminal/terminal-service.js.map +1 -1
- package/data/build/dist/host/workspace-mcp/api-key-store.d.ts +16 -0
- package/data/build/dist/host/workspace-mcp/api-key-store.d.ts.map +1 -0
- package/data/build/dist/host/workspace-mcp/api-key-store.js +65 -0
- package/data/build/dist/host/workspace-mcp/api-key-store.js.map +1 -0
- package/data/build/dist/host/workspace-mcp/tools.d.ts +54 -0
- package/data/build/dist/host/workspace-mcp/tools.d.ts.map +1 -0
- package/data/build/dist/host/workspace-mcp/tools.js +800 -0
- package/data/build/dist/host/workspace-mcp/tools.js.map +1 -0
- package/data/build/dist/host/workspace-mcp/transport.d.ts +35 -0
- package/data/build/dist/host/workspace-mcp/transport.d.ts.map +1 -0
- package/data/build/dist/host/workspace-mcp/transport.js +575 -0
- package/data/build/dist/host/workspace-mcp/transport.js.map +1 -0
- package/data/build/dist/shared/contracts/magpie-management.d.ts +15 -1
- package/data/build/dist/shared/contracts/magpie-management.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/subscription.d.ts +7 -0
- package/data/build/dist/shared/contracts/subscription.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/subscription.js.map +1 -1
- package/data/build/dist/shared/contracts/terminal.d.ts +2 -0
- package/data/build/dist/shared/contracts/terminal.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/version.d.ts +1 -1
- package/data/build/dist/shared/contracts/version.js +1 -1
- package/package.json +1 -1
- package/profile/README.md +2 -2
- package/profile/package.json +2 -2
- package/profile/version.json +1 -1
- package/version.json +1 -1
|
@@ -183,6 +183,31 @@ export class MagpieUsageService {
|
|
|
183
183
|
}
|
|
184
184
|
return changed ? { ...resolvedCatalog, groups } : resolvedCatalog;
|
|
185
185
|
}
|
|
186
|
+
async updateAccountPolicy(input, signal) {
|
|
187
|
+
const update = readMagpieAccountPolicyUpdate(input);
|
|
188
|
+
const path = update.policy === 'credits' ? '/api/settings/codex-credits' : '/api/settings/codex-auto-reset';
|
|
189
|
+
const body = update.policy === 'credits'
|
|
190
|
+
? { user: update.user, on: update.enabled }
|
|
191
|
+
: { user: update.user, on: update.enabled, when: update.policy };
|
|
192
|
+
const result = await this.requestWebJson(path, { method: 'POST', body }, signal);
|
|
193
|
+
if (!result.ok)
|
|
194
|
+
throw new Error('Magpie account policy update failed');
|
|
195
|
+
const settings = parseMagpieAccountPolicies(result.value);
|
|
196
|
+
if (settings === null || !magpieAccountPolicyMatches(settings, update)) {
|
|
197
|
+
throw new Error('Magpie account policy update could not be verified');
|
|
198
|
+
}
|
|
199
|
+
return update;
|
|
200
|
+
}
|
|
201
|
+
async resetCodexAccount(input, signal) {
|
|
202
|
+
const user = readMagpieAccountUser(input);
|
|
203
|
+
const result = await this.requestWebJson('/api/usage/codex-reset', {
|
|
204
|
+
method: 'POST',
|
|
205
|
+
body: { user },
|
|
206
|
+
}, signal);
|
|
207
|
+
if (!result.ok)
|
|
208
|
+
throw new Error('Magpie Codex reset failed');
|
|
209
|
+
return { outcome: normalizeMagpieResetOutcome(result.value) };
|
|
210
|
+
}
|
|
186
211
|
/** Return an exact, CLI-confirmed Magpie model record for trusted Host use. */
|
|
187
212
|
async readModelMetadata(adapterId, modelId, signal) {
|
|
188
213
|
signal?.throwIfAborted();
|
|
@@ -209,16 +234,16 @@ export class MagpieUsageService {
|
|
|
209
234
|
return parseMagpieContextResponse(response.value, options);
|
|
210
235
|
}
|
|
211
236
|
/** Read bounded, graph-ready usage and quota data through authenticated Magpie Web. */
|
|
212
|
-
async readDashboard(period, signal) {
|
|
237
|
+
async readDashboard(period, signal, force = false) {
|
|
213
238
|
signal?.throwIfAborted();
|
|
214
239
|
const cached = this.dashboardCache.get(period);
|
|
215
|
-
if (cached !== undefined) {
|
|
240
|
+
if (!force && cached !== undefined) {
|
|
216
241
|
if (this.now() - cached.loadedAt >= MAGPIE_DASHBOARD_CACHE_TTL_MS) {
|
|
217
242
|
void this.refreshDashboard(period).catch(() => undefined);
|
|
218
243
|
}
|
|
219
244
|
return cached.dashboard;
|
|
220
245
|
}
|
|
221
|
-
return this.refreshDashboard(period, signal);
|
|
246
|
+
return this.refreshDashboard(period, signal, force);
|
|
222
247
|
}
|
|
223
248
|
/** Stream cumulative dashboard snapshots as each independent Web API part is ready. */
|
|
224
249
|
async *readDashboardStream(period, signal, force = false) {
|
|
@@ -238,22 +263,25 @@ export class MagpieUsageService {
|
|
|
238
263
|
if (latest !== undefined)
|
|
239
264
|
this.dashboardCache.set(period, { dashboard: latest, loadedAt: this.now() });
|
|
240
265
|
}
|
|
241
|
-
async refreshDashboard(period, signal) {
|
|
266
|
+
async refreshDashboard(period, signal, force = false) {
|
|
242
267
|
const pending = this.dashboardRefreshes.get(period);
|
|
243
|
-
if (pending !== undefined)
|
|
268
|
+
if (!force && pending !== undefined)
|
|
244
269
|
return awaitWithSignal(pending, signal);
|
|
245
|
-
|
|
270
|
+
let request = null;
|
|
271
|
+
const task = (async () => {
|
|
246
272
|
let latest;
|
|
247
273
|
for await (const chunk of this.readDashboardNetwork(period, signal))
|
|
248
274
|
latest = chunk.dashboard;
|
|
249
275
|
if (latest === undefined)
|
|
250
276
|
throw new Error('Magpie dashboard returned no snapshot');
|
|
251
|
-
|
|
277
|
+
if (request !== null && this.dashboardRefreshes.get(period) === request)
|
|
278
|
+
this.dashboardCache.set(period, { dashboard: latest, loadedAt: this.now() });
|
|
252
279
|
return latest;
|
|
253
280
|
})().finally(() => {
|
|
254
|
-
if (this.dashboardRefreshes.get(period) === request)
|
|
281
|
+
if (request !== null && this.dashboardRefreshes.get(period) === request)
|
|
255
282
|
this.dashboardRefreshes.delete(period);
|
|
256
283
|
});
|
|
284
|
+
request = task;
|
|
257
285
|
this.dashboardRefreshes.set(period, request);
|
|
258
286
|
return awaitWithSignal(request, signal);
|
|
259
287
|
}
|
|
@@ -262,19 +290,23 @@ export class MagpieUsageService {
|
|
|
262
290
|
let dashboard = emptyMagpieDashboard(period, capturedAt);
|
|
263
291
|
let quotas = null;
|
|
264
292
|
let logoLoad;
|
|
293
|
+
let settingsRead = false;
|
|
265
294
|
const results = new Map([
|
|
266
295
|
['usage', this.timedDashboardRead('usage', () => this.readWebJson(`/api/usage?period=${magpieWebPeriod(period)}`, signal))],
|
|
267
296
|
['quotas', this.timedDashboardRead('quotas', () => this.readWebJson('/api/usage/quotas', signal))],
|
|
297
|
+
['settings', this.timedDashboardRead('settings', () => this.readWebJson('/api/settings', signal))],
|
|
268
298
|
['history', this.timedDashboardRead('history', () => this.readWebJson('/api/usage/quotas/history?days=30', signal))],
|
|
269
299
|
]);
|
|
270
300
|
const completed = new Map();
|
|
301
|
+
let policies = null;
|
|
271
302
|
while (results.size > 0) {
|
|
272
303
|
const result = await Promise.race(results.values());
|
|
273
304
|
results.delete(result.part);
|
|
274
305
|
const response = asRecord(result.value);
|
|
275
306
|
const partOk = result.ok && response?.ok === true;
|
|
276
307
|
const partValue = partOk ? response.value : undefined;
|
|
277
|
-
|
|
308
|
+
if (result.part !== 'settings')
|
|
309
|
+
completed.set(result.part, partOk);
|
|
278
310
|
if (result.part === 'usage') {
|
|
279
311
|
const parsed = partOk ? parseMagpieDashboardUsage(partValue) : null;
|
|
280
312
|
dashboard = {
|
|
@@ -291,10 +323,21 @@ export class MagpieUsageService {
|
|
|
291
323
|
};
|
|
292
324
|
}
|
|
293
325
|
else if (result.part === 'quotas') {
|
|
294
|
-
|
|
326
|
+
const parsedQuotas = partOk ? parseMagpieQuotaCards(partValue) : null;
|
|
327
|
+
quotas = parsedQuotas === null ? null : applyMagpieDashboardAccountPolicies(parsedQuotas, policies);
|
|
295
328
|
dashboard = { ...dashboard, quotaStatus: quotas === null ? 'unavailable' : 'available', quotas: quotas ?? [] };
|
|
329
|
+
if (quotas !== null && settingsRead)
|
|
330
|
+
logoLoad = this.timedDashboardRead('quota-logos', () => this.attachQuotaLogos(quotas, signal)).then((logoResult) => logoResult.value);
|
|
331
|
+
}
|
|
332
|
+
else if (result.part === 'settings') {
|
|
333
|
+
settingsRead = true;
|
|
334
|
+
policies = partOk ? parseMagpieAccountPolicies(partValue) : null;
|
|
335
|
+
if (quotas !== null && policies !== null) {
|
|
336
|
+
quotas = applyMagpieDashboardAccountPolicies(quotas, policies);
|
|
337
|
+
dashboard = { ...dashboard, quotas };
|
|
338
|
+
}
|
|
296
339
|
if (quotas !== null)
|
|
297
|
-
logoLoad = this.timedDashboardRead('quota-logos', () => this.attachQuotaLogos(quotas, signal)).then((
|
|
340
|
+
logoLoad = this.timedDashboardRead('quota-logos', () => this.attachQuotaLogos(quotas, signal)).then((logoResult) => logoResult.value);
|
|
298
341
|
}
|
|
299
342
|
else {
|
|
300
343
|
const parsed = partOk ? parseMagpieQuotaHistory(partValue) : null;
|
|
@@ -474,10 +517,11 @@ export class MagpieUsageService {
|
|
|
474
517
|
}
|
|
475
518
|
async readFromWeb(agent, modelId, sessionId, magpieSessionId, fallbackSessionId, signal, includeRoute, allowPendingSession) {
|
|
476
519
|
const capturedAt = new Date(this.now()).toISOString();
|
|
477
|
-
const [usageResult, sessionResult, quotaResult] = await Promise.all([
|
|
520
|
+
const [usageResult, sessionResult, quotaResult, settingsResult] = await Promise.all([
|
|
478
521
|
this.readWebJson('/api/usage?period=today', signal),
|
|
479
522
|
this.readWebJson('/api/usage?period=all', signal),
|
|
480
523
|
this.readWebJson('/api/usage/quotas', signal),
|
|
524
|
+
agent === 'codex' ? this.readWebJson('/api/settings', signal) : Promise.resolve({ ok: false }),
|
|
481
525
|
]);
|
|
482
526
|
const aggregate = usageResult.ok ? readTotals(usageResult.value) : null;
|
|
483
527
|
const primarySession = sessionResult.ok && magpieSessionId !== null
|
|
@@ -519,7 +563,9 @@ export class MagpieUsageService {
|
|
|
519
563
|
: !canReadRoute || !routeHistoryValid
|
|
520
564
|
? 'unavailable'
|
|
521
565
|
: 'no-route';
|
|
522
|
-
const allQuotas = quotaResult.ok
|
|
566
|
+
const allQuotas = quotaResult.ok
|
|
567
|
+
? applyMagpieAccountPolicies(parseMagpieQuotas(quotaResult.value), settingsResult.ok ? settingsResult.value : null)
|
|
568
|
+
: null;
|
|
523
569
|
const routeProviders = [...new Set([
|
|
524
570
|
providerFromRoute(route),
|
|
525
571
|
...routeHistory.map((record) => record.provider),
|
|
@@ -730,6 +776,20 @@ export class MagpieUsageService {
|
|
|
730
776
|
return { ok: false };
|
|
731
777
|
}
|
|
732
778
|
}
|
|
779
|
+
async requestWebJson(path, options, signal) {
|
|
780
|
+
if (this.webApi === undefined)
|
|
781
|
+
return { ok: false };
|
|
782
|
+
try {
|
|
783
|
+
return {
|
|
784
|
+
ok: true,
|
|
785
|
+
value: await this.webApi.requestJson(path, signal === undefined ? options : { ...options, signal }),
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
catch {
|
|
789
|
+
signal?.throwIfAborted();
|
|
790
|
+
return { ok: false };
|
|
791
|
+
}
|
|
792
|
+
}
|
|
733
793
|
/** Provider management data is the canonical source when a usage row mislabels its upstream. */
|
|
734
794
|
async readProviderCatalog(signal) {
|
|
735
795
|
const cached = this.providerCatalog;
|
|
@@ -1395,6 +1455,113 @@ export function parseMagpieQuotas(value) {
|
|
|
1395
1455
|
}
|
|
1396
1456
|
return quotas;
|
|
1397
1457
|
}
|
|
1458
|
+
function parseMagpieAccountPolicies(value) {
|
|
1459
|
+
const root = asRecord(value);
|
|
1460
|
+
if (root === null)
|
|
1461
|
+
return null;
|
|
1462
|
+
const autoResetUsers = readLowercaseSet(root.codexAutoReset, 500);
|
|
1463
|
+
const noCreditsUsers = readLowercaseSet(root.codexNoCredits, 500);
|
|
1464
|
+
const autoResetOnly = new Map();
|
|
1465
|
+
const only = asRecord(root.codexAutoResetOnly);
|
|
1466
|
+
if (only !== null) {
|
|
1467
|
+
for (const [user, value] of Object.entries(only).slice(0, 500)) {
|
|
1468
|
+
if (value === 'week' || value === 'expiring')
|
|
1469
|
+
autoResetOnly.set(user.toLocaleLowerCase(), value);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
if (autoResetUsers === null || noCreditsUsers === null)
|
|
1473
|
+
return null;
|
|
1474
|
+
return { autoResetUsers, autoResetOnly, noCreditsUsers };
|
|
1475
|
+
}
|
|
1476
|
+
function applyMagpieAccountPolicies(quotas, settingsValue) {
|
|
1477
|
+
if (quotas === null)
|
|
1478
|
+
return null;
|
|
1479
|
+
const settings = parseMagpieAccountPolicies(settingsValue);
|
|
1480
|
+
if (settings === null)
|
|
1481
|
+
return quotas;
|
|
1482
|
+
return quotas.map((quota) => {
|
|
1483
|
+
if (quota.provider.toLocaleLowerCase() !== 'codex' || quota.user === null)
|
|
1484
|
+
return quota;
|
|
1485
|
+
const user = quota.user.toLocaleLowerCase();
|
|
1486
|
+
const enabled = settings.autoResetUsers.has(user);
|
|
1487
|
+
const only = settings.autoResetOnly.get(user);
|
|
1488
|
+
return {
|
|
1489
|
+
...quota,
|
|
1490
|
+
autoReset: {
|
|
1491
|
+
week: enabled && only !== 'expiring',
|
|
1492
|
+
expiring: enabled && only !== 'week',
|
|
1493
|
+
},
|
|
1494
|
+
useCredits: !settings.noCreditsUsers.has(user),
|
|
1495
|
+
};
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
function applyMagpieDashboardAccountPolicies(quotas, settings) {
|
|
1499
|
+
return quotas.map((quota) => {
|
|
1500
|
+
if (quota.provider.toLocaleLowerCase() !== 'codex' || quota.user === null)
|
|
1501
|
+
return quota;
|
|
1502
|
+
if (settings === null)
|
|
1503
|
+
return { ...quota, policyStatus: 'unavailable' };
|
|
1504
|
+
const user = quota.user.toLocaleLowerCase();
|
|
1505
|
+
const enabled = settings.autoResetUsers.has(user);
|
|
1506
|
+
const only = settings.autoResetOnly.get(user);
|
|
1507
|
+
return {
|
|
1508
|
+
...quota,
|
|
1509
|
+
autoReset: {
|
|
1510
|
+
week: enabled && only !== 'expiring',
|
|
1511
|
+
expiring: enabled && only !== 'week',
|
|
1512
|
+
},
|
|
1513
|
+
useCredits: !settings.noCreditsUsers.has(user),
|
|
1514
|
+
policyStatus: 'available',
|
|
1515
|
+
};
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
function readLowercaseSet(value, maxItems) {
|
|
1519
|
+
if (value === undefined)
|
|
1520
|
+
return new Set();
|
|
1521
|
+
if (!Array.isArray(value) || value.length > maxItems)
|
|
1522
|
+
return null;
|
|
1523
|
+
const values = value.filter((item) => typeof item === 'string' && item.trim() !== '');
|
|
1524
|
+
return values.length === value.length
|
|
1525
|
+
? new Set(values.map((item) => item.trim().toLocaleLowerCase()))
|
|
1526
|
+
: null;
|
|
1527
|
+
}
|
|
1528
|
+
function readMagpieAccountUser(value) {
|
|
1529
|
+
const record = asRecord(value);
|
|
1530
|
+
const user = typeof record?.user === 'string' ? record.user.trim() : '';
|
|
1531
|
+
if (user === '' || user.length > 180)
|
|
1532
|
+
throw new TypeError('Magpie account user is invalid');
|
|
1533
|
+
return user;
|
|
1534
|
+
}
|
|
1535
|
+
function readMagpieAccountPolicyUpdate(value) {
|
|
1536
|
+
const record = asRecord(value);
|
|
1537
|
+
const user = readMagpieAccountUser(value);
|
|
1538
|
+
const policy = record?.policy;
|
|
1539
|
+
if (policy !== 'week' && policy !== 'expiring' && policy !== 'credits') {
|
|
1540
|
+
throw new TypeError('Magpie account policy is invalid');
|
|
1541
|
+
}
|
|
1542
|
+
if (typeof record?.enabled !== 'boolean')
|
|
1543
|
+
throw new TypeError('Magpie account policy state is invalid');
|
|
1544
|
+
return { user, policy, enabled: record.enabled };
|
|
1545
|
+
}
|
|
1546
|
+
function magpieAccountPolicyMatches(settings, update) {
|
|
1547
|
+
const user = update.user.toLocaleLowerCase();
|
|
1548
|
+
if (update.policy === 'credits')
|
|
1549
|
+
return settings.noCreditsUsers.has(user) !== update.enabled;
|
|
1550
|
+
const enabled = settings.autoResetUsers.has(user);
|
|
1551
|
+
const only = settings.autoResetOnly.get(user);
|
|
1552
|
+
const current = update.policy === 'week'
|
|
1553
|
+
? enabled && only !== 'expiring'
|
|
1554
|
+
: enabled && only !== 'week';
|
|
1555
|
+
return current === update.enabled;
|
|
1556
|
+
}
|
|
1557
|
+
function normalizeMagpieResetOutcome(value) {
|
|
1558
|
+
const record = asRecord(value);
|
|
1559
|
+
const outcome = record?.code ?? record?.outcome;
|
|
1560
|
+
if (outcome === 'reset' || outcome === 'alreadyRedeemed' || outcome === 'nothingToReset' || outcome === 'noCredit') {
|
|
1561
|
+
return outcome;
|
|
1562
|
+
}
|
|
1563
|
+
throw new Error('Magpie returned an unknown reset result');
|
|
1564
|
+
}
|
|
1398
1565
|
/** Normalize the live aggregate and per-dimension usage response. */
|
|
1399
1566
|
export function parseMagpieDashboardUsage(value) {
|
|
1400
1567
|
const root = asRecord(value);
|