create-mercato-app 0.6.1-develop.3291.1.6fad645fd0 โ 0.6.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-mercato-app",
|
|
3
|
-
"version": "0.6.1
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Create a new Open Mercato application",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -41,6 +41,5 @@
|
|
|
41
41
|
"scaffolding",
|
|
42
42
|
"cli"
|
|
43
43
|
],
|
|
44
|
-
"license": "MIT"
|
|
45
|
-
"stableVersion": "0.6.0"
|
|
44
|
+
"license": "MIT"
|
|
46
45
|
}
|
|
@@ -76,6 +76,10 @@ export function isIgnorableBootstrapNoiseLine(line) {
|
|
|
76
76
|
return normalized.startsWith('[Bootstrap] Entity IDs re-registered')
|
|
77
77
|
|| normalized.startsWith('๐ Starting scheduler')
|
|
78
78
|
|| normalized.startsWith('โ Local scheduler started')
|
|
79
|
+
|| normalized.startsWith('[lazy-scheduler] Watching for enabled schedules')
|
|
80
|
+
|| normalized.startsWith('[lazy-scheduler] Schedule probe failed')
|
|
81
|
+
|| normalized.startsWith('[lazy-scheduler] Poll cycle failed')
|
|
82
|
+
|| normalized.startsWith('[lazy-scheduler] Initial poll failed')
|
|
79
83
|
|| normalized.startsWith('๐ก Tip:')
|
|
80
84
|
}
|
|
81
85
|
|
|
@@ -42,6 +42,27 @@ function isEnabledEnvFlag(value) {
|
|
|
42
42
|
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase())
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
function parseEnvBooleanToken(value) {
|
|
46
|
+
if (typeof value !== 'string') return null
|
|
47
|
+
const normalized = value.trim().toLowerCase()
|
|
48
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true
|
|
49
|
+
if (['0', 'false', 'no', 'off'].includes(normalized)) return false
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function resolveAutoSpawnEnabled(env, legacyName, aliasedName) {
|
|
54
|
+
const legacy = parseEnvBooleanToken(env[legacyName])
|
|
55
|
+
if (legacy !== null) return legacy
|
|
56
|
+
const aliased = parseEnvBooleanToken(env[aliasedName])
|
|
57
|
+
if (aliased !== null) return aliased
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveAutoSpawnMode(env, legacyName, aliasedName, lazyName) {
|
|
62
|
+
if (!resolveAutoSpawnEnabled(env, legacyName, aliasedName)) return 'off'
|
|
63
|
+
return parseEnvBooleanToken(env[lazyName]) === true ? 'lazy' : 'eager'
|
|
64
|
+
}
|
|
65
|
+
|
|
45
66
|
const {
|
|
46
67
|
clampPercent,
|
|
47
68
|
connectLineStream,
|
|
@@ -83,6 +104,10 @@ const CYAN_BORDER = '\u001B[46m\u001B[30m'
|
|
|
83
104
|
const ERROR_BANNER = '\u001B[41m\u001B[97m'
|
|
84
105
|
const warmupRequestTimeoutsMs = [45000, 120000]
|
|
85
106
|
const maxWarmupRetryAttempts = 3
|
|
107
|
+
const backgroundServiceModes = {
|
|
108
|
+
workers: resolveAutoSpawnMode(process.env, 'AUTO_SPAWN_WORKERS', 'OM_AUTO_SPAWN_WORKERS', 'OM_AUTO_SPAWN_WORKERS_LAZY'),
|
|
109
|
+
scheduler: resolveAutoSpawnMode(process.env, 'AUTO_SPAWN_SCHEDULER', 'OM_AUTO_SPAWN_SCHEDULER', 'OM_AUTO_SPAWN_SCHEDULER_LAZY'),
|
|
110
|
+
}
|
|
86
111
|
const splashState = {
|
|
87
112
|
mode: splashMode,
|
|
88
113
|
phase: startupSplashPhase,
|
|
@@ -98,6 +123,8 @@ const splashState = {
|
|
|
98
123
|
packageNames: [],
|
|
99
124
|
workerQueues: [],
|
|
100
125
|
schedulerActive: false,
|
|
126
|
+
workerMode: backgroundServiceModes.workers,
|
|
127
|
+
schedulerMode: backgroundServiceModes.scheduler,
|
|
101
128
|
progressCurrent: runtimeProgressCurrent,
|
|
102
129
|
progressTotal: runtimeProgressTotal,
|
|
103
130
|
progressPercent: 0,
|
|
@@ -120,6 +147,8 @@ const runtimeSummaryState = {
|
|
|
120
147
|
packageNames: [],
|
|
121
148
|
workerQueues: [],
|
|
122
149
|
schedulerActive: false,
|
|
150
|
+
workerMode: backgroundServiceModes.workers,
|
|
151
|
+
schedulerMode: backgroundServiceModes.scheduler,
|
|
123
152
|
packagesPrinted: false,
|
|
124
153
|
workersPrinted: false,
|
|
125
154
|
lastWorkersSignature: '',
|
|
@@ -145,6 +174,22 @@ function printCompactSummary(icon, title, lines) {
|
|
|
145
174
|
}
|
|
146
175
|
}
|
|
147
176
|
|
|
177
|
+
function formatBackgroundServiceMode(modes = runtimeSummaryState) {
|
|
178
|
+
const activeModes = []
|
|
179
|
+
if (modes.workerMode !== 'off') activeModes.push(['workers', modes.workerMode])
|
|
180
|
+
if (modes.schedulerMode !== 'off') activeModes.push(['scheduler', modes.schedulerMode])
|
|
181
|
+
if (activeModes.length === 0) return 'off'
|
|
182
|
+
|
|
183
|
+
const uniqueModes = new Set(activeModes.map(([, mode]) => mode))
|
|
184
|
+
if (uniqueModes.size === 1) return activeModes[0][1]
|
|
185
|
+
|
|
186
|
+
return activeModes.map(([service, mode]) => `${service} ${mode}`).join(', ')
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function formatBackgroundServiceStatus(action = 'Starting background services', modes = runtimeSummaryState) {
|
|
190
|
+
return `${action} (${formatBackgroundServiceMode(modes)})`
|
|
191
|
+
}
|
|
192
|
+
|
|
148
193
|
function loadRuntimePackageNames() {
|
|
149
194
|
const pkg = readJsonFile(path.join(process.cwd(), 'package.json'))
|
|
150
195
|
if (!pkg || typeof pkg !== 'object') return []
|
|
@@ -168,6 +213,8 @@ function updateRuntimeSummaryState() {
|
|
|
168
213
|
packageNames: runtimeSummaryState.packageNames,
|
|
169
214
|
workerQueues: runtimeSummaryState.workerQueues,
|
|
170
215
|
schedulerActive: runtimeSummaryState.schedulerActive,
|
|
216
|
+
workerMode: runtimeSummaryState.workerMode,
|
|
217
|
+
schedulerMode: runtimeSummaryState.schedulerMode,
|
|
171
218
|
})
|
|
172
219
|
}
|
|
173
220
|
|
|
@@ -193,6 +240,8 @@ function printBackgroundServicesSummary() {
|
|
|
193
240
|
|
|
194
241
|
const signature = JSON.stringify({
|
|
195
242
|
schedulerActive: runtimeSummaryState.schedulerActive,
|
|
243
|
+
workerMode: runtimeSummaryState.workerMode,
|
|
244
|
+
schedulerMode: runtimeSummaryState.schedulerMode,
|
|
196
245
|
workerQueues: runtimeSummaryState.workerQueues,
|
|
197
246
|
})
|
|
198
247
|
|
|
@@ -204,7 +253,7 @@ function printBackgroundServicesSummary() {
|
|
|
204
253
|
runtimeSummaryState.workersPrinted = true
|
|
205
254
|
printCompactSummary(
|
|
206
255
|
'โ๏ธ',
|
|
207
|
-
`Background services (${detailItems.length})`,
|
|
256
|
+
`Background services (${formatBackgroundServiceMode()}, ${detailItems.length} active)`,
|
|
208
257
|
detailItems.map((item, index) => `${index === 0 ? '๐' : '๐งต'} ${item}`),
|
|
209
258
|
)
|
|
210
259
|
}
|
|
@@ -215,6 +264,32 @@ function initializeRuntimeSummary() {
|
|
|
215
264
|
}
|
|
216
265
|
|
|
217
266
|
function captureBackgroundServiceLine(line) {
|
|
267
|
+
if (
|
|
268
|
+
line.startsWith('[server] Lazy worker auto-spawn enabled')
|
|
269
|
+
|| line.startsWith('[lazy-supervisor] Watching')
|
|
270
|
+
|| line.startsWith('[lazy-supervisor] Pending job detected')
|
|
271
|
+
) {
|
|
272
|
+
runtimeSummaryState.workerMode = 'lazy'
|
|
273
|
+
updateRuntimeSummaryState()
|
|
274
|
+
return true
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (
|
|
278
|
+
line === '[server] Starting workers for all queues...'
|
|
279
|
+
|| line === '[server] Eager worker auto-spawn enabled - starting workers for all queues...'
|
|
280
|
+
|| line.startsWith('๐ Running queue:worker')
|
|
281
|
+
) {
|
|
282
|
+
runtimeSummaryState.workerMode = 'eager'
|
|
283
|
+
updateRuntimeSummaryState()
|
|
284
|
+
return true
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (line.startsWith('[server] Lazy scheduler auto-spawn enabled')) {
|
|
288
|
+
runtimeSummaryState.schedulerMode = 'lazy'
|
|
289
|
+
updateRuntimeSummaryState()
|
|
290
|
+
return true
|
|
291
|
+
}
|
|
292
|
+
|
|
218
293
|
const queuesMatch = line.match(/^\[worker\] Starting workers for all queues: (.+)$/)
|
|
219
294
|
if (queuesMatch) {
|
|
220
295
|
const queueNames = queuesMatch[1].split(',').map((item) => item.trim()).filter(Boolean)
|
|
@@ -241,7 +316,24 @@ function captureBackgroundServiceLine(line) {
|
|
|
241
316
|
return true
|
|
242
317
|
}
|
|
243
318
|
|
|
244
|
-
if (
|
|
319
|
+
if (
|
|
320
|
+
line === '[server] Starting scheduler polling engine...'
|
|
321
|
+
|| line === '[server] Eager scheduler auto-spawn enabled - starting scheduler polling engine...'
|
|
322
|
+
|| line.startsWith('๐ Running scheduler:start')
|
|
323
|
+
) {
|
|
324
|
+
runtimeSummaryState.schedulerMode = 'eager'
|
|
325
|
+
runtimeSummaryState.schedulerActive = true
|
|
326
|
+
updateRuntimeSummaryState()
|
|
327
|
+
return true
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (
|
|
331
|
+
line === '[lazy-scheduler] Enabled schedule detected - starting scheduler polling engine.'
|
|
332
|
+
|| line.startsWith('โ Local scheduler started')
|
|
333
|
+
) {
|
|
334
|
+
if (line === '[lazy-scheduler] Enabled schedule detected - starting scheduler polling engine.') {
|
|
335
|
+
runtimeSummaryState.schedulerMode = 'lazy'
|
|
336
|
+
}
|
|
245
337
|
runtimeSummaryState.schedulerActive = true
|
|
246
338
|
updateRuntimeSummaryState()
|
|
247
339
|
return true
|
|
@@ -315,6 +407,8 @@ function updateSplashState(patch) {
|
|
|
315
407
|
if (Array.isArray(patch.packageNames)) splashState.packageNames = patch.packageNames
|
|
316
408
|
if (Array.isArray(patch.workerQueues)) splashState.workerQueues = patch.workerQueues
|
|
317
409
|
if (typeof patch.schedulerActive === 'boolean') splashState.schedulerActive = patch.schedulerActive
|
|
410
|
+
if (typeof patch.workerMode === 'string') splashState.workerMode = patch.workerMode
|
|
411
|
+
if (typeof patch.schedulerMode === 'string') splashState.schedulerMode = patch.schedulerMode
|
|
318
412
|
if (typeof patch.progressCurrent === 'number') splashState.progressCurrent = patch.progressCurrent
|
|
319
413
|
if (typeof patch.progressTotal === 'number') splashState.progressTotal = patch.progressTotal
|
|
320
414
|
if (typeof patch.progressPercent === 'number') splashState.progressPercent = clampPercent(patch.progressPercent)
|
|
@@ -1377,18 +1471,63 @@ function classifyServerLine(line) {
|
|
|
1377
1471
|
}
|
|
1378
1472
|
if (
|
|
1379
1473
|
line === '[server] Starting workers for all queues...'
|
|
1474
|
+
|| line === '[server] Eager worker auto-spawn enabled - starting workers for all queues...'
|
|
1380
1475
|
|| line === '[server] Starting scheduler polling engine...'
|
|
1476
|
+
|| line === '[server] Eager scheduler auto-spawn enabled - starting scheduler polling engine...'
|
|
1477
|
+
|| line === '[lazy-scheduler] Enabled schedule detected - starting scheduler polling engine.'
|
|
1381
1478
|
|| line.startsWith('๐ Running queue:worker')
|
|
1382
1479
|
|| line.startsWith('๐ Running scheduler:start')
|
|
1383
1480
|
) {
|
|
1481
|
+
const isLazyTrigger = line === '[lazy-scheduler] Enabled schedule detected - starting scheduler polling engine.'
|
|
1482
|
+
const modes = isLazyTrigger
|
|
1483
|
+
? { workerMode: runtimeSummaryState.workerMode, schedulerMode: 'lazy' }
|
|
1484
|
+
: runtimeSummaryState
|
|
1485
|
+
const status = formatBackgroundServiceStatus('Starting background services', modes)
|
|
1486
|
+
return {
|
|
1487
|
+
type: 'status',
|
|
1488
|
+
message: `โ๏ธ ${status}`,
|
|
1489
|
+
splashPhase: startupSplashPhase,
|
|
1490
|
+
splashDetail: status,
|
|
1491
|
+
activity: status,
|
|
1492
|
+
progressCurrent: 3,
|
|
1493
|
+
progressLabel: status,
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
if (line.startsWith('[server] Lazy worker auto-spawn enabled')) {
|
|
1497
|
+
const status = 'Background workers armed (lazy)'
|
|
1498
|
+
return {
|
|
1499
|
+
type: 'status',
|
|
1500
|
+
message: `โ๏ธ ${status}`,
|
|
1501
|
+
splashPhase: startupSplashPhase,
|
|
1502
|
+
splashDetail: status,
|
|
1503
|
+
activity: status,
|
|
1504
|
+
progressCurrent: 3,
|
|
1505
|
+
progressLabel: 'Background services (lazy)',
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
if (line.startsWith('[server] Lazy scheduler auto-spawn enabled')) {
|
|
1509
|
+
const status = 'Scheduler armed (lazy)'
|
|
1510
|
+
return {
|
|
1511
|
+
type: 'status',
|
|
1512
|
+
message: `โ๏ธ ${status}`,
|
|
1513
|
+
splashPhase: startupSplashPhase,
|
|
1514
|
+
splashDetail: status,
|
|
1515
|
+
activity: status,
|
|
1516
|
+
progressCurrent: 3,
|
|
1517
|
+
progressLabel: 'Background services (lazy)',
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
const lazyWorkerStartMatch = line.match(/^\[lazy-supervisor\] Pending job detected .+ starting worker for queue "(.+)"$/)
|
|
1521
|
+
if (lazyWorkerStartMatch) {
|
|
1522
|
+
const status = `Starting worker "${lazyWorkerStartMatch[1]}" (lazy)`
|
|
1384
1523
|
return {
|
|
1385
1524
|
type: 'status',
|
|
1386
|
-
message:
|
|
1525
|
+
message: `โ๏ธ ${status}`,
|
|
1387
1526
|
splashPhase: startupSplashPhase,
|
|
1388
|
-
splashDetail:
|
|
1389
|
-
activity:
|
|
1527
|
+
splashDetail: status,
|
|
1528
|
+
activity: status,
|
|
1390
1529
|
progressCurrent: 3,
|
|
1391
|
-
progressLabel: '
|
|
1530
|
+
progressLabel: 'Background services (lazy)',
|
|
1392
1531
|
}
|
|
1393
1532
|
}
|
|
1394
1533
|
|
package/template/scripts/dev.mjs
CHANGED
|
@@ -509,6 +509,27 @@ function buildSplashChildEnv() {
|
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
+
function applyLocalDevBackgroundServiceDefaults(childEnv) {
|
|
513
|
+
const env = childEnv ?? {}
|
|
514
|
+
if (
|
|
515
|
+
typeof process.env.OM_AUTO_SPAWN_WORKERS_LAZY !== 'string'
|
|
516
|
+
|| process.env.OM_AUTO_SPAWN_WORKERS_LAZY.trim() === ''
|
|
517
|
+
) {
|
|
518
|
+
env.OM_AUTO_SPAWN_WORKERS_LAZY = 'true'
|
|
519
|
+
}
|
|
520
|
+
if (
|
|
521
|
+
typeof process.env.OM_AUTO_SPAWN_SCHEDULER_LAZY !== 'string'
|
|
522
|
+
|| process.env.OM_AUTO_SPAWN_SCHEDULER_LAZY.trim() === ''
|
|
523
|
+
) {
|
|
524
|
+
env.OM_AUTO_SPAWN_SCHEDULER_LAZY = 'true'
|
|
525
|
+
}
|
|
526
|
+
return env
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function buildAppDevEnv() {
|
|
530
|
+
return applyLocalDevBackgroundServiceDefaults(buildSplashChildEnv() ?? {})
|
|
531
|
+
}
|
|
532
|
+
|
|
512
533
|
function launchStandaloneDev(options = {}) {
|
|
513
534
|
if (!fs.existsSync(standaloneRuntimeScript)) {
|
|
514
535
|
console.error(`โ Standalone dev runtime not found at ${standaloneRuntimeScript}`)
|
|
@@ -543,7 +564,7 @@ function launchStandaloneDev(options = {}) {
|
|
|
543
564
|
|
|
544
565
|
const app = spawnCommand(process.execPath, runtimeArgs, {
|
|
545
566
|
stdio: 'inherit',
|
|
546
|
-
env:
|
|
567
|
+
env: buildAppDevEnv(),
|
|
547
568
|
})
|
|
548
569
|
|
|
549
570
|
app.on('close', (code) => {
|
|
@@ -1590,7 +1611,7 @@ function launchMonorepoAppDev() {
|
|
|
1590
1611
|
})
|
|
1591
1612
|
const app = spawnCommand(yarnCommand, appArgs, {
|
|
1592
1613
|
stdio: 'inherit',
|
|
1593
|
-
env:
|
|
1614
|
+
env: buildAppDevEnv(),
|
|
1594
1615
|
})
|
|
1595
1616
|
|
|
1596
1617
|
app.on('close', (code, signal) => {
|
|
@@ -5,17 +5,49 @@
|
|
|
5
5
|
// duplication is deliberate. Keep both copies in sync when editing; CI
|
|
6
6
|
// runs `yarn template:sync` to enforce parity.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const localDevHostAliases = ['localhost', '127.0.0.1', '[::1]', '0.0.0.0', 'host.docker.internal'] as const
|
|
9
|
+
const localDevHosts = new Set<string>([...localDevHostAliases, '::1'])
|
|
10
|
+
|
|
11
|
+
function normalizeHostname(hostname: string): string {
|
|
12
|
+
const normalized = hostname.trim().toLowerCase()
|
|
13
|
+
return normalized === '::1' ? '[::1]' : normalized
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isLocalDevHost(hostname: string): boolean {
|
|
17
|
+
return localDevHosts.has(hostname)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isAllowedBareHostname(hostname: string): boolean {
|
|
21
|
+
return isLocalDevHost(hostname) || hostname.includes('.') || hostname.startsWith('*.') || hostname.startsWith('**.')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readUrlOriginHostname(raw: string | undefined): string | null {
|
|
9
25
|
const value = raw?.trim()
|
|
10
26
|
if (!value) return null
|
|
11
27
|
|
|
12
28
|
try {
|
|
13
|
-
return new URL(value).hostname
|
|
29
|
+
return normalizeHostname(new URL(value).hostname)
|
|
14
30
|
} catch {
|
|
15
31
|
return null
|
|
16
32
|
}
|
|
17
33
|
}
|
|
18
34
|
|
|
35
|
+
function readAllowedOriginHostname(raw: string | undefined): string | null {
|
|
36
|
+
const value = raw?.trim()
|
|
37
|
+
if (!value || /\s/.test(value)) return null
|
|
38
|
+
|
|
39
|
+
const urlHostname = readUrlOriginHostname(value)
|
|
40
|
+
if (urlHostname) return urlHostname
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const hostname = normalizeHostname(new URL(`http://${value}`).hostname)
|
|
44
|
+
return isAllowedBareHostname(hostname) ? hostname : null
|
|
45
|
+
} catch {
|
|
46
|
+
const hostname = normalizeHostname(value)
|
|
47
|
+
return isAllowedBareHostname(hostname) ? hostname : null
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
19
51
|
function readCsv(value: string | undefined): string[] {
|
|
20
52
|
return (value ?? '')
|
|
21
53
|
.split(',')
|
|
@@ -23,13 +55,31 @@ function readCsv(value: string | undefined): string[] {
|
|
|
23
55
|
.filter((item) => item.length > 0)
|
|
24
56
|
}
|
|
25
57
|
|
|
58
|
+
function addOriginHostname(origins: Set<string>, hostname: string): void {
|
|
59
|
+
const normalized = normalizeHostname(hostname)
|
|
60
|
+
origins.add(normalized)
|
|
61
|
+
|
|
62
|
+
if (isLocalDevHost(normalized)) {
|
|
63
|
+
for (const alias of localDevHostAliases) {
|
|
64
|
+
origins.add(alias)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
26
69
|
export function resolveAllowedDevOrigins(env: NodeJS.ProcessEnv = process.env): string[] {
|
|
27
70
|
const origins = new Set<string>()
|
|
28
71
|
|
|
29
|
-
for (const raw of [env.APP_URL, env.NEXT_PUBLIC_APP_URL
|
|
30
|
-
const hostname =
|
|
72
|
+
for (const raw of [env.APP_URL, env.NEXT_PUBLIC_APP_URL]) {
|
|
73
|
+
const hostname = readUrlOriginHostname(raw)
|
|
74
|
+
if (hostname) {
|
|
75
|
+
addOriginHostname(origins, hostname)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (const raw of readCsv(env.APP_ALLOWED_ORIGINS)) {
|
|
80
|
+
const hostname = readAllowedOriginHostname(raw)
|
|
31
81
|
if (hostname) {
|
|
32
|
-
origins
|
|
82
|
+
addOriginHostname(origins, hostname)
|
|
33
83
|
}
|
|
34
84
|
}
|
|
35
85
|
|