@breakside/jskit 2025.33.0 → 2025.36.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 (40) 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/HTMLBuilder.js +42 -2
  11. package/Node/HTMLProjectServer.js +209 -0
  12. package/Node/io.breakside.jskit-bundle.js +2 -2
  13. package/Node/jskit +1 -0
  14. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  15. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  16. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  17. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  18. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  19. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  20. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  21. package/Root/Frameworks/DOM/Info.yaml +1 -1
  22. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  23. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  24. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  25. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  26. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  27. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  28. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  29. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  30. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  31. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  32. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  33. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  34. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  35. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  36. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  37. package/Root/Frameworks/UIKit/UIContainerView.js +17 -1
  38. package/Root/Frameworks/UIKit/UIDraggingSession.js +4 -0
  39. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  40. 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.33.0",
4
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
12
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
6
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
14
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
4
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
11
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
6
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
13
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
4
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
12
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
6
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
14
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
4
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
12
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
6
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
14
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
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.33.0",
4
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
11
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
12
12
  }
@@ -17,6 +17,7 @@
17
17
  // #import "Builder.js"
18
18
  // #import "Resources.js"
19
19
  // #import "JavascriptCompilation.js"
20
+ // #import "HTMLProjectServer.js"
20
21
  'use strict';
21
22
 
22
23
  // buildURL
