neo.mjs 11.2.0 → 11.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
- "lastSync": "2025-11-13T13:00:00.077Z",
3
- "releasesLastFetched": "2025-11-13T13:00:00.085Z",
2
+ "lastSync": "2025-11-14T15:18:33.969Z",
3
+ "releasesLastFetched": "2025-11-14T15:18:33.979Z",
4
4
  "pushFailures": [],
5
5
  "issues": {
6
6
  "3789": {
@@ -3617,7 +3617,7 @@
3617
3617
  },
3618
3618
  "7304": {
3619
3619
  "state": "CLOSED",
3620
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7304.md",
3620
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7304.md",
3621
3621
  "closedAt": "2025-11-12T11:53:00Z",
3622
3622
  "updatedAt": "2025-11-12T11:53:00Z",
3623
3623
  "contentHash": "05f00d7410005fca52997dbb8bd707808c490e5d5a49f2f4fbf554284eb01e4f"
@@ -4331,7 +4331,7 @@
4331
4331
  },
4332
4332
  "7447": {
4333
4333
  "state": "CLOSED",
4334
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7447.md",
4334
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7447.md",
4335
4335
  "closedAt": "2025-11-12T13:57:32Z",
4336
4336
  "updatedAt": "2025-11-12T13:57:32Z",
4337
4337
  "contentHash": "98d159a41e22c79c28779b7d601cd03166d8e2142f5281dbc6580094c04376b5"
@@ -5619,7 +5619,7 @@
5619
5619
  },
5620
5620
  "7650": {
5621
5621
  "state": "CLOSED",
5622
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7650.md",
5622
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7650.md",
5623
5623
  "closedAt": "2025-11-13T11:52:40Z",
5624
5624
  "updatedAt": "2025-11-13T11:55:57Z",
5625
5625
  "contentHash": "b71d8302ec3201b6efc5c1108d404f70a4c42056433fb7ebb2f3e943441414b9"
@@ -6235,28 +6235,28 @@
6235
6235
  },
6236
6236
  "7749": {
6237
6237
  "state": "CLOSED",
6238
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7749.md",
6238
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7749.md",
6239
6239
  "closedAt": "2025-11-12T14:23:01Z",
6240
6240
  "updatedAt": "2025-11-12T14:23:01Z",
6241
6241
  "contentHash": "d5cc4155dc32e52669f21a2464f96e1289fb20aa13486bda0ea89b84a279d855"
6242
6242
  },
6243
6243
  "7750": {
6244
6244
  "state": "CLOSED",
6245
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7750.md",
6245
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7750.md",
6246
6246
  "closedAt": "2025-11-12T14:27:19Z",
6247
6247
  "updatedAt": "2025-11-12T14:27:19Z",
6248
6248
  "contentHash": "61d61d64ad2c541baa15b10af96e2209318a7acbdb4329b63d41a52ce3841e48"
6249
6249
  },
6250
6250
  "7751": {
6251
6251
  "state": "CLOSED",
6252
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7751.md",
6252
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7751.md",
6253
6253
  "closedAt": "2025-11-13T10:12:48Z",
6254
6254
  "updatedAt": "2025-11-13T10:12:48Z",
6255
6255
  "contentHash": "f7ec6f01b3c83c34cc3699ca6eee0f4488bffd0c566cccfe9433d6cbc5a87219"
6256
6256
  },
6257
6257
  "7752": {
6258
6258
  "state": "CLOSED",
6259
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7752.md",
6259
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7752.md",
6260
6260
  "closedAt": "2025-11-12T14:31:45Z",
6261
6261
  "updatedAt": "2025-11-12T14:31:45Z",
6262
6262
  "contentHash": "5f0121262ce785189cb1057dde143df058782f4eec704acd6792d3963a1867d7"
@@ -6265,64 +6265,99 @@
6265
6265
  "state": "OPEN",
6266
6266
  "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7756.md",
6267
6267
  "closedAt": null,
6268
- "updatedAt": "2025-11-12T14:12:09Z",
6269
- "contentHash": "656a49e4f060dc6f95bf1e8822f1daff6a6db216c29b42f62b5400a04caa6951"
6268
+ "updatedAt": "2025-11-14T09:15:12Z",
6269
+ "contentHash": "8b3fc488721f1838ea30740801783a201daf70d0c46c49d6dc1543277160f7a3"
6270
6270
  },
6271
6271
  "7757": {
6272
6272
  "state": "CLOSED",
6273
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7757.md",
6273
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7757.md",
6274
6274
  "closedAt": "2025-11-12T21:15:11Z",
6275
6275
  "updatedAt": "2025-11-12T21:15:11Z",
6276
6276
  "contentHash": "d319761e4e4f6af17f61f8fa82b7585ef80b132adea31a40465a61927e42fcf1"
6277
6277
  },
6278
6278
  "7758": {
6279
6279
  "state": "CLOSED",
6280
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7758.md",
6280
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7758.md",
6281
6281
  "closedAt": "2025-11-13T10:28:44Z",
6282
6282
  "updatedAt": "2025-11-13T10:28:44Z",
6283
6283
  "contentHash": "b953d24b316824788abe7e050e24e52a80b3c4352e549a09d95ce0f27d04326d"
6284
6284
  },
6285
6285
  "7759": {
6286
6286
  "state": "CLOSED",
6287
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7759.md",
6287
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7759.md",
6288
6288
  "closedAt": "2025-11-13T10:32:35Z",
6289
6289
  "updatedAt": "2025-11-13T10:32:35Z",
6290
6290
  "contentHash": "b0e8cb24d6a43e6116738dc56ef146d021a8fc0ea67546208b77c53139b5ea22"
6291
6291
  },
6292
6292
  "7760": {
6293
6293
  "state": "CLOSED",
6294
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7760.md",
6294
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7760.md",
6295
6295
  "closedAt": "2025-11-13T12:49:31Z",
6296
6296
  "updatedAt": "2025-11-13T12:49:31Z",
6297
6297
  "contentHash": "31e236b43a34dbd4199bee0ed79d4d40a88541225f426f877c40cf58f4a1a4d2"
6298
6298
  },
6299
6299
  "7761": {
6300
6300
  "state": "CLOSED",
6301
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7761.md",
6301
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7761.md",
6302
6302
  "closedAt": "2025-11-12T20:55:18Z",
6303
6303
  "updatedAt": "2025-11-12T20:55:18Z",
6304
6304
  "contentHash": "129524e52a7392ca95e5ac74c61fba0742b2a3fd2ad3e95eacfac986a58acddd"
6305
6305
  },
6306
6306
  "7765": {
6307
6307
  "state": "CLOSED",
6308
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7765.md",
6308
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7765.md",
6309
6309
  "closedAt": "2025-11-13T09:11:30Z",
6310
6310
  "updatedAt": "2025-11-13T09:11:30Z",
6311
6311
  "contentHash": "12b225e52c7f69b98aeb6f37e7513b5b42221e79865faaaa87642470a9e60d3a"
6312
6312
  },
6313
6313
  "7766": {
6314
6314
  "state": "CLOSED",
6315
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7766.md",
6315
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7766.md",
6316
6316
  "closedAt": "2025-11-13T09:21:18Z",
6317
6317
  "updatedAt": "2025-11-13T09:21:18Z",
6318
6318
  "contentHash": "1baec98eccb68b5faf5e043729f629da8e6c145b1c3e18d7ee6370df6b28e43f"
6319
6319
  },
6320
6320
  "7767": {
6321
6321
  "state": "CLOSED",
6322
- "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7767.md",
6322
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE_ARCHIVE/11.2.0/issue-7767.md",
6323
6323
  "closedAt": "2025-11-13T10:51:52Z",
6324
6324
  "updatedAt": "2025-11-13T10:51:52Z",
6325
6325
  "contentHash": "67f664cfd7f3c74e548fac407743ea56b2663dd9bf9669a8dd9d6e9eb1d43d74"
6326
+ },
6327
+ "7769": {
6328
+ "state": "CLOSED",
6329
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7769.md",
6330
+ "closedAt": "2025-11-13T22:12:31Z",
6331
+ "updatedAt": "2025-11-13T22:12:31Z",
6332
+ "contentHash": "7c2a6b46c1de475ba4a5c585d2f8fa397aa7bceb8e86767906145c9cd0c33219"
6333
+ },
6334
+ "7770": {
6335
+ "state": "CLOSED",
6336
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7770.md",
6337
+ "closedAt": "2025-11-13T22:17:28Z",
6338
+ "updatedAt": "2025-11-13T22:17:28Z",
6339
+ "contentHash": "7575cb7f05c4aa45189926563059610b8588fc7e6455a4f2a4bb9e030d188f9e"
6340
+ },
6341
+ "7771": {
6342
+ "state": "CLOSED",
6343
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7771.md",
6344
+ "closedAt": "2025-11-13T22:54:46Z",
6345
+ "updatedAt": "2025-11-13T22:54:46Z",
6346
+ "contentHash": "262498b1110113a15db6536f3fe79d8eff910724095bfdf166b5fb885766bd7d"
6347
+ },
6348
+ "7772": {
6349
+ "state": "CLOSED",
6350
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7772.md",
6351
+ "closedAt": "2025-11-14T11:41:20Z",
6352
+ "updatedAt": "2025-11-14T11:41:20Z",
6353
+ "contentHash": "59a12299ce0880d4942ee5509f3f8935c1306bcec067997dbbd7f758dcb1d13c"
6354
+ },
6355
+ "7773": {
6356
+ "state": "CLOSED",
6357
+ "path": "/Users/Shared/github/neomjs/neo/.github/ISSUE/issue-7773.md",
6358
+ "closedAt": "2025-11-14T15:01:57Z",
6359
+ "updatedAt": "2025-11-14T15:01:57Z",
6360
+ "contentHash": "41b089e9c0e49db562fd044c6e66f3bafd89cc9f2e5cb2b29cf8658886d2650c"
6326
6361
  }
6327
6362
  },
