@breakside/jskit 2025.9.0 → 2025.10.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.
Files changed (38) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  5. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  6. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  7. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  8. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  9. package/Info.json +2 -2
  10. package/Node/io.breakside.jskit-bundle.js +2 -2
  11. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  12. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  13. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  14. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  15. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  16. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  17. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  18. package/Root/Frameworks/DOM/Info.yaml +1 -1
  19. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  20. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  21. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  22. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  23. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  24. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  25. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  26. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  27. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  28. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  29. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  30. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  31. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  32. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  33. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  34. package/Root/Frameworks/UIKit/UIHTMLOpenPanel.js +19 -4
  35. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  36. package/Root/Templates/html/${PROJECT_NAME}/www/HTMLAppBootstrapper.js +198 -89
  37. package/Root/Templates/html/${PROJECT_NAME}/www/index.html +1 -10
  38. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "JSBundleType": "framework",
3
3
  "JSBundleIdentifier": "io.breakside.JSKit.DOM",
4
- "JSBundleVersion": "2025.9.0",
4
+ "JSBundleVersion": "2025.10.0",
5
5
  "JSDevelopmentLanguage": "en",
6
6
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
7
7
  "JSBundleEnvironments": {
@@ -9,5 +9,5 @@
9
9
  "node": "DOM+Node.js"
10
10
  },
11
11
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
12
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
12
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
13
13
  }
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.DOM'] = {
3
3
  "Info": {
4
4
  "JSBundleType": "framework",
5
5
  "JSBundleIdentifier": "io.breakside.JSKit.DOM",
6
- "JSBundleVersion": "2025.9.0",
6
+ "JSBundleVersion": "2025.10.0",
7
7
  "JSDevelopmentLanguage": "en",
8
8
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
9
9
  "JSBundleEnvironments": {
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.DOM'] = {
11
11
  "node": "DOM+Node.js"
12
12
  },
13
13
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
14
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
14
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
15
15
  },
16
16
  "Resources": [],
17
17
  "ResourceLookup": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "JSBundleType": "framework",
3
3
  "JSBundleIdentifier": "io.breakside.JSKit.FontKit",
4
- "JSBundleVersion": "2025.9.0",
4
+ "JSBundleVersion": "2025.10.0",
5
5
  "JSDevelopmentLanguage": "en",
6
6
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
7
7
  "JSBundleEnvironments": {
8
8
  "html": "FontKit+HTML.js"
9
9
  },
10
10
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
11
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
11
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
12
12
  }
@@ -3,14 +3,14 @@ JSBundle.bundles['io.breakside.JSKit.FontKit'] = {
3
3
  "Info": {
4
4
  "JSBundleType": "framework",
5
5
  "JSBundleIdentifier": "io.breakside.JSKit.FontKit",
6
- "JSBundleVersion": "2025.9.0",
6
+ "JSBundleVersion": "2025.10.0",
7
7
  "JSDevelopmentLanguage": "en",
8
8
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
9
9
  "JSBundleEnvironments": {
10
10
  "html": "FontKit+HTML.js"
11
11
  },
12
12
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
13
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
13
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
14
14
  },
15
15
  "Resources": [],
16
16
  "ResourceLookup": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "JSBundleType": "framework",
3
3
  "JSBundleIdentifier": "io.breakside.JSKit.Foundation",
4
- "JSBundleVersion": "2025.9.0",
4
+ "JSBundleVersion": "2025.10.0",
5
5
  "JSDevelopmentLanguage": "en",
6
6
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
7
7
  "JSBundleEnvironments": {
@@ -9,5 +9,5 @@
9
9
  "node": "Foundation+Node.js"
10
10
  },
11
11
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
12
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
12
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
13
13
  }
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.Foundation'] = {
3
3
  "Info": {
4
4
  "JSBundleType": "framework",
5
5
  "JSBundleIdentifier": "io.breakside.JSKit.Foundation",
6
- "JSBundleVersion": "2025.9.0",
6
+ "JSBundleVersion": "2025.10.0",
7
7
  "JSDevelopmentLanguage": "en",
8
8
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
9
9
  "JSBundleEnvironments": {
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.Foundation'] = {
11
11
  "node": "Foundation+Node.js"
12
12
  },
13
13
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
14
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
14
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
15
15
  },