@@ -48,7 +49,8 @@ JSClass("HTMLBuilder", Builder, {
48
49
  'env': {default: null, help: "A file with environmental variables for this build"},
49
50
  'tls-cert': {default: null, help: "The SSL cert to use for the debug build"},
50
51
  'tls-key': {default: null, help: "The SSL key to use for the debug build"},
51
- 'zoneinfo': {default: null, help: "The build host path to timezone data files"}
52
+ 'zoneinfo': {default: null, help: "The build host path to timezone data files"},
53
+ 'server': {kind: "flag", help: "Run an http server (required --debug) (implies --no-docker)"}
52
54
  },
53
55
 
54
56
  needsDockerBuild: true,
@@ -81,6 +83,11 @@ JSClass("HTMLBuilder", Builder, {
81
83
  this.arguments['http-port'] = this.project.info.HTTPPort || 80;
82
84
  }
83
85
  }
86
+ if (this.arguments.server){
87
+ if (!this.debug){
88
+ throw new Error("--server requires --debug");
89
+ }
90
+ }
84
91
  this.wwwJavascriptPaths = [];
85
92
  this.wwwResourcePaths = [];
86
93
  this.preflightFeatures = new Set();
@@ -135,6 +142,7 @@ JSClass("HTMLBuilder", Builder, {
135
142
  await this.bundleInfo();
136
143
  await this.buildDocker();
137
144
  await this.finish();
145
+ await this.runServer();
138
146
  },
139
147
 
140
148
  findImports: async function(){
@@ -1099,7 +1107,7 @@ JSClass("HTMLBuilder", Builder, {
1099
1107
  var url = this.buildURL.appendingPathComponent("Dockerfile");
1100
1108
  await this.fileManager.createFileAtURL(url, dockerfile);
1101
1109
 
1102
- if (this.arguments['no-docker']){
1110
+ if (this.arguments['no-docker'] || this.arguments.server){
1103
1111
  return;
1104
1112
  }
1105
1113
 
@@ -1167,6 +1175,38 @@ JSClass("HTMLBuilder", Builder, {
1167
1175
  });
1168
1176
  },
1169
1177
 
1178
+ // -----------------------------------------------------------------------
1179
+ // MARK: - Server
1180
+
1181
+ httpServer: null,
1182
+
1183
+ runServer: async function(){
1184
+ if (!this.debug){
1185
+ return;
1186
+ }
1187
+ if (!this.arguments.server){
1188
+ return;
1189
+ }
1190
+ if (this.options.server){
1191
+ if (this.httpServer === null){
1192
+ this.httpServer = HTMLProjectServer.initWithProject(this.project, this.wwwURL, this.fileManager, this.printer);
1193
+ this.httpServer.port = this.arguments['http-port'];
1194
+ if (this.arguments['tls-cert']){
1195
+ this.httpServer.tlsCertificateFileURL = JSURL.initWithString(this.arguments['tls-cert'], this.workingDirectoryURL);
1196
+ if (this.arguments['tls-key']){
1197
+ this.httpServer.tlsKeyFileURL = JSURL.initWithString(this.arguments['tls-key'], this.workingDirectoryURL);
1198
+ }
1199
+ }
1200
+ this.httpServer.run();
1201
+ }
1202
+ }else{
1203
+ if (this.httpServer !== null){
1204
+ await this.httpServer.stop();
1205
+ this.httpServer = null;
1206
+ }
1207
+ }
1208
+ }
1209
+
1170
1210
  });
1171
1211
 
1172
1212
  var getenv = function(name, defaultValue){
@@ -0,0 +1,209 @@
1
+ // #import Foundation
2
+ "use strict";
3
+
4
+ const http = require("http");
5
+ const https = require("https");
6
+ const os = require("os");
7
+ const fs = require("fs");
8
+
9
+ const logger = JSLog("jskit", "http");
10
+
11
+ JSClass("HTMLProjectServer", JSObject, {
12
+
13
+ initWithProject: function(project, wwwURL, fileManager, printer){
14
+ this.project = project;
15
+ this.wwwURL = wwwURL;
16
+ this.fileManager = fileManager;
17
+ this.printer = printer;
18
+ this.contentTypesByExtension = {
19
+ ".html": "text/html",
20
+ ".css": "text/css",
21
+ ".js": "application/javascript",
22
+ ".json": "application/json",
23
+ ".xml": "text/xml",
24
+ ".txt": "text/plain",
25
+ ".gif": "image/gif",
26
+ ".jpeg": "image/jpeg",
27
+ ".jpg": "image/jpeg",
28
+ ".png": "image/png",
29
+ ".svg": "image/svg+xml",
30
+ ".svgz": "image/svg+xml",
31
+ ".pdf": "application/pdf",
32
+ ".woff": "application/font-woff",
33
+ ".ttf": "application/x-font-ttf",
34
+ ".webmanifest": "application/manifest+json",
35
+ ".appcache": "text/cache-manifest",
36
+ };
37
+ },
38
+
39
+ project: null,
40
+ wwwURL: null,
41
+ fileManager: null,
42
+ printer: null,
43
+
44
+ port: null,
45
+ tlsCertificateFileURL: null,
46
+ tlsKeyFileURL: null,
47
+ contentTypesByExtension: null,
48
+
49
+ _nodeHttpServer: null,
50
+
51
+ run: async function(){
52
+ var scheme = "http";
53
+ if (this.tlsCertificateFileURL !== null && this.tlsKeyFileURL !== null){
54
+ scheme = "https";
55
+ var options = {
56
+ cert: await this.fileManager.contentsAtURL(this.tlsCertificateFileURL),
57
+ key: await this.fileManager.contentsAtURL(this.tlsKeyFileURL)
58
+ };
59
+ this._nodeHttpServer = https.createServer(options, this._handleNodeRequest.bind(this));
60
+ if (this.port === null){
61
+ this.port = 443;
62
+ }
63
+ }else{
64
+ this._nodeHttpServer = http.createServer(this._handleNodeRequest.bind(this));
65
+ if (this.port === null){
66
+ this.port = 80;
67
+ }
68
+ }
69
+ this._nodeHttpServer.listen(this.port);
70
+ var networkInterfaces = os.networkInterfaces();
71
+ var networkInterface;
72
+ var address;
73
+ for (var name in networkInterfaces){
74
+ networkInterface = networkInterfaces[name];
75
+ for (var i = 0, l = networkInterface.length; i < l; ++i){
76
+ address = networkInterface[i];
77
+ if (address.family == "IPv4"){
78
+ this.printer.print(String.initWithFormat("HTTP server listening on %s://%s:%d", scheme, address.address, this.port), true, true);
79
+ }
80
+ }
81
+ }
82
+ },
83
+
84
+ stop: function(completion, target){
85
+ if (!completion){
86
+ completion = Promise.completion();
87
+ }
88
+ if (this._nodeHttpServer === null){
89
+ completion.call(target);
90
+ }else{
91
+ this.printer.print("HTTP server closing, waiting for outstanding requests to close", true, true);
92
+ var server = this;
93
+ this._nodeHttpServer.close(function(){
94
+ this.printer.print("HTTP server closed", true, true);
95
+ completion.call(target);
96
+ server._nodeHttpServer = null;
97
+ });
98
+ }
99
+ return completion.promise;
100
+ },
101
+
102
+ alwaysExpires: JSLazyInitProperty(() => "Thu, 01 Jan 1970 00:00:01 GMT"),
103
+ neverExpires: JSLazyInitProperty(() => "Thu, 31 Dec 2037 23:55:55 GMT"),
104
+
105
+ _handleNodeRequest: async function(nodeRequest, nodeResponse){
106
+ let statusCode = null;
107
+ let headers = {};
108
+ let filePath = null;
109
+ try{
110
+ let url = JSURL.initWithString(nodeRequest.url);
111
+ if (url !== null){
112
+ url.standardize();
113
+ if (url.pathComponents.length === 0){
114
+ url.path = "/";
115
+ }
116
+ let method = nodeRequest.method.toUpperCase();
117
+ if (method === "GET"){
118
+ if (url.pathComponents[0] === "/"){
119
+ if (url.pathComponents.length === 1){
120
+ url.appendPathComponent("index.html");
121
+ }
122
+ let statePaths = this.project.info.UIHTMLStatePaths || [];
123
+ for (let path of statePaths){
124
+ path = path.trim();
125
+ if (path.endsWith("/")){
126
+ if (url.path.startsWith(path)){
127
+ statusCode = 302;
128
+ headers.Location = "/#" + url.path;
129
+ break;
130
+ }
131
+ }else{
132
+ if (url.path === path){
133
+ statusCode = 302;
134
+ headers.Location = "/#" + url.path;
135
+ break;
136
+ }
137
+ }
138
+ }
139
+ if (statusCode === null){
140
+ if (url.pathComponents.length === 2){
141
+ if (url.pathComponents[1] === "index.html"){
142
+ headers.Expires = this.alwaysExpires;
143
+ headers["Cache-Control"] = "no-cache";
144
+ }else if (url.pathComponents[1] === "manifest.appcache"){
145
+ headers.Expires = this.alwaysExpires;
146
+ headers["Cache-Control"] = "no-cache";
147
+ }else if (url.pathComponents[1] === "service-worker.js"){
148
+ headers.Expires = this.alwaysExpires;
149
+ headers["Cache-Control"] = "no-cache";
150
+ }else if (url.pathComponents[1] === "HTMLAppBootstrapper.js"){
151
+ headers.Expires = this.alwaysExpires;
152
+ headers["Cache-Control"] = "no-cache";
153
+ }
154
+ }else if (url.pathComponents[1] === "Resources"){
155
+ headers.Expires = this.neverExpires;
156
+ headers["Cache-Control"] = "max-age=315360000"; // ~10 years
157
+ headers.Etag = url.lastPathComponent;
158
+ }
159
+ let fileURL = this.wwwURL.appendingPathComponents(url.pathComponents.slice(1));
160
+ let exists = await this.fileManager.itemExistsAtURL(fileURL);
161
+ if (exists){
162
+ let attributes = await this.fileManager.attributesOfItemAtURL(fileURL);
163
+ headers["Content-Type"] = this.contentTypesByExtension[url.fileExtension] || "application/octet-stream";
164
+ headers["Content-Length"] = attributes.size;
165
+ filePath = this.fileManager.pathForURL(fileURL);
166
+ statusCode = 200;
167
+ }else{
168
+ statusCode = 404;
169
+ }
170
+ }
171
+ }else{
172
+ statusCode = 404;
173
+ }
174
+ }else{
175
+ statusCode = 405;
176
+ }
177
+ }else{
178
+ statusCode = 404;
179
+ }
180
+ }catch (e){
181
+ logger.error("Error handling request: %{error}", e);
182
+ statusCode = 500;
183
+ }
184
+
185
+ try{
186
+ try{
187
+ nodeResponse.writeHead(statusCode, headers);
188
+ }catch (e){
189
+ logger.error("Error sending response headers: %{error}", e);
190
+ nodeResponse.writeHead(500);
191
+ }
192
+ nodeResponse.flushHeaders();
193
+
194
+ if (statusCode === 200 && filePath !== null){
195
+ let fp = fs.createReadStream(filePath);
196
+ fp.pipe(nodeResponse); // pipe will call this._nodeResponse.end(), which is the same as calling complete()
197
+ }else{
198
+ nodeResponse.end();
199
+ }
200
+ if (statusCode >= 400){
201
+ logger.warn("%d %{public} %{public}", statusCode, nodeRequest.method, nodeRequest.url);
202
+ }
203
+ }catch (e){
204
+ nodeRequest.socket.destroy();
205
+ logger.error("Error sending response: %{error}", e);
206
+ }
207
+ },
208
+
209
+ });
@@ -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.33.0",
6
+ "JSBundleVersion": "2025.36.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": "7264e2a6b69613cbb01445c6bdd34898e0fa2216"
13
+ "GitRevision": "542d9c51b5664a6f0e1a92bdb945534a06c433ea"
14
14
  },
15
15
  "Resources": [
16
16
  {
package/Node/jskit CHANGED
@@ -188,6 +188,7 @@ require("./Builder.js");
188
188
  require("./JavascriptCompilation.js");
189
189
  require("./FrameworkBuilder.js");
190
190
  require("./NodeBuilder.js");
191
+ require("./HTMLProjectServer.js");
191
192
  require("./HTMLBuilder.js");
192
193
  require("./APIBuilder.js");
193
194
  require("./TestBuilder.js");
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.APIKit
3
- JSBundleVersion: 2025.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.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.33.0
3
+ JSBundleVersion: 2025.36.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -85,7 +85,17 @@ JSClass("UIContainerView", UIView, {
85
85
  getIntrinsicSize: function(){
86
86
  var contentSize;
87
87
  if (this._contentView !== null){
88
- contentSize = this._contentView.intrinsicSize;
88
+ contentSize = JSSize(this._contentView.intrinsicSize);
89
+ if (contentSize.width !== UIView.noIntrinsicSize){
90
+ if (this._maximumContentSize.width > 0 && this._maximumContentSize.width < contentSize.width){
91
+ contentSize.width = this._maximumContentSize.width;
92
+ }
93
+ }
94
+ if (contentSize.height !== UIView.noIntrinsicSize){
95
+ if (this._maximumContentSize.height > 0 && this._maximumContentSize.height < contentSize.height){
96
+ contentSize.height = this._maximumContentSize.height;
97
+ }
98
+ }
89
99
  }else{
90
100
  contentSize = JSSize(UIView.noIntrinsicSize, UIView.noIntrinsicSize);
91
101
  }
@@ -103,6 +113,12 @@ JSClass("UIContainerView", UIView, {
103
113
  maxSize.width < Number.MAX_VALUE ? maxSize.width - this._contentInsets.width : Number.MAX_VALUE,
104
114
  maxSize.height < Number.MAX_VALUE ? maxSize.height - this._contentInsets.height : Number.MAX_VALUE
105
115
  );
116
+ if (this._maximumContentSize.width > 0 && this._maximumContentSize.width < maxContentSize.width){
117
+ maxContentSize.width = this._maximumContentSize.width - this.contentInsets.width;
118
+ }
119
+ if (this._maximumContentSize.height > 0 && this._maximumContentSize.height < maxContentSize.height){
120
+ maxContentSize.height = this._maximumContentSize.height - this.contentInsets.height;
121
+ }
106
122
  this._contentView.sizeToFitSize(maxContentSize);
107
123
  this.bounds = JSRect(0, 0, this._contentView.bounds.size.width + this._contentInsets.width, this._contentView.bounds.size.height + this._contentInsets.height);
108
124
  }
@@ -83,6 +83,10 @@ JSClass("UIDraggingSession", JSObject, {
83
83
  },
84
84
 
85
85
  cancel: function(){
86
+ this.operation = UIDragOperation.none;
87
+ if (this.source !== null){
88
+ this.source.draggingSessionEnded(this, this.operation);
89
+ }
86
90
  if (this.destination){
87
91
  this.destination.draggingExited(this);
88
92
  }
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKitTesting
3
- JSBundleVersion: 2025.33.0
3
+ JSBundleVersion: 2025.36.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "node": ">=10.10.0"
10
10
  },
11
11
  "name": "@breakside/jskit",
12
- "version": "2025.33.0",
12
+ "version": "2025.36.0",
13
13
  "license": "SEE LICENSE IN LICENSE.txt",
14
14
  "files": [
15
15
  "*"