@epic-web/workshop-utils 6.14.4 → 6.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/cache.server.d.ts.map +1 -1
- package/dist/esm/cache.server.js +92 -15
- package/dist/esm/cache.server.js.map +1 -1
- package/dist/esm/db.server.d.ts.map +1 -1
- package/dist/esm/db.server.js +41 -8
- package/dist/esm/db.server.js.map +1 -1
- package/dist/esm/env.server.d.ts +5 -0
- package/dist/esm/env.server.d.ts.map +1 -1
- package/dist/esm/env.server.js +31 -1
- package/dist/esm/env.server.js.map +1 -1
- package/dist/esm/epic-api.server.d.ts +7 -7
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.server.d.ts","sourceRoot":"","sources":["../../src/cache.server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,qBAAqB,CAAA;AAcxC,OAAO,EAA2B,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAG1E,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACyB,CAAA;AACtD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACwB,CAAA;AACpD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACwB,CAAA;AACpD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAC2B,CAAA;AAC1D,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAyC,CAAA;AAC/D,eAAO,MAAM,aAAa,iBAAgD,CAAA;AAC1E,eAAO,MAAM,cAAc,iBAAiD,CAAA;AAC5E,eAAO,MAAM,qBAAqB,iBAEjC,CAAA;AACD,eAAO,MAAM,iBAAiB,iBACoB,CAAA;AAClD,eAAO,MAAM,OAAO;;;;;CAAwC,CAAA;AAC5D,eAAO,MAAM,gCAAgC;UACtC,MAAM;WACL,MAAM,GAAG,IAAI;qBACH,KAAK,CAAC,MAAM,CAAC;EACO,CAAA;AACtC,eAAO,MAAM,oBAAoB;;;;;CAEhC,CAAA;AACD,eAAO,MAAM,eAAe;;;;;CAAiD,CAAA;AAC7E,eAAO,MAAM,oBAAoB;;;0BACd,OAAO;qBACZ,MAAM;sBACL,MAAM;kBACV,MAAM,GAAG,IAAI;;0BAHL,OAAO;qBACZ,MAAM;sBACL,MAAM;kBACV,MAAM,GAAG,IAAI;;;0BAHL,OAAO;qBACZ,MAAM;sBACL,MAAM;kBACV,MAAM,GAAG,IAAI;;;CACE,CAAA;AAC1B,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAC+B,CAAA;AAC9D,eAAO,MAAM,mBAAmB;;;;;CAE/B,CAAA;AAID,eAAO,MAAM,OAAO,kBAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"cache.server.d.ts","sourceRoot":"","sources":["../../src/cache.server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,qBAAqB,CAAA;AAcxC,OAAO,EAA2B,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAG1E,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACyB,CAAA;AACtD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACwB,CAAA;AACpD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACwB,CAAA;AACpD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAC2B,CAAA;AAC1D,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAyC,CAAA;AAC/D,eAAO,MAAM,aAAa,iBAAgD,CAAA;AAC1E,eAAO,MAAM,cAAc,iBAAiD,CAAA;AAC5E,eAAO,MAAM,qBAAqB,iBAEjC,CAAA;AACD,eAAO,MAAM,iBAAiB,iBACoB,CAAA;AAClD,eAAO,MAAM,OAAO;;;;;CAAwC,CAAA;AAC5D,eAAO,MAAM,gCAAgC;UACtC,MAAM;WACL,MAAM,GAAG,IAAI;qBACH,KAAK,CAAC,MAAM,CAAC;EACO,CAAA;AACtC,eAAO,MAAM,oBAAoB;;;;;CAEhC,CAAA;AACD,eAAO,MAAM,eAAe;;;;;CAAiD,CAAA;AAC7E,eAAO,MAAM,oBAAoB;;;0BACd,OAAO;qBACZ,MAAM;sBACL,MAAM;kBACV,MAAM,GAAG,IAAI;;0BAHL,OAAO;qBACZ,MAAM;sBACL,MAAM;kBACV,MAAM,GAAG,IAAI;;;0BAHL,OAAO;qBACZ,MAAM;sBACL,MAAM;kBACV,MAAM,GAAG,IAAI;;;CACE,CAAA;AAC1B,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAC+B,CAAA;AAC9D,eAAO,MAAM,mBAAmB;;;;;CAE/B,CAAA;AAID,eAAO,MAAM,OAAO,kBAAkC,CAAA;AAuDtD,wBAAsB,sBAAsB,iCAE3C;AAED,wBAAsB,WAAW,8BAUhC;AAED,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM;;;;;EAsB9D;AAED,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,2BA4GhE;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,EACtC,OAAO,EACP,OAAO,EACP,GAAG,EACH,SAA2E,EAC3E,oBAAoB,EACpB,GAAG,OAAO,EACV,EAAE,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,GAAG;IAClD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oBAAoB,CAAC,EAAE,KAAK,CAAA;CAC5B,GAAG,OAAO,CAAC,KAAK,CAAC,CAwBjB;AAED,wBAAsB,gBAAgB,CAAC,EACtC,UAAU,EACV,OAAO,EACP,GAAG,GACH,EAAE;IACF,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ,oBAaA"}
|
package/dist/esm/cache.server.js
CHANGED
|
@@ -36,8 +36,33 @@ async function readJsonFilesInDirectory(dir) {
|
|
|
36
36
|
return [file, subEntries];
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
|
-
const
|
|
40
|
-
|
|
39
|
+
const maxRetries = 2;
|
|
40
|
+
const baseDelay = 25; // shorter delay for directory listing
|
|
41
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
42
|
+
try {
|
|
43
|
+
const data = await fsExtra.readJSON(filePath);
|
|
44
|
+
return [file, data];
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// Handle JSON parsing errors (could be race condition or corruption)
|
|
48
|
+
if (error instanceof SyntaxError &&
|
|
49
|
+
error.message.includes('JSON')) {
|
|
50
|
+
// If this is a retry attempt, it might be a race condition
|
|
51
|
+
if (attempt < maxRetries) {
|
|
52
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
53
|
+
console.warn(`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for directory listing ${filePath}, retrying in ${delay}ms...`);
|
|
54
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
// Final attempt failed, skip the file
|
|
58
|
+
console.warn(`Skipping corrupted JSON file in directory listing after ${attempt + 1} attempts: ${filePath}`);
|
|
59
|
+
return [file, null];
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// This should never be reached, but just in case
|
|
65
|
+
return [file, null];
|
|
41
66
|
}
|
|
42
67
|
}));
|
|
43
68
|
return Object.fromEntries(entries);
|
|
@@ -80,25 +105,77 @@ export function makeSingletonCache(name) {
|
|
|
80
105
|
}
|
|
81
106
|
export function makeSingletonFsCache(name) {
|
|
82
107
|
return remember(name, () => {
|
|
83
|
-
const cacheDir = path.join(os.homedir(), '.epicshop', 'cache', name);
|
|
108
|
+
const cacheDir = path.join(os.homedir(), '.epicshop', 'cache', process.env.EPICSHOP_WORKSHOP_INSTANCE_ID, name);
|
|
84
109
|
const fsCache = {
|
|
85
110
|
name: `Filesystem cache (${name})`,
|
|
86
111
|
async get(key) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (error instanceof Error &&
|
|
96
|
-
'code' in error &&
|
|
97
|
-
error.code === 'ENOENT') {
|
|
112
|
+
const filePath = path.join(cacheDir, md5(key));
|
|
113
|
+
const maxRetries = 3;
|
|
114
|
+
const baseDelay = 10;
|
|
115
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
116
|
+
try {
|
|
117
|
+
const data = await fsExtra.readJSON(filePath);
|
|
118
|
+
if (data.entry)
|
|
119
|
+
return data.entry;
|
|
98
120
|
return null;
|
|
99
121
|
}
|
|
100
|
-
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error instanceof Error &&
|
|
124
|
+
'code' in error &&
|
|
125
|
+
error.code === 'ENOENT') {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
// Handle JSON parsing errors (could be race condition or corruption)
|
|
129
|
+
if (error instanceof SyntaxError &&
|
|
130
|
+
error.message.includes('JSON')) {
|
|
131
|
+
// If this is a retry attempt, it might be a race condition
|
|
132
|
+
if (attempt < maxRetries) {
|
|
133
|
+
const delay = baseDelay * Math.pow(2, attempt); // exponential backoff
|
|
134
|
+
console.warn(`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for ${filePath}, retrying in ${delay}ms...`);
|
|
135
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Final attempt failed, treat as corrupted file
|
|
139
|
+
// Log to Sentry if available
|
|
140
|
+
if (process.env.SENTRY_DSN && process.env.EPICSHOP_IS_PUBLISHED) {
|
|
141
|
+
try {
|
|
142
|
+
const Sentry = await import('@sentry/react-router');
|
|
143
|
+
Sentry.captureException(error, {
|
|
144
|
+
tags: {
|
|
145
|
+
error_type: 'corrupted_cache_file',
|
|
146
|
+
cache_name: name,
|
|
147
|
+
cache_key: key,
|
|
148
|
+
retry_attempts: attempt.toString(),
|
|
149
|
+
},
|
|
150
|
+
extra: {
|
|
151
|
+
filePath,
|
|
152
|
+
errorMessage: error.message,
|
|
153
|
+
cacheName: name,
|
|
154
|
+
cacheKey: key,
|
|
155
|
+
retryAttempts: attempt,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch (sentryError) {
|
|
160
|
+
console.error('Failed to log to Sentry:', sentryError);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Delete the corrupted file
|
|
164
|
+
try {
|
|
165
|
+
await fsExtra.remove(filePath);
|
|
166
|
+
console.warn(`Deleted corrupted cache file after ${attempt + 1} attempts: ${filePath}`);
|
|
167
|
+
}
|
|
168
|
+
catch (deleteError) {
|
|
169
|
+
console.error(`Failed to delete corrupted cache file ${filePath}:`, deleteError);
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
// For other errors, don't retry
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
101
176
|
}
|
|
177
|
+
// This should never be reached, but just in case
|
|
178
|
+
return null;
|
|
102
179
|
},
|
|
103
180
|
async set(key, entry) {
|
|
104
181
|
const filePath = path.join(cacheDir, md5(key));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.server.js","sourceRoot":"","sources":["../../src/cache.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,KAAK,CAAC,MAAM,qBAAqB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAmB,MAAM,qBAAqB,CAAA;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,OAAO,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,GAAG,MAAM,SAAS,CAAA;AASzB,OAAO,EAAE,uBAAuB,EAAgB,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,MAAM,CAAC,MAAM,gBAAgB,GAC5B,oBAAoB,CAAc,kBAAkB,CAAC,CAAA;AACtD,MAAM,CAAC,MAAM,eAAe,GAC3B,oBAAoB,CAAa,iBAAiB,CAAC,CAAA;AACpD,MAAM,CAAC,MAAM,eAAe,GAC3B,oBAAoB,CAAa,iBAAiB,CAAC,CAAA;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAC9B,oBAAoB,CAAgB,oBAAoB,CAAC,CAAA;AAC1D,MAAM,CAAC,MAAM,SAAS,GAAG,oBAAoB,CAAM,WAAW,CAAC,CAAA;AAC/D,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAS,eAAe,CAAC,CAAA;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAAS,gBAAgB,CAAC,CAAA;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CACxD,uBAAuB,CACvB,CAAA;AACD,MAAM,CAAC,MAAM,iBAAiB,GAC7B,oBAAoB,CAAS,mBAAmB,CAAC,CAAA;AAClD,MAAM,CAAC,MAAM,OAAO,GAAG,kBAAkB,CAAS,SAAS,CAAC,CAAA;AAC5D,MAAM,CAAC,MAAM,gCAAgC,GAAG,oBAAoB,CAIjE,kCAAkC,CAAC,CAAA;AACtC,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CACrD,sBAAsB,CACtB,CAAA;AACD,MAAM,CAAC,MAAM,eAAe,GAAG,kBAAkB,CAAU,iBAAiB,CAAC,CAAA;AAC7E,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAKnD,sBAAsB,CAAC,CAAA;AAC1B,MAAM,CAAC,MAAM,kBAAkB,GAC9B,kBAAkB,CAAsB,oBAAoB,CAAC,CAAA;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CACpD,qBAAqB,CACrB,CAAA;AAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;AAE9D,MAAM,CAAC,MAAM,OAAO,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAA;AAEtD,KAAK,UAAU,wBAAwB,CACtC,GAAW;IAEX,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACxC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACrC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC1C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC,QAAQ,CAAC,CAAA;YAC3D,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QAC1B,CAAC;aAAM,CAAC;YACP,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAC7C,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACpB,CAAC;IACF,CAAC,CAAC,CACF,CAAA;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC3C,OAAO,wBAAwB,CAAC,QAAQ,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAChC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,IAAI,CAAA;IAE9C,IAAI,CAAC;QACJ,IAAI,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAC/B,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,+BAA+B,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAA;IAChE,CAAC;AACF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAiB,IAAY;IAC9D,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QAC1B,MAAM,WAAW,GAAG,IAAI,QAAQ,CAAqC;YACpE,GAAG,EAAE,IAAI;SACT,CAAC,CAAA;QAEF,MAAM,GAAG,GAAG;YACX,IAAI;YACJ,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBACnB,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;gBACtC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE;oBAC3B,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;oBACvC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;iBACjC,CAAC,CAAA;gBACF,OAAO,KAAK,CAAA;YACb,CAAC;YACD,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAClC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;SACN,CAAA;QAEnC,OAAO,GAAG,CAAA;IACX,CAAC,CAAC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAiB,IAAY;IAChE,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QAEpE,MAAM,OAAO,GAA4B;YACxC,IAAI,EAAE,qBAAqB,IAAI,GAAG;YAClC,KAAK,CAAC,GAAG,CAAC,GAAG;gBACZ,IAAI,CAAC;oBACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;oBAC9C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;oBAC7C,IAAI,IAAI,CAAC,KAAK;wBAAE,OAAO,IAAI,CAAC,KAAK,CAAA;oBACjC,OAAO,IAAI,CAAA;gBACZ,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACzB,IACC,KAAK,YAAY,KAAK;wBACtB,MAAM,IAAI,KAAK;wBACf,KAAK,CAAC,IAAI,KAAK,QAAQ,EACtB,CAAC;wBACF,OAAO,IAAI,CAAA;oBACZ,CAAC;oBACD,MAAM,KAAK,CAAA;gBACZ,CAAC;YACF,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK;gBACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;gBAC9C,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;gBAC/C,MAAM,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;YAClD,CAAC;YACD,KAAK,CAAC,MAAM,CAAC,GAAG;gBACf,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;gBAC9C,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YAC/B,CAAC;SACD,CAAA;QAED,OAAO,OAAO,CAAA;IACf,CAAC,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAQ,EACtC,OAAO,EACP,OAAO,EACP,GAAG,EACH,SAAS,GAAG,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAC3E,oBAAoB,EACpB,GAAG,OAAO,EAOV;IACA,IAAI,oBAAoB,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;QAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC/C,OAAO,UAAU,EAAE,KAAK,IAAI,oBAAoB,CAAA;QACjD,CAAC;IACF,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC;QACzC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,OAAO;QACP,GAAG;KACH,CAAC,CAAA;IACF,OAAO,CAAC,CAAC,SAAS,CACjB;QACC,GAAG,OAAO;QACV,GAAG;QACH,UAAU;KACV,EACD,CAAC,CAAC,cAAc,CACf,uBAAuB,CAAC,OAAO,EAAE,SAAS,CAAC,EAC3C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,SAAS,CAChE,CACD,CAAA;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EACtC,UAAU,EACV,OAAO,EACP,GAAG,GAKH;IACA,IAAI,OAAO,UAAU,KAAK,SAAS;QAAE,OAAO,UAAU,CAAA;IACtD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,GAAG,EAAE,CAAC;QAC3C,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC3C,CAAC;IAED,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IAC1B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAA;IAC7B,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAA;IAEtB,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;AACtC,CAAC","sourcesContent":["import os from 'os'\nimport path from 'path'\nimport * as C from '@epic-web/cachified'\nimport { verboseReporter, type CacheEntry } from '@epic-web/cachified'\nimport { remember } from '@epic-web/remember'\nimport fsExtra from 'fs-extra'\nimport { LRUCache } from 'lru-cache'\nimport md5 from 'md5-hex'\nimport {\n\ttype App,\n\ttype ExampleApp,\n\ttype PlaygroundApp,\n\ttype ProblemApp,\n\ttype SolutionApp,\n} from './apps.server.js'\nimport { type Notification } from './notifications.server.js'\nimport { cachifiedTimingReporter, type Timings } from './timing.server.js'\nimport { checkConnectionCached } from './utils.server.js'\n\nexport const solutionAppCache =\n\tmakeSingletonFsCache<SolutionApp>('SolutionAppCache')\nexport const problemAppCache =\n\tmakeSingletonFsCache<ProblemApp>('ProblemAppCache')\nexport const exampleAppCache =\n\tmakeSingletonFsCache<ExampleApp>('ExampleAppCache')\nexport const playgroundAppCache =\n\tmakeSingletonFsCache<PlaygroundApp>('PlaygroundAppCache')\nexport const appsCache = makeSingletonFsCache<App>('AppsCache')\nexport const diffCodeCache = makeSingletonFsCache<string>('DiffCodeCache')\nexport const diffFilesCache = makeSingletonFsCache<string>('DiffFilesCache')\nexport const compiledMarkdownCache = makeSingletonFsCache<string>(\n\t'CompiledMarkdownCache',\n)\nexport const compiledCodeCache =\n\tmakeSingletonFsCache<string>('CompiledCodeCache')\nexport const ogCache = makeSingletonCache<string>('OgCache')\nexport const compiledInstructionMarkdownCache = makeSingletonFsCache<{\n\tcode: string\n\ttitle: string | null\n\tepicVideoEmbeds: Array<string>\n}>('CompiledInstructionMarkdownCache')\nexport const dirModifiedTimeCache = makeSingletonCache<number>(\n\t'DirModifiedTimeCache',\n)\nexport const connectionCache = makeSingletonCache<boolean>('ConnectionCache')\nexport const checkForUpdatesCache = makeSingletonCache<{\n\tupdatesAvailable: boolean\n\tlocalCommit: string\n\tremoteCommit: string\n\tdiffLink: string | null\n}>('CheckForUpdatesCache')\nexport const notificationsCache =\n\tmakeSingletonCache<Array<Notification>>('NotificationsCache')\nexport const directoryEmptyCache = makeSingletonCache<boolean>(\n\t'DirectoryEmptyCache',\n)\n\nconst cacheDir = path.join(os.homedir(), '.epicshop', 'cache')\n\nexport const fsCache = makeSingletonFsCache('FsCache')\n\nasync function readJsonFilesInDirectory(\n\tdir: string,\n): Promise<Record<string, any>> {\n\tconst files = await fsExtra.readdir(dir)\n\tconst entries = await Promise.all(\n\t\tfiles.map(async (file) => {\n\t\t\tconst filePath = path.join(dir, file)\n\t\t\tconst stats = await fsExtra.stat(filePath)\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst subEntries = await readJsonFilesInDirectory(filePath)\n\t\t\t\treturn [file, subEntries]\n\t\t\t} else {\n\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\treturn [file, data]\n\t\t\t}\n\t\t}),\n\t)\n\treturn Object.fromEntries(entries)\n}\n\nexport async function getAllFileCacheEntries() {\n\treturn readJsonFilesInDirectory(cacheDir)\n}\n\nexport async function deleteCache() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\ttry {\n\t\tif (await fsExtra.exists(cacheDir)) {\n\t\t\tawait fsExtra.remove(cacheDir)\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(`Error deleting the cache in ${cacheDir}`, error)\n\t}\n}\n\nexport function makeSingletonCache<CacheEntryType>(name: string) {\n\treturn remember(name, () => {\n\t\tconst lruInstance = new LRUCache<string, CacheEntry<CacheEntryType>>({\n\t\t\tmax: 1000,\n\t\t})\n\n\t\tconst lru = {\n\t\t\tname,\n\t\t\tset: (key, value) => {\n\t\t\t\tconst ttl = C.totalTtl(value.metadata)\n\t\t\t\tlruInstance.set(key, value, {\n\t\t\t\t\tttl: ttl === Infinity ? undefined : ttl,\n\t\t\t\t\tstart: value.metadata.createdTime,\n\t\t\t\t})\n\t\t\t\treturn value\n\t\t\t},\n\t\t\tget: (key) => lruInstance.get(key),\n\t\t\tdelete: (key) => lruInstance.delete(key),\n\t\t} satisfies C.Cache<CacheEntryType>\n\n\t\treturn lru\n\t})\n}\n\nexport function makeSingletonFsCache<CacheEntryType>(name: string) {\n\treturn remember(name, () => {\n\t\tconst cacheDir = path.join(os.homedir(), '.epicshop', 'cache', name)\n\n\t\tconst fsCache: C.Cache<CacheEntryType> = {\n\t\t\tname: `Filesystem cache (${name})`,\n\t\t\tasync get(key) {\n\t\t\t\ttry {\n\t\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\tif (data.entry) return data.entry\n\t\t\t\t\treturn null\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\t'code' in error &&\n\t\t\t\t\t\terror.code === 'ENOENT'\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t},\n\t\t\tasync set(key, entry) {\n\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\tawait fsExtra.ensureDir(path.dirname(filePath))\n\t\t\t\tawait fsExtra.writeJSON(filePath, { key, entry })\n\t\t\t},\n\t\t\tasync delete(key) {\n\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\tawait fsExtra.remove(filePath)\n\t\t\t},\n\t\t}\n\n\t\treturn fsCache\n\t})\n}\n\n/**\n * This wraps @epic-web/cachified to add a few handy features:\n *\n * 1. Automatic timing for timing headers\n * 2. Automatic force refresh based on the request and enhancement of forceFresh\n * to support comma-separated keys to force\n * 3. Offline fallback support. If a fallback is given and we are detected to be\n * offline, then the cached value is used regardless of whether it's expired and\n * if one is not present then the given fallback will be used.\n */\nexport async function cachified<Value>({\n\trequest,\n\ttimings,\n\tkey,\n\ttimingKey = key.length > 18 ? `${key.slice(0, 7)}...${key.slice(-8)}` : key,\n\tofflineFallbackValue,\n\t...options\n}: Omit<C.CachifiedOptions<Value>, 'forceFresh'> & {\n\trequest?: Request\n\ttimings?: Timings\n\tforceFresh?: boolean | string\n\ttimingKey?: string\n\tofflineFallbackValue?: Value\n}): Promise<Value> {\n\tif (offlineFallbackValue !== undefined) {\n\t\tconst isOnline = await checkConnectionCached({ request, timings })\n\t\tif (!isOnline) {\n\t\t\tconst cacheEntry = await options.cache.get(key)\n\t\t\treturn cacheEntry?.value ?? offlineFallbackValue\n\t\t}\n\t}\n\tconst forceFresh = await shouldForceFresh({\n\t\tforceFresh: options.forceFresh,\n\t\trequest,\n\t\tkey,\n\t})\n\treturn C.cachified(\n\t\t{\n\t\t\t...options,\n\t\t\tkey,\n\t\t\tforceFresh,\n\t\t},\n\t\tC.mergeReporters(\n\t\t\tcachifiedTimingReporter(timings, timingKey),\n\t\t\tprocess.env.EPICSHOP_DEBUG_CACHE ? verboseReporter() : undefined,\n\t\t),\n\t)\n}\n\nexport async function shouldForceFresh({\n\tforceFresh,\n\trequest,\n\tkey,\n}: {\n\tforceFresh?: boolean | string\n\trequest?: Request\n\tkey?: string\n}) {\n\tif (typeof forceFresh === 'boolean') return forceFresh\n\tif (typeof forceFresh === 'string' && key) {\n\t\treturn forceFresh.split(',').includes(key)\n\t}\n\n\tif (!request) return false\n\tconst fresh = new URL(request.url).searchParams.get('fresh')\n\tif (typeof fresh !== 'string') return false\n\tif (fresh === '') return true\n\tif (!key) return false\n\n\treturn fresh.split(',').includes(key)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cache.server.js","sourceRoot":"","sources":["../../src/cache.server.ts"],"names":[],"mappings":"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","sourcesContent":["import os from 'os'\nimport path from 'path'\nimport * as C from '@epic-web/cachified'\nimport { verboseReporter, type CacheEntry } from '@epic-web/cachified'\nimport { remember } from '@epic-web/remember'\nimport fsExtra from 'fs-extra'\nimport { LRUCache } from 'lru-cache'\nimport md5 from 'md5-hex'\nimport {\n\ttype App,\n\ttype ExampleApp,\n\ttype PlaygroundApp,\n\ttype ProblemApp,\n\ttype SolutionApp,\n} from './apps.server.js'\nimport { type Notification } from './notifications.server.js'\nimport { cachifiedTimingReporter, type Timings } from './timing.server.js'\nimport { checkConnectionCached } from './utils.server.js'\n\nexport const solutionAppCache =\n\tmakeSingletonFsCache<SolutionApp>('SolutionAppCache')\nexport const problemAppCache =\n\tmakeSingletonFsCache<ProblemApp>('ProblemAppCache')\nexport const exampleAppCache =\n\tmakeSingletonFsCache<ExampleApp>('ExampleAppCache')\nexport const playgroundAppCache =\n\tmakeSingletonFsCache<PlaygroundApp>('PlaygroundAppCache')\nexport const appsCache = makeSingletonFsCache<App>('AppsCache')\nexport const diffCodeCache = makeSingletonFsCache<string>('DiffCodeCache')\nexport const diffFilesCache = makeSingletonFsCache<string>('DiffFilesCache')\nexport const compiledMarkdownCache = makeSingletonFsCache<string>(\n\t'CompiledMarkdownCache',\n)\nexport const compiledCodeCache =\n\tmakeSingletonFsCache<string>('CompiledCodeCache')\nexport const ogCache = makeSingletonCache<string>('OgCache')\nexport const compiledInstructionMarkdownCache = makeSingletonFsCache<{\n\tcode: string\n\ttitle: string | null\n\tepicVideoEmbeds: Array<string>\n}>('CompiledInstructionMarkdownCache')\nexport const dirModifiedTimeCache = makeSingletonCache<number>(\n\t'DirModifiedTimeCache',\n)\nexport const connectionCache = makeSingletonCache<boolean>('ConnectionCache')\nexport const checkForUpdatesCache = makeSingletonCache<{\n\tupdatesAvailable: boolean\n\tlocalCommit: string\n\tremoteCommit: string\n\tdiffLink: string | null\n}>('CheckForUpdatesCache')\nexport const notificationsCache =\n\tmakeSingletonCache<Array<Notification>>('NotificationsCache')\nexport const directoryEmptyCache = makeSingletonCache<boolean>(\n\t'DirectoryEmptyCache',\n)\n\nconst cacheDir = path.join(os.homedir(), '.epicshop', 'cache')\n\nexport const fsCache = makeSingletonFsCache('FsCache')\n\nasync function readJsonFilesInDirectory(\n\tdir: string,\n): Promise<Record<string, any>> {\n\tconst files = await fsExtra.readdir(dir)\n\tconst entries = await Promise.all(\n\t\tfiles.map(async (file) => {\n\t\t\tconst filePath = path.join(dir, file)\n\t\t\tconst stats = await fsExtra.stat(filePath)\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst subEntries = await readJsonFilesInDirectory(filePath)\n\t\t\t\treturn [file, subEntries]\n\t\t\t} else {\n\t\t\t\tconst maxRetries = 2\n\t\t\t\tconst baseDelay = 25 // shorter delay for directory listing\n\n\t\t\t\tfor (let attempt = 0; attempt <= maxRetries; attempt++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\t\treturn [file, data]\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\t// Handle JSON parsing errors (could be race condition or corruption)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof SyntaxError &&\n\t\t\t\t\t\t\terror.message.includes('JSON')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// If this is a retry attempt, it might be a race condition\n\t\t\t\t\t\t\tif (attempt < maxRetries) {\n\t\t\t\t\t\t\t\tconst delay = baseDelay * Math.pow(2, attempt)\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for directory listing ${filePath}, retrying in ${delay}ms...`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Final attempt failed, skip the file\n\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t`Skipping corrupted JSON file in directory listing after ${attempt + 1} attempts: ${filePath}`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn [file, null]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This should never be reached, but just in case\n\t\t\t\treturn [file, null]\n\t\t\t}\n\t\t}),\n\t)\n\treturn Object.fromEntries(entries)\n}\n\nexport async function getAllFileCacheEntries() {\n\treturn readJsonFilesInDirectory(cacheDir)\n}\n\nexport async function deleteCache() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\ttry {\n\t\tif (await fsExtra.exists(cacheDir)) {\n\t\t\tawait fsExtra.remove(cacheDir)\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(`Error deleting the cache in ${cacheDir}`, error)\n\t}\n}\n\nexport function makeSingletonCache<CacheEntryType>(name: string) {\n\treturn remember(name, () => {\n\t\tconst lruInstance = new LRUCache<string, CacheEntry<CacheEntryType>>({\n\t\t\tmax: 1000,\n\t\t})\n\n\t\tconst lru = {\n\t\t\tname,\n\t\t\tset: (key, value) => {\n\t\t\t\tconst ttl = C.totalTtl(value.metadata)\n\t\t\t\tlruInstance.set(key, value, {\n\t\t\t\t\tttl: ttl === Infinity ? undefined : ttl,\n\t\t\t\t\tstart: value.metadata.createdTime,\n\t\t\t\t})\n\t\t\t\treturn value\n\t\t\t},\n\t\t\tget: (key) => lruInstance.get(key),\n\t\t\tdelete: (key) => lruInstance.delete(key),\n\t\t} satisfies C.Cache<CacheEntryType>\n\n\t\treturn lru\n\t})\n}\n\nexport function makeSingletonFsCache<CacheEntryType>(name: string) {\n\treturn remember(name, () => {\n\t\tconst cacheDir = path.join(\n\t\t\tos.homedir(),\n\t\t\t'.epicshop',\n\t\t\t'cache',\n\t\t\tprocess.env.EPICSHOP_WORKSHOP_INSTANCE_ID,\n\t\t\tname,\n\t\t)\n\n\t\tconst fsCache: C.Cache<CacheEntryType> = {\n\t\t\tname: `Filesystem cache (${name})`,\n\t\t\tasync get(key) {\n\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\tconst maxRetries = 3\n\t\t\t\tconst baseDelay = 10\n\n\t\t\t\tfor (let attempt = 0; attempt <= maxRetries; attempt++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\t\tif (data.entry) return data.entry\n\t\t\t\t\t\treturn null\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\t\t'code' in error &&\n\t\t\t\t\t\t\terror.code === 'ENOENT'\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Handle JSON parsing errors (could be race condition or corruption)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof SyntaxError &&\n\t\t\t\t\t\t\terror.message.includes('JSON')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// If this is a retry attempt, it might be a race condition\n\t\t\t\t\t\t\tif (attempt < maxRetries) {\n\t\t\t\t\t\t\t\tconst delay = baseDelay * Math.pow(2, attempt) // exponential backoff\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for ${filePath}, retrying in ${delay}ms...`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Final attempt failed, treat as corrupted file\n\t\t\t\t\t\t\t// Log to Sentry if available\n\t\t\t\t\t\t\tif (process.env.SENTRY_DSN && process.env.EPICSHOP_IS_PUBLISHED) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst Sentry = await import('@sentry/react-router')\n\t\t\t\t\t\t\t\t\tSentry.captureException(error, {\n\t\t\t\t\t\t\t\t\t\ttags: {\n\t\t\t\t\t\t\t\t\t\t\terror_type: 'corrupted_cache_file',\n\t\t\t\t\t\t\t\t\t\t\tcache_name: name,\n\t\t\t\t\t\t\t\t\t\t\tcache_key: key,\n\t\t\t\t\t\t\t\t\t\t\tretry_attempts: attempt.toString(),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\textra: {\n\t\t\t\t\t\t\t\t\t\t\tfilePath,\n\t\t\t\t\t\t\t\t\t\t\terrorMessage: error.message,\n\t\t\t\t\t\t\t\t\t\t\tcacheName: name,\n\t\t\t\t\t\t\t\t\t\t\tcacheKey: key,\n\t\t\t\t\t\t\t\t\t\t\tretryAttempts: attempt,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t} catch (sentryError) {\n\t\t\t\t\t\t\t\t\tconsole.error('Failed to log to Sentry:', sentryError)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Delete the corrupted file\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait fsExtra.remove(filePath)\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`Deleted corrupted cache file after ${attempt + 1} attempts: ${filePath}`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t} catch (deleteError) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t`Failed to delete corrupted cache file ${filePath}:`,\n\t\t\t\t\t\t\t\t\tdeleteError,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// For other errors, don't retry\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This should never be reached, but just in case\n\t\t\t\treturn null\n\t\t\t},\n\t\t\tasync set(key, entry) {\n\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\tawait fsExtra.ensureDir(path.dirname(filePath))\n\t\t\t\tawait fsExtra.writeJSON(filePath, { key, entry })\n\t\t\t},\n\t\t\tasync delete(key) {\n\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\tawait fsExtra.remove(filePath)\n\t\t\t},\n\t\t}\n\n\t\treturn fsCache\n\t})\n}\n\n/**\n * This wraps @epic-web/cachified to add a few handy features:\n *\n * 1. Automatic timing for timing headers\n * 2. Automatic force refresh based on the request and enhancement of forceFresh\n * to support comma-separated keys to force\n * 3. Offline fallback support. If a fallback is given and we are detected to be\n * offline, then the cached value is used regardless of whether it's expired and\n * if one is not present then the given fallback will be used.\n */\nexport async function cachified<Value>({\n\trequest,\n\ttimings,\n\tkey,\n\ttimingKey = key.length > 18 ? `${key.slice(0, 7)}...${key.slice(-8)}` : key,\n\tofflineFallbackValue,\n\t...options\n}: Omit<C.CachifiedOptions<Value>, 'forceFresh'> & {\n\trequest?: Request\n\ttimings?: Timings\n\tforceFresh?: boolean | string\n\ttimingKey?: string\n\tofflineFallbackValue?: Value\n}): Promise<Value> {\n\tif (offlineFallbackValue !== undefined) {\n\t\tconst isOnline = await checkConnectionCached({ request, timings })\n\t\tif (!isOnline) {\n\t\t\tconst cacheEntry = await options.cache.get(key)\n\t\t\treturn cacheEntry?.value ?? offlineFallbackValue\n\t\t}\n\t}\n\tconst forceFresh = await shouldForceFresh({\n\t\tforceFresh: options.forceFresh,\n\t\trequest,\n\t\tkey,\n\t})\n\treturn C.cachified(\n\t\t{\n\t\t\t...options,\n\t\t\tkey,\n\t\t\tforceFresh,\n\t\t},\n\t\tC.mergeReporters(\n\t\t\tcachifiedTimingReporter(timings, timingKey),\n\t\t\tprocess.env.EPICSHOP_DEBUG_CACHE ? verboseReporter() : undefined,\n\t\t),\n\t)\n}\n\nexport async function shouldForceFresh({\n\tforceFresh,\n\trequest,\n\tkey,\n}: {\n\tforceFresh?: boolean | string\n\trequest?: Request\n\tkey?: string\n}) {\n\tif (typeof forceFresh === 'boolean') return forceFresh\n\tif (typeof forceFresh === 'string' && key) {\n\t\treturn forceFresh.split(',').includes(key)\n\t}\n\n\tif (!request) return false\n\tconst fresh = new URL(request.url).searchParams.get('fresh')\n\tif (typeof fresh !== 'string') return false\n\tif (fresh === '') return true\n\tif (!key) return false\n\n\treturn fresh.split(',').includes(key)\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.server.d.ts","sourceRoot":"","sources":["../../src/db.server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,QAAA,MAAM,cAAc;;;;;;;;;;;;EAIlB,CAAA;AACF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyBvB,CAAA;AAkBb,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCd,CAAA;AAKF,wBAAsB,WAAW,oBAQhC;AAED,wBAAsB,MAAM,kBAY3B;AAED,wBAAsB,QAAQ,8BAU7B;
|
|
1
|
+
{"version":3,"file":"db.server.d.ts","sourceRoot":"","sources":["../../src/db.server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,QAAA,MAAM,cAAc;;;;;;;;;;;;EAIlB,CAAA;AACF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyBvB,CAAA;AAkBb,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCd,CAAA;AAKF,wBAAsB,WAAW,oBAQhC;AAED,wBAAsB,MAAM,kBAY3B;AAED,wBAAsB,QAAQ,8BAU7B;AA2DD,wBAAsB,WAAW;;;;;;;;;sBAuBhC;AAED,wBAAsB,eAAe,CAAC,EACrC,OAAO,EACP,UAAU,GACV,EAAE;IACF,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;;;;;;;;;GAeA;AAED,wBAAsB,WAAW,CAAC,EACjC,EAAE,EACF,QAAQ,EACR,KAA6B,EAC7B,IAAI,GACJ,EAAE;IACF,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC,CAAA;IACjD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;;;;;;;;;GAiBA;AAED,wBAAsB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;UAGnC;AAED,wBAAsB,cAAc,CACnC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;GAyBtD;AAED,wBAAsB,qBAAqB,sBAG1C;AAED,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,MAAM,qBAYhD;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,+BASvE;AAED,wBAAsB,qBAAqB,2BAG1C;AAED,wBAAsB,kBAAkB;;;;WAGvC;AAED,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM;;GAehE"}
|
package/dist/esm/db.server.js
CHANGED
|
@@ -122,15 +122,48 @@ export async function deleteDb() {
|
|
|
122
122
|
async function readDb() {
|
|
123
123
|
if (process.env.EPICSHOP_DEPLOYED)
|
|
124
124
|
return null;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
const maxRetries = 3;
|
|
126
|
+
const baseDelay = 10;
|
|
127
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
128
|
+
try {
|
|
129
|
+
if (await fsExtra.exists(dbPath)) {
|
|
130
|
+
const db = DataSchema.parse(await fsExtra.readJSON(dbPath));
|
|
131
|
+
return db;
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
// If this is a retry attempt, it might be a race condition
|
|
137
|
+
if (attempt < maxRetries) {
|
|
138
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
139
|
+
console.warn(`Database read error on attempt ${attempt + 1}/${maxRetries + 1}, retrying in ${delay}ms...`);
|
|
140
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// Final attempt failed, handle as corrupted file
|
|
144
|
+
console.error(`Error reading the database in ${dbPath} after ${attempt + 1} attempts, moving it to a .bkp file to avoid parsing errors in the future`, error);
|
|
145
|
+
// Log to Sentry if available
|
|
146
|
+
if (process.env.SENTRY_DSN && process.env.EPICSHOP_IS_PUBLISHED) {
|
|
147
|
+
try {
|
|
148
|
+
const Sentry = await import('@sentry/react-router');
|
|
149
|
+
Sentry.captureException(error, {
|
|
150
|
+
tags: {
|
|
151
|
+
error_type: 'corrupted_database_file',
|
|
152
|
+
retry_attempts: attempt.toString(),
|
|
153
|
+
},
|
|
154
|
+
extra: {
|
|
155
|
+
filePath: dbPath,
|
|
156
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
157
|
+
retryAttempts: attempt,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
catch (sentryError) {
|
|
162
|
+
console.error('Failed to log to Sentry:', sentryError);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
void fsExtra.move(dbPath, `${dbPath}.bkp`).catch(() => { });
|
|
129
166
|
}
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
console.error(`Error reading the database in ${dbPath}, moving it to a .bkp file to avoid parsing errors in the future`, error);
|
|
133
|
-
void fsExtra.move(dbPath, `${dbPath}.bkp`).catch(() => { });
|
|
134
167
|
}
|
|
135
168
|
return null;
|
|
136
169
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.server.js","sourceRoot":"","sources":["../../src/db.server.ts"],"names":[],"mappings":"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","sourcesContent":["import os from 'os'\nimport path from 'path'\nimport { createId as cuid } from '@paralleldrive/cuid2'\nimport fsExtra from 'fs-extra'\nimport { redirect } from 'react-router'\nimport { z } from 'zod'\nimport { getWorkshopConfig } from './config.server.js'\n\nconst TokenSetSchema = z.object({\n\taccess_token: z.string(),\n\ttoken_type: z.string(),\n\tscope: z.string(),\n})\nexport const PlayerPreferencesSchema = z\n\t.object({\n\t\tminResolution: z.number().optional(),\n\t\tmaxResolution: z.number().optional(),\n\t\tvolumeRate: z.number().optional(),\n\t\tplaybackRate: z.number().optional(),\n\t\tautoplay: z.boolean().optional(),\n\t\tsubtitle: z\n\t\t\t.object({\n\t\t\t\tid: z.string().nullable().default(null),\n\t\t\t\tmode: z\n\t\t\t\t\t.literal('disabled')\n\t\t\t\t\t.or(z.literal('hidden'))\n\t\t\t\t\t.or(z.literal('showing'))\n\t\t\t\t\t.nullable()\n\t\t\t\t\t.default('disabled'),\n\t\t\t})\n\t\t\t.optional()\n\t\t\t.default({}),\n\t\tmuted: z.boolean().optional(),\n\t\ttheater: z.boolean().optional(),\n\t\tdefaultView: z.string().optional(),\n\t\tactiveSidebarTab: z.number().optional(),\n\t})\n\t.optional()\n\t.default({})\n\nconst PresencePreferencesSchema = z\n\t.object({\n\t\toptOut: z.boolean(),\n\t})\n\t.optional()\n\t.default({ optOut: false })\n\nconst AuthInfoSchema = z.object({\n\tid: z.string(),\n\ttokenSet: TokenSetSchema,\n\temail: z.string(),\n\tname: z.string().nullable().optional(),\n})\n\nconst MutedNotificationSchema = z.array(z.string()).default([])\n\nconst DataSchema = z.object({\n\tonboarding: z\n\t\t.object({\n\t\t\ttourVideosWatched: z.array(z.string()).default([]),\n\t\t})\n\t\t.passthrough()\n\t\t.optional()\n\t\t.default({ tourVideosWatched: [] }),\n\tpreferences: z\n\t\t.object({\n\t\t\tplayer: PlayerPreferencesSchema,\n\t\t\tpresence: PresencePreferencesSchema,\n\t\t\tplayground: z\n\t\t\t\t.object({\n\t\t\t\t\tpersist: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tfontSize: z.number().optional(),\n\t\t\texerciseWarning: z\n\t\t\t\t.object({\n\t\t\t\t\tdismissed: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional()\n\t\t\t\t.default({ dismissed: false }),\n\t\t})\n\t\t.optional()\n\t\t.default({}),\n\t// deprecated. Probably safe to remove in May 2026:\n\tauthInfo: AuthInfoSchema.optional(),\n\t// new:\n\tauthInfos: z.record(z.string(), AuthInfoSchema).optional(),\n\tclientId: z.string().optional(),\n\tmutedNotifications: MutedNotificationSchema.optional(),\n})\n\nconst appDir = path.join(os.homedir(), '.epicshop')\nconst dbPath = path.join(appDir, 'data.json')\n\nexport async function getClientId() {\n\tconst data = await readDb()\n\tif (data?.clientId) return data.clientId\n\n\tconst clientId = cuid()\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, { ...data, clientId })\n\treturn clientId\n}\n\nexport async function logout() {\n\tconst config = getWorkshopConfig()\n\tconst host = config.product.host\n\tif (host) {\n\t\tconst data = await readDb()\n\t\tconst newAuthInfos = { ...data?.authInfos }\n\t\tdelete newAuthInfos[host]\n\t\tawait fsExtra.writeJSON(dbPath, {\n\t\t\t...data,\n\t\t\tauthInfos: newAuthInfos,\n\t\t})\n\t}\n}\n\nexport async function deleteDb() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\ttry {\n\t\tif (await fsExtra.exists(dbPath)) {\n\t\t\tawait fsExtra.remove(dbPath)\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(`Error deleting the database in ${dbPath}`, error)\n\t}\n}\n\nasync function readDb() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\ttry {\n\t\tif (await fsExtra.exists(dbPath)) {\n\t\t\tconst db = DataSchema.parse(await fsExtra.readJSON(dbPath))\n\t\t\treturn db\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(\n\t\t\t`Error reading the database in ${dbPath}, moving it to a .bkp file to avoid parsing errors in the future`,\n\t\t\terror,\n\t\t)\n\t\tvoid fsExtra.move(dbPath, `${dbPath}.bkp`).catch(() => {})\n\t}\n\treturn null\n}\n\nexport async function getAuthInfo() {\n\tconst config = getWorkshopConfig()\n\tconst data = await readDb()\n\tif (config.product.host && typeof data?.authInfos === 'object') {\n\t\tif (config.product.host in data.authInfos) {\n\t\t\treturn data.authInfos[config.product.host]\n\t\t}\n\t}\n\n\t// special case for non-epicweb/epicreact workshops\n\tif (\n\t\t!config.product.host ||\n\t\tconfig.product.host === 'epicweb.dev' ||\n\t\tconfig.product.host === 'epicreact.dev'\n\t) {\n\t\t// upgrade from old authInfo to new authInfos\n\t\tif (data?.authInfo && config.product.host) {\n\t\t\tawait setAuthInfo(data.authInfo)\n\t\t}\n\t\treturn data?.authInfo ?? null\n\t}\n\n\treturn null\n}\n\nexport async function requireAuthInfo({\n\trequest,\n\tredirectTo,\n}: {\n\trequest: Request\n\tredirectTo?: string | null\n}) {\n\tconst authInfo = await getAuthInfo()\n\tif (!authInfo) {\n\t\tconst requestUrl = new URL(request.url)\n\t\tredirectTo =\n\t\t\tredirectTo === null\n\t\t\t\t? null\n\t\t\t\t: (redirectTo ?? `${requestUrl.pathname}${requestUrl.search}`)\n\t\tconst loginParams = redirectTo ? new URLSearchParams({ redirectTo }) : null\n\t\tconst loginRedirect = ['/login', loginParams?.toString()]\n\t\t\t.filter(Boolean)\n\t\t\t.join('?')\n\t\tthrow redirect(loginRedirect)\n\t}\n\treturn authInfo\n}\n\nexport async function setAuthInfo({\n\tid,\n\ttokenSet,\n\temail = 'unknown@example.com',\n\tname,\n}: {\n\tid: string\n\ttokenSet: Partial<z.infer<typeof TokenSetSchema>>\n\temail?: string | null\n\tname?: string | null\n}) {\n\tconst data = await readDb()\n\tconst authInfo = AuthInfoSchema.parse({ id, tokenSet, email, name })\n\tawait fsExtra.ensureDir(appDir)\n\tconst config = getWorkshopConfig()\n\tif (config.product.host) {\n\t\tawait fsExtra.writeJSON(dbPath, {\n\t\t\t...data,\n\t\t\tauthInfos: {\n\t\t\t\t...data?.authInfos,\n\t\t\t\t[config.product.host]: authInfo,\n\t\t\t},\n\t\t})\n\t} else {\n\t\tawait fsExtra.writeJSON(dbPath, { ...data, authInfo })\n\t}\n\treturn authInfo\n}\n\nexport async function getPreferences() {\n\tconst data = await readDb()\n\treturn data?.preferences ?? null\n}\n\nexport async function setPreferences(\n\tpreferences: z.input<typeof DataSchema>['preferences'],\n) {\n\tconst data = await readDb()\n\tconst updatedData = {\n\t\t...data,\n\t\tpreferences: {\n\t\t\t...data?.preferences,\n\t\t\t...preferences,\n\t\t\tplayer: {\n\t\t\t\t...data?.preferences?.player,\n\t\t\t\t...preferences?.player,\n\t\t\t},\n\t\t\tpresence: {\n\t\t\t\t...data?.preferences?.presence,\n\t\t\t\t...preferences?.presence,\n\t\t\t},\n\t\t\texerciseWarning: {\n\t\t\t\t...data?.preferences?.exerciseWarning,\n\t\t\t\t...preferences?.exerciseWarning,\n\t\t\t},\n\t\t},\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn updatedData.preferences\n}\n\nexport async function getMutedNotifications() {\n\tconst data = await readDb()\n\treturn data?.mutedNotifications ?? []\n}\n\nexport async function muteNotification(id: string) {\n\tconst data = await readDb()\n\tconst mutedNotifications = Array.from(\n\t\tnew Set([...(data?.mutedNotifications ?? []), id]),\n\t)\n\tconst updatedData = {\n\t\t...data,\n\t\tmutedNotifications,\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn mutedNotifications\n}\n\nexport async function setFontSizePreference(fontSize: number | undefined) {\n\tconst data = await readDb()\n\tconst updatedData = {\n\t\t...data,\n\t\tpreferences: { ...data?.preferences, fontSize },\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn updatedData.preferences.fontSize\n}\n\nexport async function getFontSizePreference() {\n\tconst data = await readDb()\n\treturn data?.preferences?.fontSize ?? null\n}\n\nexport async function readOnboardingData() {\n\tconst data = await readDb()\n\treturn data?.onboarding ?? null\n}\n\nexport async function markOnboardingVideoWatched(videoUrl: string) {\n\tconst data = await readDb()\n\tconst updatedData = {\n\t\t...data,\n\t\tonboarding: {\n\t\t\t...data?.onboarding,\n\t\t\ttourVideosWatched: [\n\t\t\t\t...(data?.onboarding.tourVideosWatched ?? []),\n\t\t\t\tvideoUrl,\n\t\t\t].filter(Boolean),\n\t\t},\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn updatedData.onboarding\n}\n"]}
|
|
1
|
+
{"version":3,"file":"db.server.js","sourceRoot":"","sources":["../../src/db.server.ts"],"names":[],"mappings":"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","sourcesContent":["import os from 'os'\nimport path from 'path'\nimport { createId as cuid } from '@paralleldrive/cuid2'\nimport fsExtra from 'fs-extra'\nimport { redirect } from 'react-router'\nimport { z } from 'zod'\nimport { getWorkshopConfig } from './config.server.js'\n\nconst TokenSetSchema = z.object({\n\taccess_token: z.string(),\n\ttoken_type: z.string(),\n\tscope: z.string(),\n})\nexport const PlayerPreferencesSchema = z\n\t.object({\n\t\tminResolution: z.number().optional(),\n\t\tmaxResolution: z.number().optional(),\n\t\tvolumeRate: z.number().optional(),\n\t\tplaybackRate: z.number().optional(),\n\t\tautoplay: z.boolean().optional(),\n\t\tsubtitle: z\n\t\t\t.object({\n\t\t\t\tid: z.string().nullable().default(null),\n\t\t\t\tmode: z\n\t\t\t\t\t.literal('disabled')\n\t\t\t\t\t.or(z.literal('hidden'))\n\t\t\t\t\t.or(z.literal('showing'))\n\t\t\t\t\t.nullable()\n\t\t\t\t\t.default('disabled'),\n\t\t\t})\n\t\t\t.optional()\n\t\t\t.default({}),\n\t\tmuted: z.boolean().optional(),\n\t\ttheater: z.boolean().optional(),\n\t\tdefaultView: z.string().optional(),\n\t\tactiveSidebarTab: z.number().optional(),\n\t})\n\t.optional()\n\t.default({})\n\nconst PresencePreferencesSchema = z\n\t.object({\n\t\toptOut: z.boolean(),\n\t})\n\t.optional()\n\t.default({ optOut: false })\n\nconst AuthInfoSchema = z.object({\n\tid: z.string(),\n\ttokenSet: TokenSetSchema,\n\temail: z.string(),\n\tname: z.string().nullable().optional(),\n})\n\nconst MutedNotificationSchema = z.array(z.string()).default([])\n\nconst DataSchema = z.object({\n\tonboarding: z\n\t\t.object({\n\t\t\ttourVideosWatched: z.array(z.string()).default([]),\n\t\t})\n\t\t.passthrough()\n\t\t.optional()\n\t\t.default({ tourVideosWatched: [] }),\n\tpreferences: z\n\t\t.object({\n\t\t\tplayer: PlayerPreferencesSchema,\n\t\t\tpresence: PresencePreferencesSchema,\n\t\t\tplayground: z\n\t\t\t\t.object({\n\t\t\t\t\tpersist: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tfontSize: z.number().optional(),\n\t\t\texerciseWarning: z\n\t\t\t\t.object({\n\t\t\t\t\tdismissed: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional()\n\t\t\t\t.default({ dismissed: false }),\n\t\t})\n\t\t.optional()\n\t\t.default({}),\n\t// deprecated. Probably safe to remove in May 2026:\n\tauthInfo: AuthInfoSchema.optional(),\n\t// new:\n\tauthInfos: z.record(z.string(), AuthInfoSchema).optional(),\n\tclientId: z.string().optional(),\n\tmutedNotifications: MutedNotificationSchema.optional(),\n})\n\nconst appDir = path.join(os.homedir(), '.epicshop')\nconst dbPath = path.join(appDir, 'data.json')\n\nexport async function getClientId() {\n\tconst data = await readDb()\n\tif (data?.clientId) return data.clientId\n\n\tconst clientId = cuid()\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, { ...data, clientId })\n\treturn clientId\n}\n\nexport async function logout() {\n\tconst config = getWorkshopConfig()\n\tconst host = config.product.host\n\tif (host) {\n\t\tconst data = await readDb()\n\t\tconst newAuthInfos = { ...data?.authInfos }\n\t\tdelete newAuthInfos[host]\n\t\tawait fsExtra.writeJSON(dbPath, {\n\t\t\t...data,\n\t\t\tauthInfos: newAuthInfos,\n\t\t})\n\t}\n}\n\nexport async function deleteDb() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\ttry {\n\t\tif (await fsExtra.exists(dbPath)) {\n\t\t\tawait fsExtra.remove(dbPath)\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(`Error deleting the database in ${dbPath}`, error)\n\t}\n}\n\nasync function readDb() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\tconst maxRetries = 3\n\tconst baseDelay = 10\n\n\tfor (let attempt = 0; attempt <= maxRetries; attempt++) {\n\t\ttry {\n\t\t\tif (await fsExtra.exists(dbPath)) {\n\t\t\t\tconst db = DataSchema.parse(await fsExtra.readJSON(dbPath))\n\t\t\t\treturn db\n\t\t\t}\n\t\t\treturn null\n\t\t} catch (error) {\n\t\t\t// If this is a retry attempt, it might be a race condition\n\t\t\tif (attempt < maxRetries) {\n\t\t\t\tconst delay = baseDelay * Math.pow(2, attempt)\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Database read error on attempt ${attempt + 1}/${maxRetries + 1}, retrying in ${delay}ms...`,\n\t\t\t\t)\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Final attempt failed, handle as corrupted file\n\t\t\tconsole.error(\n\t\t\t\t`Error reading the database in ${dbPath} after ${attempt + 1} attempts, moving it to a .bkp file to avoid parsing errors in the future`,\n\t\t\t\terror,\n\t\t\t)\n\n\t\t\t// Log to Sentry if available\n\t\t\tif (process.env.SENTRY_DSN && process.env.EPICSHOP_IS_PUBLISHED) {\n\t\t\t\ttry {\n\t\t\t\t\tconst Sentry = await import('@sentry/react-router')\n\t\t\t\t\tSentry.captureException(error, {\n\t\t\t\t\t\ttags: {\n\t\t\t\t\t\t\terror_type: 'corrupted_database_file',\n\t\t\t\t\t\t\tretry_attempts: attempt.toString(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\textra: {\n\t\t\t\t\t\t\tfilePath: dbPath,\n\t\t\t\t\t\t\terrorMessage:\n\t\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t\tretryAttempts: attempt,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t} catch (sentryError) {\n\t\t\t\t\tconsole.error('Failed to log to Sentry:', sentryError)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid fsExtra.move(dbPath, `${dbPath}.bkp`).catch(() => {})\n\t\t}\n\t}\n\treturn null\n}\n\nexport async function getAuthInfo() {\n\tconst config = getWorkshopConfig()\n\tconst data = await readDb()\n\tif (config.product.host && typeof data?.authInfos === 'object') {\n\t\tif (config.product.host in data.authInfos) {\n\t\t\treturn data.authInfos[config.product.host]\n\t\t}\n\t}\n\n\t// special case for non-epicweb/epicreact workshops\n\tif (\n\t\t!config.product.host ||\n\t\tconfig.product.host === 'epicweb.dev' ||\n\t\tconfig.product.host === 'epicreact.dev'\n\t) {\n\t\t// upgrade from old authInfo to new authInfos\n\t\tif (data?.authInfo && config.product.host) {\n\t\t\tawait setAuthInfo(data.authInfo)\n\t\t}\n\t\treturn data?.authInfo ?? null\n\t}\n\n\treturn null\n}\n\nexport async function requireAuthInfo({\n\trequest,\n\tredirectTo,\n}: {\n\trequest: Request\n\tredirectTo?: string | null\n}) {\n\tconst authInfo = await getAuthInfo()\n\tif (!authInfo) {\n\t\tconst requestUrl = new URL(request.url)\n\t\tredirectTo =\n\t\t\tredirectTo === null\n\t\t\t\t? null\n\t\t\t\t: (redirectTo ?? `${requestUrl.pathname}${requestUrl.search}`)\n\t\tconst loginParams = redirectTo ? new URLSearchParams({ redirectTo }) : null\n\t\tconst loginRedirect = ['/login', loginParams?.toString()]\n\t\t\t.filter(Boolean)\n\t\t\t.join('?')\n\t\tthrow redirect(loginRedirect)\n\t}\n\treturn authInfo\n}\n\nexport async function setAuthInfo({\n\tid,\n\ttokenSet,\n\temail = 'unknown@example.com',\n\tname,\n}: {\n\tid: string\n\ttokenSet: Partial<z.infer<typeof TokenSetSchema>>\n\temail?: string | null\n\tname?: string | null\n}) {\n\tconst data = await readDb()\n\tconst authInfo = AuthInfoSchema.parse({ id, tokenSet, email, name })\n\tawait fsExtra.ensureDir(appDir)\n\tconst config = getWorkshopConfig()\n\tif (config.product.host) {\n\t\tawait fsExtra.writeJSON(dbPath, {\n\t\t\t...data,\n\t\t\tauthInfos: {\n\t\t\t\t...data?.authInfos,\n\t\t\t\t[config.product.host]: authInfo,\n\t\t\t},\n\t\t})\n\t} else {\n\t\tawait fsExtra.writeJSON(dbPath, { ...data, authInfo })\n\t}\n\treturn authInfo\n}\n\nexport async function getPreferences() {\n\tconst data = await readDb()\n\treturn data?.preferences ?? null\n}\n\nexport async function setPreferences(\n\tpreferences: z.input<typeof DataSchema>['preferences'],\n) {\n\tconst data = await readDb()\n\tconst updatedData = {\n\t\t...data,\n\t\tpreferences: {\n\t\t\t...data?.preferences,\n\t\t\t...preferences,\n\t\t\tplayer: {\n\t\t\t\t...data?.preferences?.player,\n\t\t\t\t...preferences?.player,\n\t\t\t},\n\t\t\tpresence: {\n\t\t\t\t...data?.preferences?.presence,\n\t\t\t\t...preferences?.presence,\n\t\t\t},\n\t\t\texerciseWarning: {\n\t\t\t\t...data?.preferences?.exerciseWarning,\n\t\t\t\t...preferences?.exerciseWarning,\n\t\t\t},\n\t\t},\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn updatedData.preferences\n}\n\nexport async function getMutedNotifications() {\n\tconst data = await readDb()\n\treturn data?.mutedNotifications ?? []\n}\n\nexport async function muteNotification(id: string) {\n\tconst data = await readDb()\n\tconst mutedNotifications = Array.from(\n\t\tnew Set([...(data?.mutedNotifications ?? []), id]),\n\t)\n\tconst updatedData = {\n\t\t...data,\n\t\tmutedNotifications,\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn mutedNotifications\n}\n\nexport async function setFontSizePreference(fontSize: number | undefined) {\n\tconst data = await readDb()\n\tconst updatedData = {\n\t\t...data,\n\t\tpreferences: { ...data?.preferences, fontSize },\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn updatedData.preferences.fontSize\n}\n\nexport async function getFontSizePreference() {\n\tconst data = await readDb()\n\treturn data?.preferences?.fontSize ?? null\n}\n\nexport async function readOnboardingData() {\n\tconst data = await readDb()\n\treturn data?.onboarding ?? null\n}\n\nexport async function markOnboardingVideoWatched(videoUrl: string) {\n\tconst data = await readDb()\n\tconst updatedData = {\n\t\t...data,\n\t\tonboarding: {\n\t\t\t...data?.onboarding,\n\t\t\ttourVideosWatched: [\n\t\t\t\t...(data?.onboarding.tourVideosWatched ?? []),\n\t\t\t\tvideoUrl,\n\t\t\t].filter(Boolean),\n\t\t},\n\t}\n\tawait fsExtra.ensureDir(appDir)\n\tawait fsExtra.writeJSON(dbPath, updatedData)\n\treturn updatedData.onboarding\n}\n"]}
|
package/dist/esm/env.server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
declare const schema: z.ZodEffects<z.ZodObject<{
|
|
3
3
|
EPICSHOP_CONTEXT_CWD: z.ZodDefault<z.ZodString>;
|
|
4
|
+
EPICSHOP_WORKSHOP_INSTANCE_ID: z.ZodDefault<z.ZodString>;
|
|
4
5
|
NODE_ENV: z.ZodDefault<z.ZodEnum<["production", "development", "test"]>>;
|
|
5
6
|
EPICSHOP_GITHUB_REPO: z.ZodDefault<z.ZodString>;
|
|
6
7
|
EPICSHOP_GITHUB_ROOT: z.ZodDefault<z.ZodString>;
|
|
@@ -15,6 +16,7 @@ declare const schema: z.ZodEffects<z.ZodObject<{
|
|
|
15
16
|
SENTRY_PROJECT_ID: z.ZodDefault<z.ZodString>;
|
|
16
17
|
}, "strip", z.ZodTypeAny, {
|
|
17
18
|
EPICSHOP_CONTEXT_CWD: string;
|
|
19
|
+
EPICSHOP_WORKSHOP_INSTANCE_ID: string;
|
|
18
20
|
NODE_ENV: "production" | "development" | "test";
|
|
19
21
|
EPICSHOP_GITHUB_REPO: string;
|
|
20
22
|
EPICSHOP_GITHUB_ROOT: string;
|
|
@@ -29,6 +31,7 @@ declare const schema: z.ZodEffects<z.ZodObject<{
|
|
|
29
31
|
EPICSHOP_APP_LOCATION?: string | undefined;
|
|
30
32
|
}, {
|
|
31
33
|
EPICSHOP_CONTEXT_CWD?: string | undefined;
|
|
34
|
+
EPICSHOP_WORKSHOP_INSTANCE_ID?: string | undefined;
|
|
32
35
|
NODE_ENV?: "production" | "development" | "test" | undefined;
|
|
33
36
|
EPICSHOP_GITHUB_REPO?: string | undefined;
|
|
34
37
|
EPICSHOP_GITHUB_ROOT?: string | undefined;
|
|
@@ -43,6 +46,7 @@ declare const schema: z.ZodEffects<z.ZodObject<{
|
|
|
43
46
|
SENTRY_PROJECT_ID?: string | undefined;
|
|
44
47
|
}>, {
|
|
45
48
|
EPICSHOP_CONTEXT_CWD: string;
|
|
49
|
+
EPICSHOP_WORKSHOP_INSTANCE_ID: string;
|
|
46
50
|
NODE_ENV: "production" | "development" | "test";
|
|
47
51
|
EPICSHOP_GITHUB_REPO: string;
|
|
48
52
|
EPICSHOP_GITHUB_ROOT: string;
|
|
@@ -57,6 +61,7 @@ declare const schema: z.ZodEffects<z.ZodObject<{
|
|
|
57
61
|
EPICSHOP_APP_LOCATION?: string | undefined;
|
|
58
62
|
}, {
|
|
59
63
|
EPICSHOP_CONTEXT_CWD?: string | undefined;
|
|
64
|
+
EPICSHOP_WORKSHOP_INSTANCE_ID?: string | undefined;
|
|
60
65
|
NODE_ENV?: "production" | "development" | "test" | undefined;
|
|
61
66
|
EPICSHOP_GITHUB_REPO?: string | undefined;
|
|
62
67
|
EPICSHOP_GITHUB_ROOT?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.server.d.ts","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"env.server.d.ts","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuET,CAAA;AAuBH,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM,CAAC;QAChB,UAAU,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC;SAAG;KACtD;CACD;AAED,wBAAsB,IAAI,kBAazB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM;;;;;;;;;;;;EAgBrB;AAED,KAAK,GAAG,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;AAEpC,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,GAAG,EAAE,GAAG,CAAA;IACZ,UAAU,MAAM;QACf,GAAG,EAAE,GAAG,CAAA;KACR;CACD"}
|
package/dist/esm/env.server.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import md5 from 'md5-hex';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import { handleGitHubRepoAndRoot } from './utils.js';
|
|
6
7
|
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
7
8
|
const schema = z
|
|
8
9
|
.object({
|
|
9
|
-
EPICSHOP_CONTEXT_CWD: z.string().default(
|
|
10
|
+
EPICSHOP_CONTEXT_CWD: z.string().default(''),
|
|
11
|
+
EPICSHOP_WORKSHOP_INSTANCE_ID: z.string().default(''),
|
|
10
12
|
NODE_ENV: z
|
|
11
13
|
.enum(['production', 'development', 'test'])
|
|
12
14
|
.default('development'),
|
|
@@ -28,6 +30,12 @@ const schema = z
|
|
|
28
30
|
SENTRY_PROJECT_ID: z.string().default('4509630082252800'),
|
|
29
31
|
})
|
|
30
32
|
.transform(async (env) => {
|
|
33
|
+
if (env.EPICSHOP_CONTEXT_CWD === '') {
|
|
34
|
+
env.EPICSHOP_CONTEXT_CWD = await getEpicshopContextCwd();
|
|
35
|
+
}
|
|
36
|
+
if (env.EPICSHOP_WORKSHOP_INSTANCE_ID === '') {
|
|
37
|
+
env.EPICSHOP_WORKSHOP_INSTANCE_ID = md5(env.EPICSHOP_CONTEXT_CWD);
|
|
38
|
+
}
|
|
31
39
|
const pkgJsonPath = path.join(env.EPICSHOP_CONTEXT_CWD, 'package.json');
|
|
32
40
|
const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8'));
|
|
33
41
|
const epicshopConfig = pkgJson.epicshop ?? {};
|
|
@@ -53,6 +61,28 @@ const schema = z
|
|
|
53
61
|
}
|
|
54
62
|
return env;
|
|
55
63
|
});
|
|
64
|
+
async function getEpicshopContextCwd() {
|
|
65
|
+
if (process.env.EPICSHOP_CONTEXT_CWD) {
|
|
66
|
+
return process.env.EPICSHOP_CONTEXT_CWD;
|
|
67
|
+
}
|
|
68
|
+
let dir = process.cwd();
|
|
69
|
+
while (true) {
|
|
70
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
71
|
+
try {
|
|
72
|
+
const pkgRaw = await fs.readFile(pkgPath, 'utf8');
|
|
73
|
+
const pkg = JSON.parse(pkgRaw);
|
|
74
|
+
if (pkg.epicshop) {
|
|
75
|
+
return dir;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch { }
|
|
79
|
+
const parentDir = path.dirname(dir);
|
|
80
|
+
if (parentDir === dir)
|
|
81
|
+
break;
|
|
82
|
+
dir = parentDir;
|
|
83
|
+
}
|
|
84
|
+
return process.cwd();
|
|
85
|
+
}
|
|
56
86
|
export async function init() {
|
|
57
87
|
const parsed = await schema.safeParseAsync(process.env);
|
|
58
88
|
if (!parsed.success) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.server.js","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { z } from 'zod'\nimport { handleGitHubRepoAndRoot } from './utils.js'\n\nconst __dirname = path.dirname(new URL(import.meta.url).pathname)\n\nconst schema = z\n\t.object({\n\t\tEPICSHOP_CONTEXT_CWD: z.string().default(process.cwd()),\n\t\tNODE_ENV: z\n\t\t\t.enum(['production', 'development', 'test'] as const)\n\t\t\t.default('development'),\n\t\tEPICSHOP_GITHUB_REPO: z.string().default(''),\n\t\tEPICSHOP_GITHUB_ROOT: z.string().default(''),\n\t\tEPICSHOP_APP_VERSION: z.string().default('0.0.0-unknown'),\n\t\tEPICSHOP_PARENT_PORT: z.string().optional(),\n\t\tEPICSHOP_PARENT_TOKEN: z.string().optional(),\n\t\tEPICSHOP_APP_LOCATION: z.string().optional(),\n\t\tEPICSHOP_IS_PUBLISHED: z\n\t\t\t.string()\n\t\t\t.default(__dirname.includes('node_modules') ? 'true' : 'false'),\n\t\t// Sentry configuration\n\t\tSENTRY_DSN: z\n\t\t\t.string()\n\t\t\t.default(\n\t\t\t\t'https://cd51fbf4ca0834f7b3529a478a8ece4c@o913766.ingest.us.sentry.io/4509630082252800',\n\t\t\t),\n\t\tSENTRY_ORG: z.string().default('kent-c-dodds-tech-llc'),\n\t\tSENTRY_PROJECT: z.string().default('epicshop'),\n\t\tSENTRY_PROJECT_ID: z.string().default('4509630082252800'),\n\t})\n\t.transform(async (env) => {\n\t\tconst pkgJsonPath = path.join(env.EPICSHOP_CONTEXT_CWD, 'package.json')\n\t\tconst pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8')) as {\n\t\t\tepicshop?: {\n\t\t\t\tgithubRepo?: string\n\t\t\t\tgithubRoot?: string\n\t\t\t}\n\t\t}\n\t\tconst epicshopConfig = pkgJson.epicshop ?? {}\n\t\tif (!epicshopConfig) {\n\t\t\tthrow new Error(\n\t\t\t\t`No epicshop configuration found in \"${pkgJsonPath}\". If this is a workshop directory, please add an \"epicshop\" section to your package.json. If this is not a workshop directory, please set the EPICSHOP_CONTEXT_CWD environment variable to the directory containing your package.json with the \"epicshop\" config section.`,\n\t\t\t)\n\t\t}\n\t\tif (env.EPICSHOP_APP_LOCATION === undefined) {\n\t\t\tconst workshopAppPath = import.meta.resolve(\n\t\t\t\t'@epic-web/workshop-app/package.json',\n\t\t\t)\n\t\t\tconst packagePath = fileURLToPath(workshopAppPath)\n\t\t\tenv.EPICSHOP_APP_LOCATION = path.dirname(packagePath)\n\t\t}\n\t\tif (env.EPICSHOP_APP_VERSION === '0.0.0-unknown') {\n\t\t\tconst packageJson = JSON.parse(\n\t\t\t\tawait fs.readFile(\n\t\t\t\t\tpath.join(env.EPICSHOP_APP_LOCATION, 'package.json'),\n\t\t\t\t\t'utf-8',\n\t\t\t\t),\n\t\t\t) as { version: string }\n\t\t\tenv.EPICSHOP_APP_VERSION = packageJson.version\n\t\t}\n\t\tif (!env.EPICSHOP_GITHUB_REPO || !env.EPICSHOP_GITHUB_ROOT) {\n\t\t\tconst { githubRepo, githubRoot } = handleGitHubRepoAndRoot({\n\t\t\t\tgithubRepo: epicshopConfig.githubRepo,\n\t\t\t\tgithubRoot: epicshopConfig.githubRoot,\n\t\t\t})\n\t\t\tenv.EPICSHOP_GITHUB_REPO = githubRepo\n\t\t\tenv.EPICSHOP_GITHUB_ROOT = githubRoot\n\t\t}\n\t\treturn env\n\t})\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv extends z.infer<typeof schema> {}\n\t}\n}\n\nexport async function init() {\n\tconst parsed = await schema.safeParseAsync(process.env)\n\n\tif (!parsed.success) {\n\t\tconsole.error(\n\t\t\t'❌ Invalid environment variables:',\n\t\t\tparsed.error.flatten().fieldErrors,\n\t\t)\n\n\t\tthrow new Error('Invalid environment variables')\n\t}\n\n\tObject.assign(process.env, parsed.data)\n}\n\n/**\n * This is used in both `entry.server.ts` and `root.tsx` to ensure that\n * the environment variables are set and globally available before the app is\n * started.\n *\n * NOTE: Do *not* add any environment variables in here that you do not wish to\n * be included in the client.\n * @returns all public ENV variables\n */\nexport function getEnv() {\n\treturn {\n\t\tMODE: process.env.NODE_ENV,\n\t\tEPICSHOP_CONTEXT_CWD: process.env.EPICSHOP_CONTEXT_CWD,\n\t\tEPICSHOP_GITHUB_REPO: process.env.EPICSHOP_GITHUB_REPO,\n\t\tEPICSHOP_GITHUB_ROOT: process.env.EPICSHOP_GITHUB_ROOT,\n\t\tEPICSHOP_DEPLOYED:\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === 'true' ||\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === '1',\n\t\tEPICSHOP_APP_VERSION: process.env.EPICSHOP_APP_VERSION,\n\t\tEPICSHOP_PARENT_PORT: process.env.EPICSHOP_PARENT_PORT,\n\t\tEPICSHOP_PARENT_TOKEN: process.env.EPICSHOP_PARENT_TOKEN,\n\t\tEPICSHOP_IS_PUBLISHED: process.env.EPICSHOP_IS_PUBLISHED === 'true',\n\t\tSENTRY_DSN: process.env.SENTRY_DSN,\n\t\tSENTRY_PROJECT_ID: process.env.SENTRY_PROJECT_ID,\n\t}\n}\n\ntype ENV = ReturnType<typeof getEnv>\n\ndeclare global {\n\tvar ENV: ENV\n\tinterface Window {\n\t\tENV: ENV\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"env.server.js","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport md5 from 'md5-hex'\nimport { z } from 'zod'\nimport { handleGitHubRepoAndRoot } from './utils.js'\n\nconst __dirname = path.dirname(new URL(import.meta.url).pathname)\n\nconst schema = z\n\t.object({\n\t\tEPICSHOP_CONTEXT_CWD: z.string().default(''),\n\t\tEPICSHOP_WORKSHOP_INSTANCE_ID: z.string().default(''),\n\t\tNODE_ENV: z\n\t\t\t.enum(['production', 'development', 'test'] as const)\n\t\t\t.default('development'),\n\t\tEPICSHOP_GITHUB_REPO: z.string().default(''),\n\t\tEPICSHOP_GITHUB_ROOT: z.string().default(''),\n\t\tEPICSHOP_APP_VERSION: z.string().default('0.0.0-unknown'),\n\t\tEPICSHOP_PARENT_PORT: z.string().optional(),\n\t\tEPICSHOP_PARENT_TOKEN: z.string().optional(),\n\t\tEPICSHOP_APP_LOCATION: z.string().optional(),\n\t\tEPICSHOP_IS_PUBLISHED: z\n\t\t\t.string()\n\t\t\t.default(__dirname.includes('node_modules') ? 'true' : 'false'),\n\t\t// Sentry configuration\n\t\tSENTRY_DSN: z\n\t\t\t.string()\n\t\t\t.default(\n\t\t\t\t'https://cd51fbf4ca0834f7b3529a478a8ece4c@o913766.ingest.us.sentry.io/4509630082252800',\n\t\t\t),\n\t\tSENTRY_ORG: z.string().default('kent-c-dodds-tech-llc'),\n\t\tSENTRY_PROJECT: z.string().default('epicshop'),\n\t\tSENTRY_PROJECT_ID: z.string().default('4509630082252800'),\n\t})\n\t.transform(async (env) => {\n\t\tif (env.EPICSHOP_CONTEXT_CWD === '') {\n\t\t\tenv.EPICSHOP_CONTEXT_CWD = await getEpicshopContextCwd()\n\t\t}\n\t\tif (env.EPICSHOP_WORKSHOP_INSTANCE_ID === '') {\n\t\t\tenv.EPICSHOP_WORKSHOP_INSTANCE_ID = md5(env.EPICSHOP_CONTEXT_CWD)\n\t\t}\n\t\tconst pkgJsonPath = path.join(env.EPICSHOP_CONTEXT_CWD, 'package.json')\n\t\tconst pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8')) as {\n\t\t\tepicshop?: {\n\t\t\t\tgithubRepo?: string\n\t\t\t\tgithubRoot?: string\n\t\t\t}\n\t\t}\n\t\tconst epicshopConfig = pkgJson.epicshop ?? {}\n\t\tif (!epicshopConfig) {\n\t\t\tthrow new Error(\n\t\t\t\t`No epicshop configuration found in \"${pkgJsonPath}\". If this is a workshop directory, please add an \"epicshop\" section to your package.json. If this is not a workshop directory, please set the EPICSHOP_CONTEXT_CWD environment variable to the directory containing your package.json with the \"epicshop\" config section.`,\n\t\t\t)\n\t\t}\n\t\tif (env.EPICSHOP_APP_LOCATION === undefined) {\n\t\t\tconst workshopAppPath = import.meta.resolve(\n\t\t\t\t'@epic-web/workshop-app/package.json',\n\t\t\t)\n\t\t\tconst packagePath = fileURLToPath(workshopAppPath)\n\t\t\tenv.EPICSHOP_APP_LOCATION = path.dirname(packagePath)\n\t\t}\n\t\tif (env.EPICSHOP_APP_VERSION === '0.0.0-unknown') {\n\t\t\tconst packageJson = JSON.parse(\n\t\t\t\tawait fs.readFile(\n\t\t\t\t\tpath.join(env.EPICSHOP_APP_LOCATION, 'package.json'),\n\t\t\t\t\t'utf-8',\n\t\t\t\t),\n\t\t\t) as { version: string }\n\t\t\tenv.EPICSHOP_APP_VERSION = packageJson.version\n\t\t}\n\t\tif (!env.EPICSHOP_GITHUB_REPO || !env.EPICSHOP_GITHUB_ROOT) {\n\t\t\tconst { githubRepo, githubRoot } = handleGitHubRepoAndRoot({\n\t\t\t\tgithubRepo: epicshopConfig.githubRepo,\n\t\t\t\tgithubRoot: epicshopConfig.githubRoot,\n\t\t\t})\n\t\t\tenv.EPICSHOP_GITHUB_REPO = githubRepo\n\t\t\tenv.EPICSHOP_GITHUB_ROOT = githubRoot\n\t\t}\n\t\treturn env\n\t})\n\nasync function getEpicshopContextCwd() {\n\tif (process.env.EPICSHOP_CONTEXT_CWD) {\n\t\treturn process.env.EPICSHOP_CONTEXT_CWD\n\t}\n\tlet dir = process.cwd()\n\twhile (true) {\n\t\tconst pkgPath = path.join(dir, 'package.json')\n\t\ttry {\n\t\t\tconst pkgRaw = await fs.readFile(pkgPath, 'utf8')\n\t\t\tconst pkg = JSON.parse(pkgRaw) as { epicshop?: boolean }\n\t\t\tif (pkg.epicshop) {\n\t\t\t\treturn dir\n\t\t\t}\n\t\t} catch {}\n\t\tconst parentDir = path.dirname(dir)\n\t\tif (parentDir === dir) break\n\t\tdir = parentDir\n\t}\n\treturn process.cwd()\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv extends z.infer<typeof schema> {}\n\t}\n}\n\nexport async function init() {\n\tconst parsed = await schema.safeParseAsync(process.env)\n\n\tif (!parsed.success) {\n\t\tconsole.error(\n\t\t\t'❌ Invalid environment variables:',\n\t\t\tparsed.error.flatten().fieldErrors,\n\t\t)\n\n\t\tthrow new Error('Invalid environment variables')\n\t}\n\n\tObject.assign(process.env, parsed.data)\n}\n\n/**\n * This is used in both `entry.server.ts` and `root.tsx` to ensure that\n * the environment variables are set and globally available before the app is\n * started.\n *\n * NOTE: Do *not* add any environment variables in here that you do not wish to\n * be included in the client.\n * @returns all public ENV variables\n */\nexport function getEnv() {\n\treturn {\n\t\tMODE: process.env.NODE_ENV,\n\t\tEPICSHOP_CONTEXT_CWD: process.env.EPICSHOP_CONTEXT_CWD,\n\t\tEPICSHOP_GITHUB_REPO: process.env.EPICSHOP_GITHUB_REPO,\n\t\tEPICSHOP_GITHUB_ROOT: process.env.EPICSHOP_GITHUB_ROOT,\n\t\tEPICSHOP_DEPLOYED:\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === 'true' ||\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === '1',\n\t\tEPICSHOP_APP_VERSION: process.env.EPICSHOP_APP_VERSION,\n\t\tEPICSHOP_PARENT_PORT: process.env.EPICSHOP_PARENT_PORT,\n\t\tEPICSHOP_PARENT_TOKEN: process.env.EPICSHOP_PARENT_TOKEN,\n\t\tEPICSHOP_IS_PUBLISHED: process.env.EPICSHOP_IS_PUBLISHED === 'true',\n\t\tSENTRY_DSN: process.env.SENTRY_DSN,\n\t\tSENTRY_PROJECT_ID: process.env.SENTRY_PROJECT_ID,\n\t}\n}\n\ntype ENV = ReturnType<typeof getEnv>\n\ndeclare global {\n\tvar ENV: ENV\n\tinterface Window {\n\t\tENV: ENV\n\t}\n}\n"]}
|
|
@@ -126,21 +126,21 @@ declare const UserInfoSchema: z.ZodEffects<z.ZodObject<{
|
|
|
126
126
|
global_name?: string | null | undefined;
|
|
127
127
|
}>;
|
|
128
128
|
}, "strip", z.ZodTypeAny, {
|
|
129
|
-
nick: string | null;
|
|
130
129
|
user: {
|
|
131
130
|
id: string;
|
|
132
131
|
username: string;
|
|
133
132
|
avatar?: string | null | undefined;
|
|
134
133
|
global_name?: string | null | undefined;
|
|
135
134
|
};
|
|
136
|
-
}, {
|
|
137
135
|
nick: string | null;
|
|
136
|
+
}, {
|
|
138
137
|
user: {
|
|
139
138
|
id: string;
|
|
140
139
|
username: string;
|
|
141
140
|
avatar?: string | null | undefined;
|
|
142
141
|
global_name?: string | null | undefined;
|
|
143
142
|
};
|
|
143
|
+
nick: string | null;
|
|
144
144
|
}>>>;
|
|
145
145
|
}, "strip", z.ZodTypeAny, {
|
|
146
146
|
name: string | null;
|
|
@@ -148,13 +148,13 @@ declare const UserInfoSchema: z.ZodEffects<z.ZodObject<{
|
|
|
148
148
|
email: string;
|
|
149
149
|
image: string | null;
|
|
150
150
|
discordProfile?: {
|
|
151
|
-
nick: string | null;
|
|
152
151
|
user: {
|
|
153
152
|
id: string;
|
|
154
153
|
username: string;
|
|
155
154
|
avatar?: string | null | undefined;
|
|
156
155
|
global_name?: string | null | undefined;
|
|
157
156
|
};
|
|
157
|
+
nick: string | null;
|
|
158
158
|
} | null | undefined;
|
|
159
159
|
}, {
|
|
160
160
|
name: string | null;
|
|
@@ -162,13 +162,13 @@ declare const UserInfoSchema: z.ZodEffects<z.ZodObject<{
|
|
|
162
162
|
email: string;
|
|
163
163
|
image: string | null;
|
|
164
164
|
discordProfile?: {
|
|
165
|
-
nick: string | null;
|
|
166
165
|
user: {
|
|
167
166
|
id: string;
|
|
168
167
|
username: string;
|
|
169
168
|
avatar?: string | null | undefined;
|
|
170
169
|
global_name?: string | null | undefined;
|
|
171
170
|
};
|
|
171
|
+
nick: string | null;
|
|
172
172
|
} | null | undefined;
|
|
173
173
|
}>, {
|
|
174
174
|
imageUrlSmall: string | null;
|
|
@@ -178,13 +178,13 @@ declare const UserInfoSchema: z.ZodEffects<z.ZodObject<{
|
|
|
178
178
|
email: string;
|
|
179
179
|
image: string | null;
|
|
180
180
|
discordProfile?: {
|
|
181
|
-
nick: string | null;
|
|
182
181
|
user: {
|
|
183
182
|
id: string;
|
|
184
183
|
username: string;
|
|
185
184
|
avatar?: string | null | undefined;
|
|
186
185
|
global_name?: string | null | undefined;
|
|
187
186
|
};
|
|
187
|
+
nick: string | null;
|
|
188
188
|
} | null | undefined;
|
|
189
189
|
}, {
|
|
190
190
|
name: string | null;
|
|
@@ -192,13 +192,13 @@ declare const UserInfoSchema: z.ZodEffects<z.ZodObject<{
|
|
|
192
192
|
email: string;
|
|
193
193
|
image: string | null;
|
|
194
194
|
discordProfile?: {
|
|
195
|
-
nick: string | null;
|
|
196
195
|
user: {
|
|
197
196
|
id: string;
|
|
198
197
|
username: string;
|
|
199
198
|
avatar?: string | null | undefined;
|
|
200
199
|
global_name?: string | null | undefined;
|
|
201
200
|
};
|
|
201
|
+
nick: string | null;
|
|
202
202
|
} | null | undefined;
|
|
203
203
|
}>;
|
|
204
204
|
export type UserInfo = z.infer<typeof UserInfoSchema>;
|
|
@@ -214,13 +214,13 @@ export declare function getUserInfo({ timings, request, forceFresh, }?: {
|
|
|
214
214
|
email: string;
|
|
215
215
|
image: string | null;
|
|
216
216
|
discordProfile?: {
|
|
217
|
-
nick: string | null;
|
|
218
217
|
user: {
|
|
219
218
|
id: string;
|
|
220
219
|
username: string;
|
|
221
220
|
avatar?: string | null | undefined;
|
|
222
221
|
global_name?: string | null | undefined;
|
|
223
222
|
};
|
|
223
|
+
nick: string | null;
|
|
224
224
|
} | null | undefined;
|
|
225
225
|
} | null>;
|
|
226
226
|
export {};
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@epic-web/workshop-utils","version":"6.
|
|
1
|
+
{"name":"@epic-web/workshop-utils","version":"6.15.1","publishConfig":{"access":"public"},"type":"module","tshy":{"project":"./tsconfig.build.json","dialects":["esm"],"exports":{"./package.json":"./package.json","./apps.server":"./src/apps.server.ts","./diff.server":"./src/diff.server.ts","./env.server":"./src/env.server.ts","./epic-api.server":"./src/epic-api.server.ts","./user.server":"./src/user.server.ts","./cache.server":"./src/cache.server.ts","./config.server":"./src/config.server.ts","./db.server":"./src/db.server.ts","./timing.server":"./src/timing.server.ts","./modified-time.server":"./src/modified-time.server.ts","./compile-mdx.server":"./src/compile-mdx.server.ts","./git.server":"./src/git.server.ts","./iframe-sync":"./src/iframe-sync.ts","./playwright.server":"./src/playwright.server.ts","./notifications.server":"./src/notifications.server.ts","./process-manager.server":"./src/process-manager.server.ts","./test":"./src/test.ts","./request-context.server":"./src/request-context.server.ts","./utils.server":"./src/utils.server.ts","./utils":"./src/utils.ts"}},"exports":{"./package.json":"./package.json","./apps.server":{"import":{"types":"./dist/esm/apps.server.d.ts","default":"./dist/esm/apps.server.js"}},"./diff.server":{"import":{"types":"./dist/esm/diff.server.d.ts","default":"./dist/esm/diff.server.js"}},"./env.server":{"import":{"types":"./dist/esm/env.server.d.ts","default":"./dist/esm/env.server.js"}},"./epic-api.server":{"import":{"types":"./dist/esm/epic-api.server.d.ts","default":"./dist/esm/epic-api.server.js"}},"./user.server":{"import":{"types":"./dist/esm/user.server.d.ts","default":"./dist/esm/user.server.js"}},"./cache.server":{"import":{"types":"./dist/esm/cache.server.d.ts","default":"./dist/esm/cache.server.js"}},"./config.server":{"import":{"types":"./dist/esm/config.server.d.ts","default":"./dist/esm/config.server.js"}},"./db.server":{"import":{"types":"./dist/esm/db.server.d.ts","default":"./dist/esm/db.server.js"}},"./timing.server":{"import":{"types":"./dist/esm/timing.server.d.ts","default":"./dist/esm/timing.server.js"}},"./modified-time.server":{"import":{"types":"./dist/esm/modified-time.server.d.ts","default":"./dist/esm/modified-time.server.js"}},"./compile-mdx.server":{"import":{"types":"./dist/esm/compile-mdx.server.d.ts","default":"./dist/esm/compile-mdx.server.js"}},"./git.server":{"import":{"types":"./dist/esm/git.server.d.ts","default":"./dist/esm/git.server.js"}},"./iframe-sync":{"import":{"types":"./dist/esm/iframe-sync.d.ts","default":"./dist/esm/iframe-sync.js"}},"./playwright.server":{"import":{"types":"./dist/esm/playwright.server.d.ts","default":"./dist/esm/playwright.server.js"}},"./notifications.server":{"import":{"types":"./dist/esm/notifications.server.d.ts","default":"./dist/esm/notifications.server.js"}},"./process-manager.server":{"import":{"types":"./dist/esm/process-manager.server.d.ts","default":"./dist/esm/process-manager.server.js"}},"./test":{"import":{"types":"./dist/esm/test.d.ts","default":"./dist/esm/test.js"}},"./request-context.server":{"import":{"types":"./dist/esm/request-context.server.d.ts","default":"./dist/esm/request-context.server.js"}},"./utils.server":{"import":{"types":"./dist/esm/utils.server.d.ts","default":"./dist/esm/utils.server.js"}},"./utils":{"import":{"types":"./dist/esm/utils.d.ts","default":"./dist/esm/utils.js"}}},"files":["dist"],"scripts":{"typecheck":"tsc --noEmit","build":"tshy","build:watch":"nx watch --projects=@epic-web/workshop-utils -- nx run \\$NX_PROJECT_NAME:build"},"dependencies":{"@epic-web/cachified":"^5.6.0","@epic-web/invariant":"^1.0.0","@epic-web/remember":"^1.1.0","@kentcdodds/md-temp":"^10.0.1","@mdx-js/mdx":"^3.1.0","@paralleldrive/cuid2":"^2.2.2","@playwright/test":"^1.53.2","@react-router/node":"^7.6.3","@sentry/react-router":"^9.40.0","@testing-library/dom":"^10.4.0","@testing-library/jest-dom":"^6.6.3","@total-typescript/ts-reset":"^0.6.1","@types/chai":"^5.2.2","@types/chai-dom":"^1.11.3","@vitest/expect":"^3.2.4","chai":"^5.2.0","chai-dom":"^1.12.1","chalk":"^5.4.1","chokidar":"^4.0.3","close-with-grace":"^2.2.0","cookie":"^1.0.2","cross-spawn":"^7.0.6","dayjs":"^1.11.13","esbuild":"^0.25.5","execa":"^9.6.0","find-process":"^1.4.10","fkill":"^9.0.0","fs-extra":"^11.3.0","globby":"^14.1.0","ignore":"^7.0.5","json5":"^2.2.3","lru-cache":"^11.1.0","lz-string":"^1.5.0","md5-hex":"^5.0.0","mdast-util-mdx-jsx":"^3.2.0","mdx-bundler":"^10.1.1","p-queue":"^8.1.0","parse-git-diff":"^0.0.19","rehype":"^13.0.2","rehype-autolink-headings":"^7.1.0","remark":"^15.0.1","remark-emoji":"^5.0.1","remark-gfm":"^4.0.1","shiki":"^3.7.0","unified":"^11.0.5","unist-util-remove-position":"^5.0.0","unist-util-visit":"^5.0.0","zod":"^3.25.71"},"devDependencies":{"@types/hast":"^3.0.4","@types/mdast":"^4.0.4","@types/node":"^24.0.10","tshy":"^3.0.2"},"repository":{"type":"git","url":"https://github.com/epicweb-dev/epicshop.git","directory":"packages/workshop-utils"}}
|