16
16
  "Resources": [
17
17
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "JSBundleType": "framework",
3
3
  "JSBundleIdentifier": "io.breakside.JSKit.SecurityKit",
4
- "JSBundleVersion": "2025.9.0",
4
+ "JSBundleVersion": "2025.10.0",
5
5
  "JSDevelopmentLanguage": "en",
6
6
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
7
7
  "JSBundleEnvironments": {
@@ -9,5 +9,5 @@
9
9
  "node": "SecurityKit+Node.js"
10
10
  },
11
11
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
12
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
12
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
13
13
  }
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.SecurityKit'] = {
3
3
  "Info": {
4
4
  "JSBundleType": "framework",
5
5
  "JSBundleIdentifier": "io.breakside.JSKit.SecurityKit",
6
- "JSBundleVersion": "2025.9.0",
6
+ "JSBundleVersion": "2025.10.0",
7
7
  "JSDevelopmentLanguage": "en",
8
8
  "JSCopyright": "Copyright © 2020 Breakside Inc.",
9
9
  "JSBundleEnvironments": {
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.SecurityKit'] = {
11
11
  "node": "SecurityKit+Node.js"
12
12
  },
13
13
  "JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
14
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
14
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
15
15
  },
16
16
  "Resources": [],
17
17
  "ResourceLookup": {
package/Info.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "JSBundleType": "node",
3
3
  "JSBundleIdentifier": "io.breakside.jskit",
4
- "JSBundleVersion": "2025.9.0",
4
+ "JSBundleVersion": "2025.10.0",
5
5
  "JSExecutableName": "jskit",
6
6
  "NPMOrganization": "breakside",
7
7
  "JSResources": [
8
8
  "Tests/HTMLTestRunner.js",
9
9
  "Tests/NodeTestRunner.js"
10
10
  ],
11
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
11
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
12
12
  }
