@zodic/shared 0.0.176 → 0.0.178
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.
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { DurableObjectState } from '@cloudflare/workers-types';
|
|
2
|
+
import { BackendBindings, ConceptProgress } from '../../types';
|
|
2
3
|
|
|
3
4
|
export class ConceptNameDO {
|
|
4
5
|
state: DurableObjectState;
|
|
5
|
-
env:
|
|
6
|
+
env: BackendBindings;
|
|
6
7
|
names: { 'en-us': string[]; 'pt-br': string[] };
|
|
8
|
+
count: number;
|
|
9
|
+
timestamps: number[];
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
static TOTAL_NAMES = 1728; // Maximum total names to be generated
|
|
12
|
+
|
|
13
|
+
constructor(state: DurableObjectState, env: BackendBindings) {
|
|
9
14
|
this.state = state;
|
|
10
15
|
this.env = env;
|
|
11
16
|
this.names = { 'en-us': [], 'pt-br': [] };
|
|
17
|
+
this.count = 0;
|
|
18
|
+
this.timestamps = [];
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
async fetch(request: Request): Promise<Response> {
|
|
@@ -16,8 +23,13 @@ export class ConceptNameDO {
|
|
|
16
23
|
const method = request.method;
|
|
17
24
|
|
|
18
25
|
if (method === 'GET' && url.pathname === '/names') {
|
|
19
|
-
await this.
|
|
20
|
-
|
|
26
|
+
return new Response(JSON.stringify(await this.getNames()), {
|
|
27
|
+
headers: { 'Content-Type': 'application/json' },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (method === 'GET' && url.pathname === '/progress') {
|
|
32
|
+
return new Response(JSON.stringify(await this.getProgress()), {
|
|
21
33
|
headers: { 'Content-Type': 'application/json' },
|
|
22
34
|
});
|
|
23
35
|
}
|
|
@@ -28,7 +40,6 @@ export class ConceptNameDO {
|
|
|
28
40
|
name: string;
|
|
29
41
|
};
|
|
30
42
|
|
|
31
|
-
// ✅ Normalize language codes to match `generateBasicInfo`
|
|
32
43
|
if (!['en-us', 'pt-br'].includes(language)) {
|
|
33
44
|
return new Response('Invalid language', { status: 400 });
|
|
34
45
|
}
|
|
@@ -40,20 +51,69 @@ export class ConceptNameDO {
|
|
|
40
51
|
return new Response('Not Found', { status: 404 });
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
async
|
|
44
|
-
|
|
45
|
-
'
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.names = stored;
|
|
54
|
+
async getNames(): Promise<{ 'en-us': string[]; 'pt-br': string[] }> {
|
|
55
|
+
if (!this.names['en-us'].length && !this.names['pt-br'].length) {
|
|
56
|
+
this.names = (await this.state.storage.get('names')) || {
|
|
57
|
+
'en-us': [],
|
|
58
|
+
'pt-br': [],
|
|
59
|
+
};
|
|
50
60
|
}
|
|
61
|
+
return this.names;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async getProgress(): Promise<ConceptProgress> {
|
|
65
|
+
if (this.count === 0) {
|
|
66
|
+
this.count = (await this.state.storage.get<number>('count')) || 0;
|
|
67
|
+
}
|
|
68
|
+
if (this.timestamps.length === 0) {
|
|
69
|
+
this.timestamps =
|
|
70
|
+
(await this.state.storage.get<number[]>('timestamps')) || [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
const oneMinuteAgo = now - 60 * 1000;
|
|
75
|
+
|
|
76
|
+
const recentTimestamps = this.timestamps.filter((ts) => ts >= oneMinuteAgo);
|
|
77
|
+
const ratePerMinute = recentTimestamps.length;
|
|
78
|
+
|
|
79
|
+
const remainingNames = ConceptNameDO.TOTAL_NAMES - this.count;
|
|
80
|
+
const estimatedTimeMinutes =
|
|
81
|
+
ratePerMinute > 0 ? Math.round(remainingNames / ratePerMinute) : 'N/A';
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
count: this.count,
|
|
85
|
+
total: ConceptNameDO.TOTAL_NAMES,
|
|
86
|
+
progress:
|
|
87
|
+
((this.count / ConceptNameDO.TOTAL_NAMES) * 100).toFixed(2) + '%',
|
|
88
|
+
ratePerMinute,
|
|
89
|
+
estimatedTimeMinutes,
|
|
90
|
+
};
|
|
51
91
|
}
|
|
52
92
|
|
|
53
93
|
async addName(language: 'en-us' | 'pt-br', name: string): Promise<void> {
|
|
94
|
+
await this.getNames(); // Ensure latest state
|
|
95
|
+
|
|
54
96
|
if (!this.names[language].includes(name)) {
|
|
55
97
|
this.names[language].push(name);
|
|
56
|
-
|
|
98
|
+
this.count++;
|
|
99
|
+
this.recordTimestamp();
|
|
100
|
+
|
|
101
|
+
// ✅ **Batch storage writes** instead of multiple separate `put()` calls
|
|
102
|
+
await this.state.storage.put({
|
|
103
|
+
names: this.names,
|
|
104
|
+
count: this.count,
|
|
105
|
+
timestamps: this.timestamps,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
recordTimestamp(): void {
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
|
|
113
|
+
// Keep only the last 60 timestamps
|
|
114
|
+
if (this.timestamps.length >= 60) {
|
|
115
|
+
this.timestamps.splice(0, this.timestamps.length - 59);
|
|
57
116
|
}
|
|
117
|
+
this.timestamps.push(now);
|
|
58
118
|
}
|
|
59
119
|
}
|
|
@@ -2,7 +2,7 @@ import { and, eq } from 'drizzle-orm';
|
|
|
2
2
|
import { inject, injectable } from 'inversify';
|
|
3
3
|
import 'reflect-metadata';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
-
import {
|
|
5
|
+
import { schema } from '../..';
|
|
6
6
|
import { Concept, ControlNetConfig, Languages } from '../../types';
|
|
7
7
|
import {
|
|
8
8
|
KVConcept,
|
|
@@ -51,7 +51,9 @@ export class ConceptService {
|
|
|
51
51
|
// ✅ Fetch the latest name list from Durable Object
|
|
52
52
|
let allNamesEN: string[] = [];
|
|
53
53
|
let allNamesPT: string[] = [];
|
|
54
|
-
const response = await stub.fetch(
|
|
54
|
+
const response = await stub.fetch(
|
|
55
|
+
`https://internal/names`
|
|
56
|
+
);
|
|
55
57
|
if (response.ok) {
|
|
56
58
|
const data = (await response.json()) as {
|
|
57
59
|
'en-us': string[];
|
|
@@ -60,7 +62,7 @@ export class ConceptService {
|
|
|
60
62
|
allNamesEN = data['en-us'] || [];
|
|
61
63
|
allNamesPT = data['pt-br'] || [];
|
|
62
64
|
} else {
|
|
63
|
-
console.log(
|
|
65
|
+
console.log(`!-- Error fetching names from DO for ${conceptSlug}`);
|
|
64
66
|
console.log('!-- Response:', await response.text());
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -71,7 +73,7 @@ export class ConceptService {
|
|
|
71
73
|
// 🔥 If names already exist in KV but not in DO, add them
|
|
72
74
|
if (existingEN.name && !allNamesEN.includes(existingEN.name)) {
|
|
73
75
|
console.log(`⚡ Backfilling existing name to DO: ${existingEN.name}`);
|
|
74
|
-
await stub.fetch(
|
|
76
|
+
await stub.fetch(`https://internal/add-name`, {
|
|
75
77
|
method: 'POST',
|
|
76
78
|
body: JSON.stringify({ language: 'en-us', name: existingEN.name }),
|
|
77
79
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -79,7 +81,7 @@ export class ConceptService {
|
|
|
79
81
|
}
|
|
80
82
|
if (existingPT.name && !allNamesPT.includes(existingPT.name)) {
|
|
81
83
|
console.log(`⚡ Backfilling existing name to DO: ${existingPT.name}`);
|
|
82
|
-
await stub.fetch(
|
|
84
|
+
await stub.fetch(`https://internal/add-name`, {
|
|
83
85
|
method: 'POST',
|
|
84
86
|
body: JSON.stringify({ language: 'pt-br', name: existingPT.name }),
|
|
85
87
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -127,13 +129,13 @@ export class ConceptService {
|
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
// ✅ **Immediately update Durable Object with the new name**
|
|
130
|
-
await stub.fetch(
|
|
132
|
+
await stub.fetch(`https://internal/add-name`, {
|
|
131
133
|
method: 'POST',
|
|
132
134
|
body: JSON.stringify({ language: 'en-us', name: nameEN }),
|
|
133
135
|
headers: { 'Content-Type': 'application/json' },
|
|
134
136
|
});
|
|
135
137
|
|
|
136
|
-
await stub.fetch(
|
|
138
|
+
await stub.fetch(`https://internal/add-name`, {
|
|
137
139
|
method: 'POST',
|
|
138
140
|
body: JSON.stringify({ language: 'pt-br', name: namePT }),
|
|
139
141
|
headers: { 'Content-Type': 'application/json' },
|
package/package.json
CHANGED
package/types/scopes/generic.ts
CHANGED
|
@@ -398,3 +398,11 @@ export type AstroKVData = {
|
|
|
398
398
|
diff: number;
|
|
399
399
|
}[];
|
|
400
400
|
};
|
|
401
|
+
|
|
402
|
+
export type ConceptProgress = {
|
|
403
|
+
count: number;
|
|
404
|
+
total: number;
|
|
405
|
+
progress: string; // Percentage as string (e.g., "75.32%")
|
|
406
|
+
ratePerMinute: number;
|
|
407
|
+
estimatedTimeMinutes: number | 'N/A';
|
|
408
|
+
};
|