6328
6363
  "releases": {
@@ -6477,6 +6512,10 @@
6477
6512
  "11.1.0": {
6478
6513
  "publishedAt": "2025-11-12T08:53:49Z",
6479
6514
  "contentHash": "9f07fa7f781bea98dbbb0dbd61621e869611d5e8b39da9e7556c1969f352dc4b"
6515
+ },
6516
+ "11.2.0": {
6517
+ "publishedAt": "2025-11-13T13:36:25Z",
6518
+ "contentHash": "2cfc4b0c38c71ec9058af53248b522da9960d48f8d7abfaae0de7e70596b49c6"
6480
6519
  }
6481
6520
  }
6482
6521
  }
package/ServiceWorker.mjs CHANGED
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='11.2.0'
23
+ * @member {String} version='11.3.0'
24
24
  */
25
- version: '11.2.0'
25
+ version: '11.3.0'
26
26
  }
27
27
 
28
28
  /**
@@ -331,7 +331,7 @@ class DatabaseService extends Base {
331
331
  logger.log(`Using collection: ${collection.name}`);
332
332
 
333
333
  logger.log('Fetching existing documents from ChromaDB...');
334
- const existingDocs = await collection.get({ include: ["metadatas"] });
334
+ const existingDocs = await collection.get({ include: ["metadatas"] });
335
335
  const existingDocsMap = new Map();
336
336
 
337
337
  existingDocs.ids.forEach((id, index) => {
@@ -374,8 +374,7 @@ class DatabaseService extends Base {
374
374
  logger.log(`Initialized Google AI embedding model: ${aiConfig.embeddingModel}.`);
375
375
 
376
376
  logger.log('Embedding chunks...');
377
- const batchSize = aiConfig.batchSize;
378
- const maxRetries = aiConfig.maxRetries;
377
+ const {batchSize, maxRetries} = aiConfig;
379
378
 
380
379
  for (let i = 0; i < chunksToProcess.length; i += batchSize) {
381
380
  const batch = chunksToProcess.slice(i, i + batchSize);
@@ -402,7 +401,7 @@ class DatabaseService extends Base {
402
401
  await collection.upsert({
403
402
  ids : batch.map(chunk => chunk.id),
404
403
  embeddings,
405
- metadatas: metadatas
404
+ metadatas
406
405
  });
407
406
  logger.log(`Processed and embedded batch ${i / batchSize + 1} of ${Math.ceil(chunksToProcess.length / batchSize)}`);
408
407
  success = true;
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2025-11-13",
19
+ "datePublished": "2025-11-14",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -1,10 +1,34 @@
1
1
  # Neo.mjs Platform
2
2
 
3
- > Neo.mjs is not a library, but a comprehensive web platform and a new operating system for the web, with over 1000 files and 130,000 lines of code. It is architected for AI collaboration from the ground up, featuring three dedicated Model Context Protocol (MCP) servers. It reimagines web development from first principles, treating the browser as a distributed computing environment, not a single-threaded document renderer.
3
+ > Neo.mjs is not a library, but a comprehensive web platform and a new operating system for the web, with over 1000
4
+ > files and 130,000 lines of code. It is architected for AI collaboration from the ground up, featuring three dedicated
5
+ > Model Context Protocol (MCP) servers. It reimagines web development from first principles, treating the browser as a
6
+ > distributed computing environment, not a single-threaded document renderer.
4
7
  >
5
- > The core of Neo.mjs is its truly multi-threaded architecture which moves all application logic, state management, and data processing off the main thread. This ensures a "jank-free" user experience where the UI remains perfectly responsive, regardless of the workload. The platform provides a holistic, managed environment with operational guarantees, a unified class config system for declaratively describing entire component trees, and critical operational primitives like multi-window state. It includes an enterprise-grade component library.
8
+ > The core of Neo.mjs is its truly multi-threaded architecture which moves all application logic, state management, and
9
+ > data processing off the main thread. This ensures a "jank-free" user experience where the UI remains perfectly
10
+ > responsive, regardless of the workload. The platform provides a holistic, managed environment with operational
11
+ > guarantees, a unified class config system for declaratively describing entire component trees, and critical operational
12
+ > primitives like multi-window state. It includes an enterprise-grade component library.
6
13
  >
7
- > The developer experience is revolutionary and future-proof, featuring a zero-builds development mode that is 100% based on web standards. This eliminates the frustrating abstraction layer of bundlers and transpilers and ensures that applications evolve with the web platform itself.
14
+ > The developer experience is revolutionary and future-proof, featuring a zero-builds development mode that is 100% based
15
+ > on web standards. This eliminates the frustrating abstraction layer of bundlers and transpilers and ensures that
16
+ > applications evolve with the web platform itself.
17
+
18
+ Neo.mjs uniquely deploys each application and example in four equivalent environments, each serving identical
19
+ functionality through different code delivery methods: development mode (zero-builds), dist/development (bundled,
20
+ unminified), dist/esm (native ES modules, optimized), and dist/production (bundled, minified).
21
+
22
+ The URLs listed below use the development mode paths (e.g., /apps/ or /examples/), representing the zero-builds,
23
+ browser-native version that embodies Neo.mjs's core philosophy. To access any application in a different environment,
24
+ simply prefix the path with /dist/development/, /dist/esm/, or /dist/production/.
25
+
26
+ For example, the Portal app is available at all four environment URLs, plus a fifth version mapped to the domain root:
27
+ - https://neomjs.com/ (mapped to dist/production)
28
+ - https://neomjs.com/apps/portal/index.html (dev mode)
29
+ - https://neomjs.com/dist/development/apps/portal/index.html
30
+ - https://neomjs.com/dist/esm/apps/portal/index.html
31
+ - https://neomjs.com/dist/production/apps/portal/index.html
8
32
 
9
33
  ## main
10
34
 
@@ -117,3 +141,135 @@
117
141
  - [v10 Post 1: A Love Story](https://neomjs.com/#/learn/blog/v10-post1-love-story)
118
142
  - [JSON Blueprints & Shared Workers](https://neomjs.com/#/learn/blog/json-blueprints-and-shared-workers)
119
143
 
144
+ ## Demo Apps and Examples
145
+
146
+ - [Colors Dashboard](https://neomjs.com/apps/colors/index.html)
147
+ - [COVID-19 IN NUMBERS](https://neomjs.com/apps/covid/index.html)
148
+ - [Email](https://neomjs.com/apps/email/index.html)
149
+ - [Neo.mjs Finance Dashboard](https://neomjs.com/apps/finance/index.html)
150
+ - [Form](https://neomjs.com/apps/form/index.html)
151
+ - [Neo.mjs](https://neomjs.com/apps/portal/index.html)
152
+ - [Conduit](https://neomjs.com/apps/realworld/index.html)
153
+ - [RealWorld2](https://neomjs.com/apps/realworld2/index.html)
154
+ - [Route](https://neomjs.com/apps/route/index.html)
155
+ - [SharedCovid MainWindow](https://neomjs.com/apps/sharedcovid/index.html)
156
+ - [SharedDialog](https://neomjs.com/apps/shareddialog/index.html)
157
+ - [Neo Button](https://neomjs.com/examples/button/base/index.html)
158
+ - [Neo EffectButton](https://neomjs.com/examples/button/effect/index.html)
159
+ - [Neo SplitButton](https://neomjs.com/examples/button/split/index.html)
160
+ - [neo.mjs Calendar Basic](https://neomjs.com/examples/calendar/basic/index.html)
161
+ - [neo.mjs Calendar WeekView](https://neomjs.com/examples/calendar/weekview/index.html)
162
+ - [Neo amCharts](https://neomjs.com/examples/charts/index.html)
163
+ - [Neo OffscreenCanvas](https://neomjs.com/examples/component/canvas/index.html)
164
+ - [Neo Carousel](https://neomjs.com/examples/component/carousel/index.html)
165
+ - [Neo Chip](https://neomjs.com/examples/component/chip/index.html)
166
+ - [Neo Circle](https://neomjs.com/examples/component/circle/index.html)
167
+ - [Neo Clock](https://neomjs.com/examples/component/clock/index.html)
168
+ - [COVID19 Gallery](https://neomjs.com/examples/component/coronaGallery/index.html)
169
+ - [COVID19 Helix](https://neomjs.com/examples/component/coronaHelix/index.html)
170
+ - [Neo DateSelector](https://neomjs.com/examples/component/dateSelector/index.html)
171
+ - [Neo Gallery](https://neomjs.com/examples/component/gallery/index.html)
172
+ - [Neo Helix](https://neomjs.com/examples/component/helix/index.html)
173
+ - [Neo Magic Move - Text](https://neomjs.com/examples/component/magicmovetext/index.html)
174
+ - [Gallery Controls](https://neomjs.com/examples/component/multiWindowCoronaGallery/childapp/index.html)
175
+ - [Neo Multi-Window Corona Gallery](https://neomjs.com/examples/component/multiWindowCoronaGallery/index.html)
176
+ - [Helix Controls](https://neomjs.com/examples/component/multiWindowHelix/childapp/index.html)
177
+ - [Neo Multi-Window Helix](https://neomjs.com/examples/component/multiWindowHelix/index.html)
178
+ - [Neo MWC Button](https://neomjs.com/examples/component/mwc/button/index.html)
179
+ - [Neo MWC Buttons](https://neomjs.com/examples/component/mwc/buttons/index.html)
180
+ - [Neo MWC TextField](https://neomjs.com/examples/component/mwc/textField/index.html)
181
+ - [Neo MWC TextFields](https://neomjs.com/examples/component/mwc/textFields/index.html)
182
+ - [Neo Process Component](https://neomjs.com/examples/component/process/index.html)
183
+ - [Neo Process Real World Example](https://neomjs.com/examples/component/process/realWorldExample/index.html)
184
+ - [Neo Progress](https://neomjs.com/examples/component/progress/index.html)
185
+ - [Neo Splitter](https://neomjs.com/examples/component/splitter/index.html)
186
+ - [Neo StatusBadge](https://neomjs.com/examples/component/statusbadge/index.html)
187
+ - [Neo Timer](https://neomjs.com/examples/component/timer/index.html)
188
+ - [Neo Toast Component](https://neomjs.com/examples/component/toast/index.html)
189
+ - [Neo Video](https://neomjs.com/examples/component/video/index.html)
190
+ - [Neo CesiumJS Component](https://neomjs.com/examples/component/wrapper/cesiumJS/index.html)
191
+ - [Neo GoogleMaps Component](https://neomjs.com/examples/component/wrapper/googleMaps/index.html)
192
+ - [Neo Monaco Editor](https://neomjs.com/examples/component/wrapper/monacoEditor/index.html)
193
+ - [Neo OpenStreetMaps/OpenLayers Component](https://neomjs.com/examples/component/wrapper/openStreetMaps/index.html)
194
+ - [Neo Accordion](https://neomjs.com/examples/container/accordion/index.html)
195
+ - [Neo Containers](https://neomjs.com/examples/container/base/index.html)
196
+ - [neo.mjs config system](https://neomjs.com/examples/core/config/index.html)
197
+ - [Neo Dashboard](https://neomjs.com/examples/dashboard/index.html)
198
+ - [Neo DateSelector](https://neomjs.com/examples/date/selectorContainer/index.html)
199
+ - [Neo Dialog](https://neomjs.com/examples/dialog/index.html)
200
+ - [Neo Fields](https://neomjs.com/examples/fields/index.html)
201
+ - [Field with Prefix](https://neomjs.com/examples/fieldWithPrefix/index.html)
202
+ - [Neo CheckBoxField](https://neomjs.com/examples/form/field/checkbox/index.html)
203
+ - [Neo ChipField](https://neomjs.com/examples/form/field/chip/index.html)
204
+ - [Neo ColorField](https://neomjs.com/examples/form/field/color/index.html)
205
+ - [Neo ComboBox](https://neomjs.com/examples/form/field/combobox/index.html)
206
+ - [Neo DateField](https://neomjs.com/examples/form/field/date/index.html)
207
+ - [Neo EmailField](https://neomjs.com/examples/form/field/email/index.html)
208
+ - [Neo FileUploadField](https://neomjs.com/examples/form/field/fileupload/index.html)
209
+ - [Neo NumberField](https://neomjs.com/examples/form/field/number/index.html)
210
+ - [Neo PickerField](https://neomjs.com/examples/form/field/picker/index.html)
211
+ - [Neo RadioField](https://neomjs.com/examples/form/field/radio/index.html)
212
+ - [Neo SwitchField](https://neomjs.com/examples/form/field/switch/index.html)
213
+ - [Neo TextField](https://neomjs.com/examples/form/field/text/index.html)
214
+ - [Neo TextAreaField](https://neomjs.com/examples/form/field/textarea/index.html)
215
+ - [Neo TimeField](https://neomjs.com/examples/form/field/time/index.html)
216
+ - [Neo Copy to Clipboard Triggers](https://neomjs.com/examples/form/field/trigger/copyToClipboard/index.html)
217
+ - [Neo UrlField](https://neomjs.com/examples/form/field/url/index.html)
218
+ - [Neo Fieldset](https://neomjs.com/examples/form/fieldset/index.html)
219
+ - [Neo Functional Button](https://neomjs.com/examples/functional/button/base/index.html)
220
+ - [Neo Functional Component](https://neomjs.com/examples/functional/defineComponent/index.html)
221
+ - [Functional Component Hosting Component](https://neomjs.com/examples/functional/hostComponent/index.html)
222
+ - [Neo Functional Nested Templates](https://neomjs.com/examples/functional/nestedTemplateComponent/index.html)
223
+ - [Neo Functional Template Component](https://neomjs.com/examples/functional/templateComponent/index.html)
224
+ - [Neo Grid: Animated Row Sorting](https://neomjs.com/examples/grid/animatedRowSorting/index.html)
225
+ - [Neo GridContainer - Big Data](https://neomjs.com/examples/grid/bigData/index.html)
226
+ - [Neo Grid CellEditing](https://neomjs.com/examples/grid/cellEditing/index.html)
227
+ - [Neo GridContainer](https://neomjs.com/examples/grid/container/index.html)
228
+ - [Neo CovidGrid](https://neomjs.com/examples/grid/covid/index.html)
229
+ - [Neo Grid: Nested Record Fields](https://neomjs.com/examples/grid/nestedRecordFields/index.html)
230
+ - [Neo Card Layout](https://neomjs.com/examples/layout/card/index.html)
231
+ - [Neo Cube Layout](https://neomjs.com/examples/layout/cube/index.html)
232
+ - [Neo Form Layout](https://neomjs.com/examples/layout/form/index.html)
233
+ - [Neo AnimatedList](https://neomjs.com/examples/list/animate/index.html)
234
+ - [Neo List](https://neomjs.com/examples/list/base/index.html)
235
+ - [Neo ChipList](https://neomjs.com/examples/list/chip/index.html)
236
+ - [Neo CircleList](https://neomjs.com/examples/list/circle/index.html)
237
+ - [Neo ColorList](https://neomjs.com/examples/list/color/index.html)
238
+ - [Neo MenuList](https://neomjs.com/examples/menu/list/index.html)
239
+ - [Neo Menu](https://neomjs.com/examples/menu/panel/index.html)
240
+ - [Neo Panels](https://neomjs.com/examples/panel/index.html)
241
+ - [Neo Tree](https://neomjs.com/examples/popover/index.html)
242
+ - [Preloading Assets](https://neomjs.com/examples/preloadingAssets/index.html)
243
+ - [Remotes API Basic](https://neomjs.com/examples/remotesApi/basic/index.html)
244
+ - [Neo.mjs - Load Grid Container](https://neomjs.com/examples/serverside/gridContainer/index.html)
245
+ - [Neo.mjs - Load Toolbar Items](https://neomjs.com/examples/serverside/toolbarItems/index.html)
246
+ - [Neo Sitemap](https://neomjs.com/examples/sitemap/index.html)
247
+ - [state.Provider: advanced](https://neomjs.com/examples/stateProvider/advanced/index.html)
248
+ - [state.Provider: dialog](https://neomjs.com/examples/stateProvider/dialog/index.html)
249
+ - [state.Provider: extended class](https://neomjs.com/examples/stateProvider/extendedClass/index.html)
250
+ - [state.Provider: inline definition](https://neomjs.com/examples/stateProvider/inline/index.html)
251
+ - [inline example without using a state.Provider](https://neomjs.com/examples/stateProvider/inlineNoStateProvider/index.html)
252
+ - [stateProvider.multiWindow](https://neomjs.com/examples/stateProvider/multiWindow/index.html)
253
+ - [stateProvider.multiWindow2](https://neomjs.com/examples/stateProvider/multiWindow2/index.html)
254
+ - [state.Provider: nested data](https://neomjs.com/examples/stateProvider/nestedData/index.html)
255
+ - [Neo table & bound store](https://neomjs.com/examples/stateProvider/table/index.html)
256
+ - [state.Provider: 2 way binding](https://neomjs.com/examples/stateProvider/twoWay/index.html)
257
+ - [Neo TabContainer](https://neomjs.com/examples/tab/container/index.html)
258
+ - [Neo Table CellEditing](https://neomjs.com/examples/table/cellEditing/index.html)
259
+ - [Neo TableContainer](https://neomjs.com/examples/table/container/index.html)
260
+ - [Neo CovidTable](https://neomjs.com/examples/table/covid/index.html)
261
+ - [Neo Table: Nested Record Fields](https://neomjs.com/examples/table/nestedRecordFields/index.html)
262
+ - [Neo Table Filtering](https://neomjs.com/examples/tableFiltering/index.html)
263
+ - [Neo Table Performance](https://neomjs.com/examples/tablePerformance/index.html)
264
+ - [Neo Table & Store](https://neomjs.com/examples/tableStore/index.html)
265
+ - [Neo Tabs](https://neomjs.com/examples/tabs/index.html)
266
+ - [Neo TodoList version1](https://neomjs.com/examples/todoList/version1/index.html)
267
+ - [Neo TodoList version2](https://neomjs.com/examples/todoList/version2/index.html)
268
+ - [Neo Breadcrumb Toolbar](https://neomjs.com/examples/toolbar/breadcrumb/index.html)
269
+ - [Neo Paging Toolbar](https://neomjs.com/examples/toolbar/paging/index.html)
270
+ - [Neo Tree](https://neomjs.com/examples/tree/index.html)
271
+ - [Neo Tree](https://neomjs.com/examples/treeAccordion/index.html)
272
+ - [Neo.mjs - Moving a Video Tag](https://neomjs.com/examples/videoMove/index.html)
273
+ - [Neo Viewport](https://neomjs.com/examples/viewport/index.html)
274
+ - [Neo TaskWorker](https://neomjs.com/examples/worker/task/index.html)
275
+
@@ -0,0 +1,30 @@
1
+ {
2
+ "/about-us": {
3
+ "title": "About Us - Neo.mjs",
4
+ "description": "Learn more about the team behind Neo.mjs."
5
+ },
6
+ "/blog": {
7
+ "title": "Neo.mjs Blog",
8
+ "description": "The official blog for the Neo.mjs platform."
9
+ },
10
+ "/docs": {
11
+ "title": "Neo.mjs Docs",
12
+ "description": "Official documentation for the Neo.mjs platform."
13
+ },
14
+ "/examples": {
15
+ "title": "Neo.mjs Examples",
16
+ "description": "A collection of examples for the Neo.mjs platform."
17
+ },
18
+ "/home": {
19
+ "title": "Neo.mjs",
20
+ "description": "Solve your toughest UI performance challenges with Neo.mjs: a multi-threaded JavaScript platform for extreme real-time web applications, complex dashboards, and unmatched developer productivity."
21
+ },
22
+ "/learn": {
23
+ "title": "Learn Neo.mjs",
24
+ "description": "Learn the fundamentals of the Neo.mjs platform."
25
+ },
26
+ "/services": {
27
+ "title": "Neo.mjs Services",
28
+ "description": "Professional services for the Neo.mjs platform."
29
+ }
30
+ }
@@ -0,0 +1,146 @@
1
+ import Base from '../../../src/core/Base.mjs';
2
+
3
+ /**
4
+ * @summary Manages SEO metadata for the Portal application, fetching it from a JSON file
5
+ * and intelligently updating the document head based on route changes.
6
+ *
7
+ * This singleton service is responsible for centralizing all SEO-related logic.
8
+ * It fetches route-specific title and description metadata from `apps/portal/resources/data/seo.json`
9
+ * during its asynchronous initialization. It then provides a mechanism for the `ViewportController`
10
+ * to notify it of route changes. The service ensures that the document's `<title>` and `<meta name="description">`
11
+ * tags are updated only when the service is fully ready and with the most recent route hash,
12
+ * preventing race conditions on slow network connections.
13
+ *
14
+ * This class demonstrates the use of asynchronous initialization (`initAsync`), reactive config hooks (`afterSetIsReady`),
15
+ * and private class fields to manage internal state and ensure robust behavior.
16
+ *
17
+ * @class Portal.service.Seo
18
+ * @extends Neo.core.Base
19
+ * @singleton
20
+ * @see Portal.view.ViewportController
21
+ */
22
+ class Seo extends Base {
23
+ static config = {
24
+ /**
25
+ * @member {String} className='Portal.service.Seo'
26
+ * @protected
27
+ */
28
+ className: 'Portal.service.Seo',
29
+ /**
30
+ * @member {Boolean} singleton=true
31
+ * @protected
32
+ */
33
+ singleton: true
34
+ }
35
+
36
+ /**
37
+ * Stores the most recent route hash received from `onRouteChanged()`.
38
+ * This is used to process a pending route update if the service becomes ready after a route change occurred.
39
+ * @member {String|null} #lastRouteHash=null
40
+ * @private
41
+ */
42
+ #lastRouteHash = null
43
+ /**
44
+ * Caches the SEO metadata fetched from `apps/portal/resources/data/seo.json`.
45
+ * This object maps route hash strings to their corresponding title and description.
46
+ * @member {Object|null} #metadata=null
47
+ * @private
48
+ */
49
+ #metadata = null
50
+
51
+ /**
52
+ * Hook that fires after the `isReady` config changes. If the service becomes ready (`value` is true)
53
+ * and there's a pending route hash (`#lastRouteHash` is not null), it triggers an update
54
+ * of the document head with the metadata for that route.
55
+ * @param {Boolean} value The new value of the `isReady` config.
56
+ * @param {Boolean} oldValue The old value of the `isReady` config.
57
+ * @protected
58
+ */
59
+ afterSetIsReady(value, oldValue) {
60
+ if (value && this.#lastRouteHash) {
61
+ this.#updateDocumentHeadIfNeeded(this.#lastRouteHash)
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Retrieves the SEO metadata (title and description) for a given route hash.
67
+ * @param {String} route The route hash string (e.g., '/home', '/blog').
68
+ * @returns {Object|null} An object containing `title` and `description` for the route, or `null` if not found.
69
+ */
70
+ getMetadata(route) {
71
+ return this.#metadata?.[route] || null
72
+ }
73
+
74
+ /**
75
+ * Asynchronously initializes the SEO service by fetching the `seo.json` file.
76
+ * This method simulates an API call to retrieve SEO data, making the service ready
77
+ * to provide metadata. It ensures that the service is fully loaded before processing
78
+ * any route-related document head updates.
79
+ * @returns {Promise<void>} A promise that resolves when the metadata has been fetched and parsed.
80
+ */
81
+ async initAsync() {
82
+ await super.initAsync();
83
+
84
+ try {
85
+ const response = await fetch('../../apps/portal/resources/data/seo.json');
86
+ if (!response.ok) {
87
+ throw new Error(`HTTP error with status: ${response.status}`)
88
+ }
89
+ this.#metadata = await response.json();
90
+ } catch (error) {
91
+ console.error('Error fetching SEO metadata:', error)
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Called by the `ViewportController` when the application's route changes.
97
+ * This method stores the new route hash and attempts to update the document head.
98
+ * If the service is not yet ready (i.e., `initAsync` is still running), the update
99
+ * is deferred until `isReady` becomes true.
100
+ * @param {String} hash The new route hash string.
101
+ */
102
+ onRouteChanged(hash) {
103
+ this.#lastRouteHash = hash;
104
+ this.#updateDocumentHeadIfNeeded(hash)
105
+ }
106
+
107
+ /**
108
+ * This private method calls the `DocumentHead` main thread addon to update the document's
109
+ * title and meta-description for SEO purposes. It is the actual mechanism for applying
110
+ * the SEO changes to the browser's DOM.
111
+ * @param {Object} config The configuration object containing `description` and `title`.
112
+ * @param {String} config.description The new meta-description for the document.
113
+ * @param {String} config.title The new title for the document.
114
+ * @private
115
+ */
116
+ async #updateDocumentHead({description, title}) {
117
+ let {windowId} = this,
118
+ DocumentHead = await Neo.currentWorker.getAddon('DocumentHead', windowId);
119
+
120
+ await DocumentHead.update({description, title, windowId})
121
+ }
122
+
123
+ /**
124
+ * A private helper method that conditionally updates the document head.
125
+ * It checks if the service is `isReady` before attempting to retrieve metadata
126
+ * and call `#updateDocumentHead`. If an update occurs, it clears `#lastRouteHash`.
127
+ * This prevents multiple updates for the same route if `onRouteChanged` is called
128
+ * before `initAsync` completes.
129
+ * @param {String} hash The route hash for which to update the document head.
130
+ * @private
131
+ */
132
+ #updateDocumentHeadIfNeeded(hash) {
133
+ let me = this;
134
+
135
+ if (me.isReady) {
136
+ let metadata = me.getMetadata(hash);
137
+
138
+ if (metadata) {
139
+ me.#updateDocumentHead(metadata);
140
+ me.#lastRouteHash = null
141
+ }
142
+ }
143
+ }
144
+ }
145
+
146
+ export default Neo.setupClass(Seo);