@@ -3,14 +3,14 @@ JSBundle.bundles['io.breakside.jskit'] = {
3
3
  "Info": {
4
4
  "JSBundleType": "node",
5
5
  "JSBundleIdentifier": "io.breakside.jskit",
6
- "JSBundleVersion": "2025.9.0",
6
+ "JSBundleVersion": "2025.10.0",
7
7
  "JSExecutableName": "jskit",
8
8
  "NPMOrganization": "breakside",
9
9
  "JSResources": [
10
10
  "Tests/HTMLTestRunner.js",
11
11
  "Tests/NodeTestRunner.js"
12
12
  ],
13
- "GitRevision": "d6edda13912309c1edca976270293b135ca54c5b"
13
+ "GitRevision": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
14
14
  },
15
15
  "Resources": [
16
16
  {
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.APIKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSIncludeDirectories:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.APIKitTesting
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.AuthKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.CSSOM
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ChartKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2021 Breakside Inc.
6
6
  # JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ConferenceKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.DBKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.DOM
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.Dispatch
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSCopyright: Copyright © 2020 Breakside Inc.
5
5
  JSBundleEnvironments:
6
6
  html: Dispatch+HTML.js
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.FontKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.Foundation
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ImageKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.MediaKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.MediaKitUI
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.NotificationKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2021 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.PDFKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.QRKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.SearchKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.SecurityKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKitTesting
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.TestKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKit
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -44,7 +44,13 @@ JSClass("UIHTMLOpenPanel", UIOpenPanel, {
44
44
  }
45
45
  }
46
46
  var panel = this;
47
- fileInput.addEventListener("change", function(){
47
+ var hasCompleted = false;
48
+ var handleChange = function(){
49
+ fileInput.removeEventListener("change", handleChange);
50
+ fileInput.removeEventListener("cancel", handleCancel);
51
+ if (hasCompleted){
52
+ return;
53
+ }
48
54
  if (panel.allowsMultipleSelection || panel.chooseDirectories){
49
55
  if (fileInput.webkitEntries && fileInput.webkitEntries.length > 0){
50
56
  panel._fileEnumerator = JSHTMLFileSystemEntryFileEnumerator.initWithHTMLEntries(fileInput.webkitEntries);
@@ -57,13 +63,22 @@ JSClass("UIHTMLOpenPanel", UIOpenPanel, {
57
63
  }
58
64
  }
59
65
  action.call(target, panel);
66
+ hasCompleted = true;
60
67
  fileInput.parentNode.removeChild(fileInput);
61
68
  UIHTMLOpenPanel.fileInput = null;
62
- });
63
- fileInput.addEventListener("cancel", function(){
69
+ };
70
+ var handleCancel = function(){
71
+ fileInput.removeEventListener("change", handleChange);
72
+ fileInput.removeEventListener("cancel", handleCancel);
73
+ if (hasCompleted){
74
+ return;
75
+ }
76
+ hasCompleted = true;
64
77
  fileInput.parentNode.removeChild(fileInput);
65
78
  UIHTMLOpenPanel.fileInput = null;
66
- });
79
+ };
80
+ fileInput.addEventListener("change", handleChange);
81
+ fileInput.addEventListener("cancel", handleCancel);
67
82
  fileInput.click();
68
83
  }
69
84
 
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKitTesting
3
- JSBundleVersion: 2025.9.0
3
+ JSBundleVersion: 2025.10.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -19,14 +19,12 @@ window.HTMLAppBootstrapper = function(rootElement, jskitapp){
19
19
  this.appSrc = jskitapp.appSrc;
20
20
  this.appCss = jskitapp.appCss;
21
21
  }
22
+ this.id = this._generateRandomID();
22
23
  this.status = HTMLAppBootstrapper.STATUS.notstarted;
23
- this.statusDispatchTimeoutID = null;
24
24
  this.preflightChecks = [];
25
- this.minStatusInterval = 30;
26
25
  this.loadingScripts = {};
27
26
  this.preflightStorageKey = this.preflightID;
28
27
  this.preflightStorageValue = navigator.userAgent;
29
- this._isAppcacheInstalled = false;
30
28
  this.serviceWorker = null;
31
29
  this.application = null;
32
30
  this.error = null;
@@ -58,26 +56,38 @@ HTMLAppBootstrapper.prototype = {
58
56
 
59
57
  // expected to be overridden by whatver code instantiates the bootstrapper, in order
60
58
  // to receive callbacks for status changes so the bootstrap UI can be updated
61
- onstatus: function(){
59
+ onstatus: function(status){
62
60
  },
63
61
 
64
- onprogress: function(){
62
+ onprogress: function(loaded, total){
63
+ },
64
+
65
+ onlongload: function(i){
66
+ },
67
+
68
+ onerror: function(error){
65
69
  },
66
70
 
67
71
  onlog: function(record){
68
72
  },
69
73
 
74
+ ontimeout: function(){
75
+ },
76
+
77
+ onhidden: function(){
78
+ },
79
+
70
80
  run: function(){
71
81
  if (this.app === null){
72
82
  return;
73
83
  }
74
- this.log_info("boot", "Booting " + this.app.bundleId + ", build " + this.app.buildId);
84
+ this.rootElement.ownerDocument.addEventListener("visibilitychange", this);
85
+ this._resetTimeout();
86
+ this.log_debug("boot", "Booting " + this.app.bundleId + ", version " + this.app.bundleVersion + " (build " + this.app.buildId + ")");
75
87
  if (this.serviceWorkerSrc && window.navigator.serviceWorker){
76
88
  this._installUsingServiceWorker(window.navigator.serviceWorker);
77
- }else if (document.documentElement.getAttribute("manifest") && window.applicationCache){
78
- this._installUsingAppcache(window.applicationCache);
79
89
  }else{
80
- this.log_warn("app", "Service worker and appcache not available");
90
+ this.log_warn("app", "Service worker not available");
81
91
  this.load();
82
92
  }
83
93
  },
@@ -114,6 +124,7 @@ HTMLAppBootstrapper.prototype = {
114
124
  }, function HTMLAppBootstrapper_preflightLoadError(e){
115
125
  bootstrapper.error = e;
116
126
  bootstrapper.setStatus(HTMLAppBootstrapper.STATUS.preflightLoadError);
127
+ bootstrapper.reportError(e);
117
128
  });
118
129
  },
119
130
 
@@ -153,6 +164,7 @@ HTMLAppBootstrapper.prototype = {
153
164
  this.linkStylesheets();
154
165
  window.addEventListener('error', this);
155
166
  window.addEventListener('unhandledrejection', this);
167
+ this.log_debug("boot", "including " + this.appSrc.length + " scripts");
156
168
  this.includeAppSrc(this.appSrc.shift());
157
169
  },
158
170
 
@@ -169,6 +181,9 @@ HTMLAppBootstrapper.prototype = {
169
181
 
170
182
  includeAppSrc: function(src){
171
183
  var bootstrapper = this;
184
+ if (!this.app.debug){
185
+ this.log_debug("boot", "including " + src);
186
+ }
172
187
  this.include(src, true, function HTMLAppBootstrapper_appScriptLoaded(){
173
188
  if (bootstrapper.appSrc.length){
174
189
  bootstrapper.includeAppSrc(bootstrapper.appSrc.shift());
@@ -178,6 +193,7 @@ HTMLAppBootstrapper.prototype = {
178
193
  }, function HTMLAppBootstrapper_appScriptLoadError(e){
179
194
  bootstrapper.error = e;
180
195
  bootstrapper.setStatus(HTMLAppBootstrapper.STATUS.appLoadError);
196
+ bootstrapper.reportError(e);
181
197
  });
182
198
  },
183
199
 
@@ -199,6 +215,7 @@ HTMLAppBootstrapper.prototype = {
199
215
  this.log_error("app", "Error calling main(): " + e.message);
200
216
  this.error = e;
201
217
  this.setStatus(HTMLAppBootstrapper.STATUS.appRunError);
218
+ this.reportError(e);
202
219
  }
203
220
  },
204
221
 
@@ -209,6 +226,7 @@ HTMLAppBootstrapper.prototype = {
209
226
  }else{
210
227
  this.error = error;
211
228
  this.setStatus(HTMLAppBootstrapper.STATUS.appLaunchFailure);
229
+ this.reportError(error);
212
230
  }
213
231
  return;
214
232
  }
@@ -258,22 +276,51 @@ HTMLAppBootstrapper.prototype = {
258
276
 
259
277
  setStatus: function(status){
260
278
  if (status !== HTMLAppBootstrapper.STATUS.appCrashed){
261
- this.log_info("status", this.status + " -> " + status);
279
+ this.log_debug("boot", this.status + " -> " + status);
262
280
  }
263
281
  this.status = status;
264
- var bootstrapper = this;
265
- if (status === HTMLAppBootstrapper.STATUS.appRunning || status === HTMLAppBootstrapper.STATUS.appLaunched || status === HTMLAppBootstrapper.STATUS.appCrashed){
266
- if (this.statusDispatchTimeoutID !== null){
267
- clearTimeout(this.statusDispatchTimeoutID);
268
- this.statusDispatchTimeoutID = null;
269
- }
270
- bootstrapper.onstatus();
271
- }else if (this.statusDispatchTimeoutID === null){
272
- this.statusDispatchTimeoutID = setTimeout(function HTMLAppBootstrapper_dispatchStatusChanged(){
273
- bootstrapper.statusDispatchTimeoutID = null;
274
- bootstrapper.onstatus();
275
- }, this.minStatusInterval);
282
+ switch (this.status){
283
+ case HTMLAppBootstrapper.STATUS.preflightLoading:
284
+ case HTMLAppBootstrapper.STATUS.preflightRunning:
285
+ case HTMLAppBootstrapper.STATUS.appLoading:
286
+ case HTMLAppBootstrapper.STATUS.appRunning:
287
+ case HTMLAppBootstrapper.STATUS.updating:
288
+ this._resetTimeout();
289
+ break;
290
+ case HTMLAppBootstrapper.STATUS.checkingForUpdate:
291
+ case HTMLAppBootstrapper.STATUS.installing:
292
+ this._resetTimeout();
293
+ this._startLongLoadInterval();
294
+ break;
295
+ case HTMLAppBootstrapper.STATUS.preflightFailedChecks:
296
+ case HTMLAppBootstrapper.STATUS.preflightLoadError:
297
+ case HTMLAppBootstrapper.STATUS.updateError:
298
+ case HTMLAppBootstrapper.STATUS.appLoadError:
299
+ case HTMLAppBootstrapper.STATUS.appRunError:
300
+ case HTMLAppBootstrapper.STATUS.appLaunchFailure:
301
+ case HTMLAppBootstrapper.STATUS.appRequiresNoOtherInstances:
302
+ case HTMLAppBootstrapper.STATUS.appLaunched:
303
+ this.rootElement.ownerDocument.removeEventListener("visibilitychange", this);
304
+ this._cancelTimeout();
305
+ this._cancelLongLoadInterval();
306
+ break;
307
+ case HTMLAppBootstrapper.STATUS.appCrashed:
308
+ break;
276
309
  }
310
+ this.onstatus(this.status);
311
+ },
312
+
313
+ _hasSeenProgress: false,
314
+
315
+ setProgress: function(loaded, total){
316
+ if (!this._hasSeenProgress){
317
+ this._hasSeenProgress = true;
318
+ this._cancelTimeout();
319
+ }
320
+ if (loaded === total){
321
+ this._resetTimeout();
322
+ }
323
+ this.onprogress(loaded, total);
277
324
  },
278
325
 
279
326
  handleEvent: function(e){
@@ -284,12 +331,14 @@ HTMLAppBootstrapper.prototype = {
284
331
  if (window.applicationCache && e.target === window.applicationCache){
285
332
  this.error = e.error;
286
333
  this.setStatus(HTMLAppBootstrapper.STATUS.updateError);
334
+ this.reportError(e.error);
287
335
  return;
288
336
  }
289
337
  if (e.target === this.serviceWorker){
290
338
  if (!this._hasLoaded){
291
339
  this.error = e.error;
292
340
  this.setStatus(HTMLAppBootstrapper.STATUS.updateError);
341
+ this.reportError(e.error);
293
342
  return;
294
343
  }
295
344
  }
@@ -312,6 +361,91 @@ HTMLAppBootstrapper.prototype = {
312
361
  // TODO:
313
362
  },
314
363
 
364
+ event_visibilitychange: function(e){
365
+ if (this.rootElement.ownerDocument.visibilityState === "hidden"){
366
+ this.onhidden();
367
+ }
368
+ },
369
+
370
+ // MARK: - Timeouts
371
+
372
+ timeoutInterval: 30,
373
+ _timeoutID: null,
374
+
375
+ _resetTimeout: function(){
376
+ if (this._timeoutID !== null){
377
+ clearTimeout(this._timeoutID);
378
+ }
379
+ var bootstrapper = this;
380
+ this._timeoutID = setTimeout(function(){
381
+ bootstrapper._handleTimeout();
382
+ }, this.timeoutInterval * 1000);
383
+ },
384
+
385
+ _cancelTimeout: function(){
386
+ if (this._timeoutID !== null){
387
+ clearTimeout(this._timeoutID);
388
+ this._timeoutID = null;
389
+ }
390
+ },
391
+
392
+ _handleTimeout: function(){
393
+ this._timeoutID = null;
394
+ this.ontimeout();
395
+ window.location.reload();
396
+ },
397
+
398
+ _longLoadIntervalID: null,
399
+ _longLoadCount: 0,
400
+ longLoadInterval: 5,
401
+
402
+ _startLongLoadInterval: function(){
403
+ if (this._longLoadIntervalID === null){
404
+ var bootstrapper = this;
405
+ this._longLoadIntervalID = setInterval(function(){
406
+ bootstrapper._handleLongLoadInterval();
407
+ }, this.longLoadInterval * 1000);
408
+ }
409
+ },
410
+
411
+ _cancelLongLoadInterval: function(){
412
+ if (this._longLoadIntervalID !== null){
413
+ clearInterval(this._longLoadIntervalID);
414
+ this._longLoadIntervalID = null;
415
+ }
416
+ },
417
+
418
+ _handleLongLoadInterval: function(){
419
+ this.onlongload(this._longLoadCount);
420
+ ++this._longLoadCount;
421
+ },
422
+
423
+ _currentTimestamp: function(){
424
+ return Date.now() / 1000;
425
+ },
426
+
427
+ _generateRandomID: function(){
428
+ var data = new Uint8Array(20);
429
+ var i, l;
430
+ if (window.crypto){
431
+ window.crypto.getRandomValues(data);
432
+ }else{
433
+ for (i = 0, l = data.length; i < l; ++i){
434
+ data[i] = Math.floor(Math.random() * 256);
435
+ }
436
+ }
437
+ var id = "";
438
+ var h;
439
+ for (i = 0, l = data.length; i < l; ++i){
440
+ h = data[i].toString(16);
441
+ if (h.length == 1){
442
+ id += "0";
443
+ }
444
+ id += h;
445
+ }
446
+ return id;
447
+ },
448
+
315
449
  // MARK: - Service Worker
316
450
 
317
451
  serviceWorkerRegistration: null,
@@ -327,6 +461,7 @@ HTMLAppBootstrapper.prototype = {
327
461
  bootstrapper.log_debug("serviceWorker", "Checking for update");
328
462
  bootstrapper.setStatus(HTMLAppBootstrapper.STATUS.checkingForUpdate);
329
463
  registration.addEventListener('updatefound', bootstrapper);
464
+ bootstrapper.log_debug("serviceWorker", "calling update()");
330
465
  return registration.update();
331
466
  }
332
467
  bootstrapper.log_debug("serviceWorker", "No registration found");
@@ -334,22 +469,30 @@ HTMLAppBootstrapper.prototype = {
334
469
  bootstrapper.log_debug("serviceWorker", "Registering");
335
470
  return container.register(bootstrapper.serviceWorkerSrc);
336
471
  }).then(function(registration){
337
- bootstrapper.serviceWorkerRegistration = registration;
472
+ bootstrapper.registration = registration;
473
+ bootstrapper.log_debug("serviceWorker", "update() or register() resolved");
474
+ bootstrapper.log_debug("serviceWorker", "registration.installing = " + (registration.installing ? "ServiceWorker" : "null"));
475
+ bootstrapper.log_debug("serviceWorker", "registration.waiting = " + (registration.waiting ? "ServiceWorker" : "null"));
476
+ bootstrapper.log_debug("serviceWorker", "registration.active = " + (registration.active ? "ServiceWorker" : "null"));
338
477
  if (registration.installing){
478
+ bootstrapper.serviceWorker = registration.installing;
479
+ bootstrapper.serviceWorker.addEventListener('statechange', bootstrapper);
480
+ bootstrapper.log_debug("serviceWorker", "Installing registration found (state = " + bootstrapper.serviceWorker.state + ")");
339
481
  if (bootstrapper.status === HTMLAppBootstrapper.STATUS.checkingForUpdate){
340
482
  bootstrapper.log_debug("serviceWorker", "Installing Update");
341
483
  bootstrapper.setStatus(HTMLAppBootstrapper.STATUS.updating);
342
484
  }else{
343
485
  bootstrapper.log_debug("serviceWorker", "Installing for the first time");
344
486
  }
345
- bootstrapper.serviceWorker = registration.installing;
346
487
  }else if (registration.waiting){
347
- bootstrapper.log_debug("serviceWorker", "Waiting registration found. Activating");
348
488
  bootstrapper.serviceWorker = registration.waiting;
489
+ bootstrapper.serviceWorker.addEventListener('statechange', bootstrapper);
490
+ bootstrapper.log_debug("serviceWorker", "Waiting registration found (state = " + bootstrapper.serviceWorker.state + "). Activating");
349
491
  bootstrapper.serviceWorker.postMessage({type: "activate"});
350
492
  }else if (registration.active){
351
493
  bootstrapper.serviceWorker = registration.active;
352
- bootstrapper.log_debug("serviceWorker", "Active registration found");
494
+ bootstrapper.serviceWorker.addEventListener('statechange', bootstrapper);
495
+ bootstrapper.log_debug("serviceWorker", "Active registration found (state = " + bootstrapper.serviceWorker.state + ")");
353
496
  if (bootstrapper.serviceWorker.state == 'activating'){
354
497
  bootstrapper.log_debug("serviceWorker", "Activating");
355
498
  }else{
@@ -360,15 +503,18 @@ HTMLAppBootstrapper.prototype = {
360
503
  bootstrapper.log_error("serviceWorker", "Nothing to install???");
361
504
  throw new Error("No service worker found on registration");
362
505
  }
363
- bootstrapper.serviceWorker.addEventListener('statechange', bootstrapper);
364
506
  }).catch(function(error){
365
507
  bootstrapper.log_warn("serviceWorker", "Error with registration: " + error.message);
366
508
  if (container.controller){
509
+ bootstrapper.serviceWorker = container.controller;
367
510
  bootstrapper.log_debug("serviceWorker", "Proceeding with cached version");
368
511
  bootstrapper.load();
512
+ bootstrapper.error = error;
513
+ bootstrapper.reportError(error);
369
514
  }else{
370
515
  bootstrapper.error = error;
371
516
  bootstrapper.setStatus(HTMLAppBootstrapper.STATUS.updateError);
517
+ bootstrapper.reportError(error);
372
518
  }
373
519
  });
374
520
  },
@@ -382,8 +528,11 @@ HTMLAppBootstrapper.prototype = {
382
528
  }else if (worker.state === "activated"){
383
529
  this.log_debug("serviceWorker", "Activated");
384
530
  this.load();
531
+ }else{
532
+ this.log_debug("serviceWorker", "statechange " + worker.state);
385
533
  }
386
534
  }else{
535
+ this.log_debug("serviceWorker", "other statechange " + worker.state);
387
536
  if (worker.state == "installed"){
388
537
  this.log_debug("serviceWorker", "Update Installed");
389
538
  if (this.application !== null){
@@ -403,15 +552,18 @@ HTMLAppBootstrapper.prototype = {
403
552
  if ((e.data.loaded % d === 0) || (e.data.loaded === e.data.total)){
404
553
  this.log_debug("serviceWorker", "Progress " + e.data.loaded + '/' + e.data.total);
405
554
  }
406
- this.onprogress(e.data.loaded, e.data.total);
555
+ this.setProgress(e.data.loaded, e.data.total);
407
556
  }else if (e.data.type == 'error'){
408
557
  this.log_warn("serviceWorker", "Install error: " + e.data.message);
409
558
  if (container.controller){
559
+ this.serviceWorker = worker;
410
560
  this.log_debug("serviceWorker", "Proceeding with cached version");
411
561
  this.load();
412
562
  }else{
413
- this.error = new Error(e.data.message);
563
+ var error = new Error(e.data.message);
564
+ this.error = error;
414
565
  this.setStatus(HTMLAppBootstrapper.STATUS.updateError);
566
+ this.reportError(error);
415
567
  }
416
568
  }
417
569
  }else{
@@ -431,7 +583,7 @@ HTMLAppBootstrapper.prototype = {
431
583
  // But in Firefox, the update() promise doesn't resolve until after
432
584
  // the install is complete, so this is where we have to detect an update starting.
433
585
  if (this.serviceWorker === null){
434
- this.log_debug("servicewWorker", "Update found before service worker set");
586
+ this.log_debug("serviceWorker", "Update found before service worker set");
435
587
  this.setStatus(HTMLAppBootstrapper.STATUS.updating);
436
588
  this.serviceWorker = worker;
437
589
  }
@@ -447,69 +599,14 @@ HTMLAppBootstrapper.prototype = {
447
599
  this.serviceWorker = worker;
448
600
  if (!this.serviceWorker){
449
601
  this.log_warn("serviceWorker", "null installer");
450
- this.error = new Error("null installing worker");
602
+ var error = new Error("null installing worker");
603
+ this.error = error;
451
604
  this.setStatus(HTMLAppBootstrapper.STATUS.updateError);
605
+ this.reportError(error);
452
606
  }
453
607
  }
454
608
  },
455
609
 
456
- // MARK: - Appcache
457
-
458
- _installUsingAppcache: function(appcache){
459
- this._isAppcacheInstalled = window.applicationCache.status !== window.applicationCache.UNCACHED;
460
- appcache.addEventListener('checking', this);
461
- appcache.addEventListener('downloading', this);
462
- appcache.addEventListener('noupdate', this);
463
- appcache.addEventListener('progress', this);
464
- appcache.addEventListener('error', this);
465
- appcache.addEventListener('updateready', this);
466
- appcache.addEventListener('cached', this);
467
- appcache.addEventListener('obsoleted', this);
468
- },
469
-
470
- event_checking: function(e){
471
- this.log_info("appcache", 'checking app cache');
472
- this.setStatus(HTMLAppBootstrapper.STATUS.checkingForUpdate);
473
- },
474
-
475
- event_downloading: function(e){
476
- this.log_info("appcache", 'cache downloading');
477
- this.setStatus(this._isAppcacheInstalled ? HTMLAppBootstrapper.STATUS.updating : HTMLAppBootstrapper.STATUS.installing);
478
- },
479
-
480
- event_noupdate: function(e){
481
- this.log_info("appcache", 'no update');
482
- this.load();
483
- },
484
-
485
- event_progress: function(e){
486
- if (e.lengthComputable){
487
- this.onprogress(e.loaded, e.total);
488
- }else{
489
- // this.log_info("appcache", 'progress is not length computable');
490
- }
491
- },
492
-
493
- event_cached: function(e){
494
- this.log_info("appcache", 'first version cached');
495
- this.load();
496
- },
497
-
498
- event_updateready: function(e){
499
- this.log_info("appcache", 'new version available');
500
- if (this._hasLoaded){
501
- // TODO: communicate to app
502
- }else{
503
- e.target.swapCache();
504
- this.load();
505
- }
506
- },
507
-
508
- event_obsoleted: function(e){
509
- this.log_info("appcache", 'cache obsoleted');
510
- this.load();
511
- },
512
-
513
610
  // MARK: - Logging
514
611
 
515
612
  log_debug: function(category, message){
@@ -537,7 +634,7 @@ HTMLAppBootstrapper.prototype = {
537
634
  level: level,
538
635
  subsystem: "boot",
539
636
  category: category,
540
- timestamp: Date.now() / 1000,
637
+ timestamp: this._currentTimestamp(),
541
638
  message: message,
542
639
  args: []
543
640
  };
@@ -546,6 +643,9 @@ HTMLAppBootstrapper.prototype = {
546
643
 
547
644
  _recordLog: function(record){
548
645
  this.logs.push(record);
646
+ if (this.app.debug){
647
+ console[record.level](HTMLAppBootstrapper.formatter.log(record));
648
+ }
549
649
  this.onlog(record);
550
650
  },
551
651
 
@@ -566,6 +666,15 @@ HTMLAppBootstrapper.prototype = {
566
666
 
567
667
  _getLogsJSLog: function(){
568
668
  return window.JSLog.getRecords();
669
+ },
670
+
671
+ // MARK: - Telemetry
672
+
673
+ reportError: function(error, fingerprint){
674
+ if (this.app.debug){
675
+ console.error(error);
676
+ }
677
+ this.onerror(error);
569
678
  }
570
679
 
571
680
  };
@@ -172,7 +172,6 @@
172
172
  statusLabel.innerHTML = "Unable to Start Application";
173
173
  detailsLabel.style.opacity = 1;
174
174
  detailsLabel.innerHTML = "Apologies, but we couldn't start the application. Don't worry, it wasn't anything you did, and it isn't something we expect to happen under normal usage.<br>We've notified our engineers of the problem, and the best thing you can do is try again soon.";
175
- reportError(bootstrapper.error, bootstrapper.getLogs());
176
175
  break;
177
176
  case S.appRequiresNoOtherInstances:
178
177
  statusLabel.style.opacity = 1;
@@ -209,15 +208,7 @@
209
208
  progressBar.style.width = (loaded * 100 / total) + '%';
210
209
  progress.setAttribute("aria-valuenow", Math.round(loaded * 100 / total));
211
210
  };
212
- if (app.debug){
213
- bootstrapper.onlog = function(record){
214
- console[record.level](HTMLAppBootstrapper.formatter.log(record));
215
- };
216
- }
217
- var reportError = function(error, logs){
218
- if (app.debug){
219
- console.error(error);
220
- }
211
+ bootstrapper.onerror = function(error){
221
212
  };
222
213
  window.JSKIT_PREFLIGHT_CONTEXT = bootstrapper;
223
214
  bootstrapper.run();
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "node": ">=10.10.0"
10
10
  },
11
11
  "name": "@breakside/jskit",
12
- "version": "2025.9.0",
12
+ "version": "2025.10.0",
13
13
  "license": "SEE LICENSE IN LICENSE.txt",
14
14
  "files": [
15
15
  "*"