Browse Source

wasmjob: started fetch demo

mattias 3 years ago
parent
commit
c5aab46aa4

+ 236 - 8
demo/wasienv/dom/job_web.pas

@@ -341,6 +341,10 @@ Type
   TJSWindowOrWorkerGlobalScope = class;
   IJSCacheStorage = interface;
   TJSCacheStorage = class;
+  IJSResponse = interface;
+  TJSResponse = class;
+  IJSHeaders = interface;
+  TJSHeaders = class;
   TJSEventListenerOptions = TJOB_Dictionary;
   TJSAddEventListenerOptions = TJOB_Dictionary;
   TJSGetRootNodeOptions = TJOB_Dictionary;
@@ -379,6 +383,7 @@ Type
   TJSChannelPixelLayout = TJOB_Dictionary;
   TJSImageBitmapOptions = TJOB_Dictionary;
   TJSMultiCacheQueryOptions = TJOB_Dictionary;
+  TJSResponseInit = TJOB_Dictionary;
   TVisibilityState = UnicodeString;
   TDocumentAutoplayPolicy = UnicodeString;
   TFlashClassification = UnicodeString;
@@ -404,6 +409,8 @@ Type
   TColorSpaceConversion = UnicodeString;
   TServiceWorkerState = UnicodeString;
   TCacheStorageNamespace = UnicodeString;
+  TResponseType = UnicodeString;
+  THeadersGuardEnum = UnicodeString;
   TEventListener = function (event: IJSEvent): Boolean of object;
   TEventHandlerNonNull = function (event: IJSEvent): TJOB_JSValue of object;
   TEventHandler = TEventHandlerNonNull;
@@ -438,6 +445,8 @@ Type
   TImagePixelLayout = IJSArray; // array of TJSChannelPixelLayout
   // Union of Blob, Directory, USVString
   TFormDataEntryValue = TJOB_JSValue;
+  // Union of sequence, record
+  THeadersInit = TJOB_JSValue;
 
   { --------------------------------------------------------------------
     TJSEventListenerOptions
@@ -842,6 +851,16 @@ Type
     cacheName: UnicodeString;
   end;
 
+  { --------------------------------------------------------------------
+    TJSResponseInit
+    --------------------------------------------------------------------}
+
+  TJSResponseInitRec = record
+    status: Word;
+    statusText: UnicodeString;
+    headers: THeadersInit;
+  end;
+
   { --------------------------------------------------------------------
     TJSEventTarget
     --------------------------------------------------------------------}
@@ -2590,7 +2609,7 @@ Type
   TJSRangeDynArray = IJSArray; // array of TJSRange
 
   IJSSelection = interface(IJSObject)
-    ['{A4886FB0-977D-3F5E-AEF5-E54883662A9A}']
+    ['{522D4098-FC2A-35AF-A806-57B88516481A}']
     function _GetanchorNode: IJSNode;
     function _GetanchorOffset: LongWord;
     function _GetfocusNode: IJSNode;
@@ -2621,7 +2640,6 @@ Type
     procedure deleteFromDocument;
     function containsNode(aNode: IJSNode; allowPartialContainment: Boolean): Boolean; overload;
     function containsNode(aNode: IJSNode): Boolean; overload;
-    function toString: UnicodeString;
     procedure modify(const alter: UnicodeString; const aDirection: UnicodeString; const aGranularity: UnicodeString);
     function toStringWithFormat(const aFormatType: UnicodeString; aFlags: LongWord; aWrapColumn: Integer): UnicodeString;
     procedure addSelectionListener(aNewListener: IJSnsISelectionListener);
@@ -2675,7 +2693,6 @@ Type
     procedure deleteFromDocument;
     function containsNode(aNode: IJSNode; allowPartialContainment: Boolean): Boolean; overload;
     function containsNode(aNode: IJSNode): Boolean; overload;
-    function toString: UnicodeString;
     procedure modify(const alter: UnicodeString; const aDirection: UnicodeString; const aGranularity: UnicodeString);
     function toStringWithFormat(const aFormatType: UnicodeString; aFlags: LongWord; aWrapColumn: Integer): UnicodeString;
     procedure addSelectionListener(aNewListener: IJSnsISelectionListener);
@@ -4585,6 +4602,98 @@ Type
     class function Cast(Intf: IJSObject): IJSCacheStorage;
   end;
 
+  { --------------------------------------------------------------------
+    TJSResponse
+    --------------------------------------------------------------------}
+
+  IJSResponse = interface(IJSObject)
+    ['{1C2F3A3B-95B8-328C-AF98-F7FD8DBAB69C}']
+    function _Gettype_: TResponseType;
+    function _Geturl: UnicodeString;
+    function _Getredirected: Boolean;
+    function _Getstatus: Word;
+    function _Getok: Boolean;
+    function _GetstatusText: UnicodeString;
+    function _Getheaders: IJSHeaders;
+    function _GethasCacheInfoChannel: Boolean;
+    function error: IJSResponse;
+    function redirect(const aUrl: UnicodeString; aStatus: Word): IJSResponse; overload;
+    function redirect(const aUrl: UnicodeString): IJSResponse; overload;
+    function clone: IJSResponse;
+    function cloneUnfiltered: IJSResponse;
+    function json: IJSPromise; overload;
+    property type_: TResponseType read _Gettype_;
+    property url: UnicodeString read _Geturl;
+    property redirected: Boolean read _Getredirected;
+    property status: Word read _Getstatus;
+    property ok: Boolean read _Getok;
+    property statusText: UnicodeString read _GetstatusText;
+    property headers: IJSHeaders read _Getheaders;
+    property hasCacheInfoChannel: Boolean read _GethasCacheInfoChannel;
+  end;
+
+  { TJSResponse }
+
+  TJSResponse = class(TJSObject,IJSResponse)
+  Private
+    function _Gettype_: TResponseType;
+    function _Geturl: UnicodeString;
+    function _Getredirected: Boolean;
+    function _Getstatus: Word;
+    function _Getok: Boolean;
+    function _GetstatusText: UnicodeString;
+    function _Getheaders: IJSHeaders;
+    function _GethasCacheInfoChannel: Boolean;
+  Public
+    function error: IJSResponse;
+    function redirect(const aUrl: UnicodeString; aStatus: Word): IJSResponse; overload;
+    function redirect(const aUrl: UnicodeString): IJSResponse; overload;
+    function clone: IJSResponse;
+    function cloneUnfiltered: IJSResponse;
+    function json: IJSPromise; overload;
+    class function Cast(Intf: IJSObject): IJSResponse;
+    property type_: TResponseType read _Gettype_;
+    property url: UnicodeString read _Geturl;
+    property redirected: Boolean read _Getredirected;
+    property status: Word read _Getstatus;
+    property ok: Boolean read _Getok;
+    property statusText: UnicodeString read _GetstatusText;
+    property headers: IJSHeaders read _Getheaders;
+    property hasCacheInfoChannel: Boolean read _GethasCacheInfoChannel;
+  end;
+
+  { --------------------------------------------------------------------
+    TJSHeaders
+    --------------------------------------------------------------------}
+
+  TUnicodeStringDynArrayDynArray = IJSArray; // array of TUnicodeStringDynArray
+
+  IJSHeaders = interface(IJSObject)
+    ['{C0BCC7DF-3747-3F31-83C9-BDEB874234DC}']
+    function _Getguard: THeadersGuardEnum;
+    procedure _Setguard(const aValue: THeadersGuardEnum);
+    procedure append(const aName: UnicodeString; const aValue: UnicodeString);
+    procedure delete(const aName: UnicodeString);
+    function get(const aName: UnicodeString): UnicodeString;
+    function has(const aName: UnicodeString): Boolean;
+    procedure set_(const aName: UnicodeString; const aValue: UnicodeString);
+    property guard: THeadersGuardEnum read _Getguard write _Setguard;
+  end;
+
+  TJSHeaders = class(TJSObject,IJSHeaders)
+  Private
+    function _Getguard: THeadersGuardEnum;
+    procedure _Setguard(const aValue: THeadersGuardEnum);
+  Public
+    procedure append(const aName: UnicodeString; const aValue: UnicodeString);
+    procedure delete(const aName: UnicodeString);
+    function get(const aName: UnicodeString): UnicodeString;
+    function has(const aName: UnicodeString): Boolean;
+    procedure set_(const aName: UnicodeString; const aValue: UnicodeString);
+    class function Cast(Intf: IJSObject): IJSHeaders;
+    property guard: THeadersGuardEnum read _Getguard write _Setguard;
+  end;
+
   { --------------------------------------------------------------------
     TJSNode
     --------------------------------------------------------------------}
@@ -4865,6 +4974,7 @@ Type
     procedure cancelIdleCallback(aHandle: LongWord);
     function getRegionalPrefsLocales: TUnicodeStringDynArray;
     function getWebExposedLocales: TUnicodeStringDynArray;
+    function fetch(const URL: UnicodeString): IJSPromise;
     property window: IJSWindowProxy read _Getwindow;
     property self_: IJSWindowProxy read _Getself_;
     property document: IJSDocument read _Getdocument;
@@ -5044,6 +5154,8 @@ Type
     property localStorage: IJSStorage read _GetlocalStorage;
   end;
 
+  { TJSWindow }
+
   TJSWindow = class(TJSEventTarget,IJSWindow)
   Private
     function _Getwindow: IJSWindowProxy;
@@ -5199,6 +5311,7 @@ Type
     procedure cancelIdleCallback(aHandle: LongWord);
     function getRegionalPrefsLocales: TUnicodeStringDynArray;
     function getWebExposedLocales: TUnicodeStringDynArray;
+    function fetch(const URL: UnicodeString): IJSPromise;
     class function Cast(Intf: IJSObject): IJSWindow;
     property window: IJSWindowProxy read _Getwindow;
     property self_: IJSWindowProxy read _Getself_;
@@ -11807,11 +11920,6 @@ begin
   Result:=InvokeJSBooleanResult('containsNode',[aNode]);
 end;
 
-function TJSSelection.toString: UnicodeString;
-begin
-  Result:=InvokeJSUnicodeStringResult('toString',[]);
-end;
-
 procedure TJSSelection.modify(const alter: UnicodeString; const aDirection: UnicodeString; const aGranularity: UnicodeString);
 begin
   InvokeJSNoResult('modify',[alter,aDirection,aGranularity]);
@@ -13902,6 +14010,121 @@ begin
   Result:=TJSCacheStorage.JOBCast(Intf);
 end;
 
+function TJSResponse._Gettype_: TResponseType;
+begin
+  Result:=ReadJSPropertyUnicodeString('type');
+end;
+
+function TJSResponse._Geturl: UnicodeString;
+begin
+  Result:=ReadJSPropertyUnicodeString('url');
+end;
+
+function TJSResponse._Getredirected: Boolean;
+begin
+  Result:=ReadJSPropertyBoolean('redirected');
+end;
+
+function TJSResponse._Getstatus: Word;
+begin
+  Result:=ReadJSPropertyLongInt('status');
+end;
+
+function TJSResponse._Getok: Boolean;
+begin
+  Result:=ReadJSPropertyBoolean('ok');
+end;
+
+function TJSResponse._GetstatusText: UnicodeString;
+begin
+  Result:=ReadJSPropertyUnicodeString('statusText');
+end;
+
+function TJSResponse._Getheaders: IJSHeaders;
+begin
+  Result:=ReadJSPropertyObject('headers',TJSHeaders) as IJSHeaders;
+end;
+
+function TJSResponse._GethasCacheInfoChannel: Boolean;
+begin
+  Result:=ReadJSPropertyBoolean('hasCacheInfoChannel');
+end;
+
+function TJSResponse.error: IJSResponse;
+begin
+  Result:=InvokeJSObjectResult('error',[],TJSResponse) as IJSResponse;
+end;
+
+function TJSResponse.redirect(const aUrl: UnicodeString; aStatus: Word): IJSResponse; overload;
+begin
+  Result:=InvokeJSObjectResult('redirect',[aUrl,aStatus],TJSResponse) as IJSResponse;
+end;
+
+function TJSResponse.redirect(const aUrl: UnicodeString): IJSResponse; overload;
+begin
+  Result:=InvokeJSObjectResult('redirect',[aUrl],TJSResponse) as IJSResponse;
+end;
+
+function TJSResponse.clone: IJSResponse;
+begin
+  Result:=InvokeJSObjectResult('clone',[],TJSResponse) as IJSResponse;
+end;
+
+function TJSResponse.cloneUnfiltered: IJSResponse;
+begin
+  Result:=InvokeJSObjectResult('cloneUnfiltered',[],TJSResponse) as IJSResponse;
+end;
+
+function TJSResponse.json: IJSPromise;
+begin
+  Result:=InvokeJSObjectResult('json',[],TJSPromise) as IJSPromise;
+end;
+
+class function TJSResponse.Cast(Intf: IJSObject): IJSResponse;
+begin
+  Result:=TJSResponse.JOBCast(Intf);
+end;
+
+function TJSHeaders._Getguard: THeadersGuardEnum;
+begin
+  Result:=ReadJSPropertyUnicodeString('guard');
+end;
+
+procedure TJSHeaders._Setguard(const aValue: THeadersGuardEnum);
+begin
+  WriteJSPropertyUnicodeString('guard',aValue);
+end;
+
+procedure TJSHeaders.append(const aName: UnicodeString; const aValue: UnicodeString);
+begin
+  InvokeJSNoResult('append',[aName,aValue]);
+end;
+
+procedure TJSHeaders.delete(const aName: UnicodeString);
+begin
+  InvokeJSNoResult('delete',[aName]);
+end;
+
+function TJSHeaders.get(const aName: UnicodeString): UnicodeString;
+begin
+  Result:=InvokeJSUnicodeStringResult('get',[aName]);
+end;
+
+function TJSHeaders.has(const aName: UnicodeString): Boolean;
+begin
+  Result:=InvokeJSBooleanResult('has',[aName]);
+end;
+
+procedure TJSHeaders.set_(const aName: UnicodeString; const aValue: UnicodeString);
+begin
+  InvokeJSNoResult('set',[aName,aValue]);
+end;
+
+class function TJSHeaders.Cast(Intf: IJSObject): IJSHeaders;
+begin
+  Result:=TJSHeaders.JOBCast(Intf);
+end;
+
 function TJSNode._GetnodeType: Word;
 begin
   Result:=ReadJSPropertyLongInt('nodeType');
@@ -14802,6 +15025,11 @@ begin
   Result:=InvokeJSObjectResult('getWebExposedLocales',[],TJSArray) as TUnicodeStringDynArray;
 end;
 
+function TJSWindow.fetch(const URL: UnicodeString): IJSPromise;
+begin
+  Result:=InvokeJSObjectResult('fetch',[URL],TJSPromise) as IJSPromise;
+end;
+
 class function TJSWindow.Cast(Intf: IJSObject): IJSWindow;
 begin
   Result:=TJSWindow.JOBCast(Intf);

+ 267 - 4
demo/wasienv/dom/job_web.webidl

@@ -3768,8 +3768,7 @@ interface Selection {
   [Throws]
   boolean   containsNode(Node node,
                          optional boolean allowPartialContainment = false);
-  /* Mattias: added toString */
-  stringifier DOMString toString ();
+// Mattias: stringifier DOMString toString ();
 };
 
 // Additional methods not currently in the spec
@@ -4079,8 +4078,8 @@ interface Range : AbstractRange {
   [Throws]
   boolean intersectsNode(Node node);
 
-  [Throws, BinaryName="ToString"]
-  stringifier;
+// Mattias:  [Throws, BinaryName="ToString"]
+//  stringifier;
 };
 
 // http://domparsing.spec.whatwg.org/#dom-range-createcontextualfragment
@@ -7431,3 +7430,267 @@ interface FormData {
   void set(USVString name, USVString value);
   iterable<USVString, FormDataEntryValue>;
 };
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-obj
+ *
+ */
+
+// Still unclear what should be subclassed.
+// https://github.com/slightlyoff/ServiceWorker/issues/189
+[Func="ServiceWorkerVisible",
+ // FIXME(nsm): Bug 1113522. This is exposed to satisfy webidl constraints, but it won't actually work.
+ Exposed=(Window,Worker)]
+interface ServiceWorker : EventTarget {
+  readonly attribute USVString scriptURL;
+  readonly attribute ServiceWorkerState state;
+
+  attribute EventHandler onstatechange;
+
+// Mattias:  [Throws]
+//  void postMessage(any message, sequence<object> transferable);
+// Mattias:  [Throws]
+//  void postMessage(any message, optional StructuredSerializeOptions options = {});
+};
+
+ServiceWorker includes AbstractWorker;
+
+enum ServiceWorkerState {
+  // https://github.com/w3c/ServiceWorker/issues/1162
+  "parsed",
+
+  "installing",
+  "installed",
+  "activating",
+  "activated",
+  "redundant"
+};
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Exposed=(Window,Worker)]
+interface mixin AbstractWorker {
+    attribute EventHandler onerror;
+};
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is:
+ * https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin
+ * https://fetch.spec.whatwg.org/#fetch-method
+ * https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
+ * https://w3c.github.io/ServiceWorker/#self-caches
+ */
+
+// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin
+[Exposed=(Window,Worker)]
+interface mixin WindowOrWorkerGlobalScope {
+  [Replaceable] readonly attribute USVString origin;
+  readonly attribute boolean crossOriginIsolated;
+
+  [Throws, NeedsCallerType]
+  void reportError(any e);
+
+  // base64 utility methods
+  [Throws]
+  DOMString btoa(DOMString btoa);
+  [Throws]
+  DOMString atob(DOMString atob);
+
+  // timers
+  // NOTE: We're using overloads where the spec uses a union.  Should
+  // be black-box the same.
+  [Throws]
+  long setTimeout(Function handler, optional long timeout = 0, any... arguments);
+  [Throws]
+  long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
+  void clearTimeout(optional long handle = 0);
+  [Throws]
+  long setInterval(Function handler, optional long timeout = 0, any... arguments);
+  [Throws]
+  long setInterval(DOMString handler, optional long timeout = 0, any... unused);
+  void clearInterval(optional long handle = 0);
+
+// Mattias:  // microtask queuing
+//  void queueMicrotask(VoidFunction callback);
+
+  // ImageBitmap
+// Mattias:  [Throws]
+//  Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage,
+//                                         optional ImageBitmapOptions aOptions = {});
+// Mattias:  [Throws]
+//  Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage,
+//                                         long aSx, long aSy, long aSw, long aSh,
+//                                         optional ImageBitmapOptions aOptions = {});
+
+  // structured cloning
+// Mattias:  [Throws]
+//  any structuredClone(any value, optional StructuredSerializeOptions options = {});
+};
+
+// https://fetch.spec.whatwg.org/#fetch-method
+partial interface mixin WindowOrWorkerGlobalScope {
+// Mattias:  [NewObject, NeedsCallerType]
+//  Promise<Response> fetch(RequestInfo input, optional RequestInit init = {});
+};
+
+// https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
+partial interface mixin WindowOrWorkerGlobalScope {
+  readonly attribute boolean isSecureContext;
+};
+
+// http://w3c.github.io/IndexedDB/#factory-interface
+partial interface mixin WindowOrWorkerGlobalScope {
+   // readonly attribute IDBFactory indexedDB;
+// Mattias:   [Throws]
+//   readonly attribute IDBFactory? indexedDB;
+};
+
+// https://w3c.github.io/ServiceWorker/#self-caches
+partial interface mixin WindowOrWorkerGlobalScope {
+  [Throws, Func="nsGlobalWindowInner::CachesEnabled", SameObject]
+  readonly attribute CacheStorage caches;
+};
+
+// https://wicg.github.io/scheduling-apis/#ref-for-windoworworkerglobalscope-scheduler
+partial interface mixin WindowOrWorkerGlobalScope {
+// Mattias:  [Replaceable, Pref="dom.enable_web_task_scheduling", SameObject]
+//  readonly attribute Scheduler scheduler;
+};
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://w3c.github.io/ServiceWorker/#cachestorage-interface
+ */
+
+interface Principal;
+
+[Exposed=(Window,Worker),
+ Func="nsGlobalWindowInner::CachesEnabled"]
+interface CacheStorage {
+  [Throws, ChromeOnly]
+  constructor(CacheStorageNamespace namespace, Principal principal);
+
+// Mattias:  [NewObject]
+//  Promise<Response> match(RequestInfo request, optional MultiCacheQueryOptions options = {});
+// Mattias:  [NewObject]
+//  Promise<boolean> has(DOMString cacheName);
+// Mattias:  [NewObject]
+//  Promise<Cache> open(DOMString cacheName);
+// Mattias:  [NewObject]
+//  Promise<boolean> delete(DOMString cacheName);
+// Mattias:  [NewObject]
+//  Promise<sequence<DOMString>> keys();
+};
+
+dictionary MultiCacheQueryOptions : CacheQueryOptions {
+  DOMString cacheName;
+};
+
+// chrome-only, gecko specific extension
+enum CacheStorageNamespace {
+  "content", "chrome"
+};
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://fetch.spec.whatwg.org/#response-class
+ */
+
+[Exposed=(Window,Worker)]
+interface Response {
+  // This should be constructor(optional BodyInit... but BodyInit doesn't
+  // include ReadableStream yet because we don't want to expose Streams API to
+  // Request.
+  [Throws]
+  constructor(optional (Blob or BufferSource or FormData or URLSearchParams or ReadableStream or USVString)? body = null,
+              optional ResponseInit init = {});
+
+  [NewObject] static Response error();
+  [Throws,
+   NewObject] static Response redirect(USVString url, optional unsigned short status = 302);
+
+  readonly attribute ResponseType type;
+
+  readonly attribute USVString url;
+  readonly attribute boolean redirected;
+  readonly attribute unsigned short status;
+  readonly attribute boolean ok;
+  readonly attribute ByteString statusText;
+  [SameObject, BinaryName="headers_"] readonly attribute Headers headers;
+
+  [Throws,
+   NewObject] Response clone();
+
+  [ChromeOnly, NewObject, Throws] Response cloneUnfiltered();
+
+  // For testing only.
+  [ChromeOnly] readonly attribute boolean hasCacheInfoChannel;
+};
+// Mattias: Response includes Body;
+
+// This should be part of Body but we don't want to expose body to request yet.
+// See bug 1387483.
+partial interface Response {
+// Mattias:  [GetterThrows]
+//  readonly attribute ReadableStream? body;
+};
+
+dictionary ResponseInit {
+  unsigned short status = 200;
+  ByteString statusText = "";
+  HeadersInit headers;
+};
+
+enum ResponseType { "basic", "cors", "default", "error", "opaque", "opaqueredirect" };
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://fetch.spec.whatwg.org/#headers-class
+ */
+
+typedef (sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit;
+
+enum HeadersGuardEnum {
+  "none",
+  "request",
+  "request-no-cors",
+  "response",
+  "immutable"
+};
+
+[Exposed=(Window,Worker)]
+interface Headers {
+  [Throws]
+  constructor(optional HeadersInit init);
+
+  [Throws] void append(ByteString name, ByteString value);
+  [Throws] void delete(ByteString name);
+  [Throws] ByteString? get(ByteString name);
+  [Throws] boolean has(ByteString name);
+  [Throws] void set(ByteString name, ByteString value);
+  iterable<ByteString, ByteString>;
+
+  // Used to test different guard states from mochitest.
+  // Note: Must be set prior to populating headers or will throw.
+  [ChromeOnly, SetterThrows] attribute HeadersGuardEnum guard;
+};

+ 108 - 0
demo/wasienv/fetch/BrowserFetch1.lpi

@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="BrowserFetch1"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="4">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="Pas2JSProject" Value="1"/>
+      <Item2 Name="PasJSLocation" Value="BrowserFetch1"/>
+      <Item3 Name="PasJSWebBrowserProject" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="BrowserFetch1.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="index.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+      <Unit>
+        <Filename Value="../../../packages/job/job_browser.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JOB_Browser"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../../../packages/job/job_shared.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JOB_Shared"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="BrowserFetch1"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../../../packages/job"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8
+-Jirtl.js
+-Jc
+-Jminclude
+-dVerboseJOB"/>
+      <OtherDefines Count="1">
+        <Define0 Value="VerboseJOB"/>
+      </OtherDefines>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 50 - 0
demo/wasienv/fetch/BrowserFetch1.lpr

@@ -0,0 +1,50 @@
+program BrowserFetch1;
+
+{$mode objfpc}
+
+uses
+  BrowserConsole, JS, Classes, SysUtils, Web, WasiEnv, WasiHostApp, JOB_Browser;
+
+Type
+
+  { TMyApplication }
+
+  TMyApplication = class(TBrowserWASIHostApplication)
+  Private
+    FWADomBridge : TJSObjectBridge;
+    function OnBeforeStart(Sender: TObject;
+      aDescriptor: TWebAssemblyStartDescriptor): Boolean;
+  Public
+    constructor Create(aOwner : TComponent); override;
+    procedure DoRun; override;
+  end;
+
+function TMyApplication.OnBeforeStart(Sender: TObject;
+  aDescriptor: TWebAssemblyStartDescriptor): Boolean;
+begin
+  FWADomBridge.WasiExports:=aDescriptor.Exported;
+  Result:=true;
+end;
+
+constructor TMyApplication.Create(aOwner: TComponent);
+begin
+  inherited Create(aOwner);
+  FWADomBridge:=TJSObjectBridge.Create(WasiEnvironment);
+  RunEntryFunction:='_initialize';
+end;
+
+procedure TMyApplication.DoRun;
+begin
+  // Your code here
+  StartWebAssembly('WasiFetch1.wasm',true,@OnBeforeStart);
+end;
+
+var
+  Application : TMyApplication;
+
+begin
+  Application:=TMyApplication.Create(nil);
+  Application.Initialize;
+  Application.Run;
+end.
+

+ 4 - 0
demo/wasienv/fetch/Example.json

@@ -0,0 +1,4 @@
+{
+  "name":"Example",
+  "value":3
+}

+ 90 - 0
demo/wasienv/fetch/WasiFetch1.lpi

@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="WasiFetch1"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="WasiFetch1.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../dom/job_web.pas"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JOB_Web"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../dom/job_js.pas"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JOB_JS"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../../../packages/job/job_shared.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JOB_Shared"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="WasiFetch1.wasm" ApplyConventions="False"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../dom;../../../packages/job"/>
+      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <CodeGeneration>
+      <TargetCPU Value="wasm32"/>
+      <TargetOS Value="wasi"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+      </Debugging>
+      <Options>
+        <ExecutableType Value="Library"/>
+      </Options>
+    </Linking>
+    <Other>
+      <OtherDefines Count="1">
+        <Define0 Value="VerboseInvokeJSArgs"/>
+      </OtherDefines>
+      <CompilerPath Value="/usr/lib/fpc/3.3.1/ppcrosswasm32"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 149 - 0
demo/wasienv/fetch/WasiFetch1.lpr

@@ -0,0 +1,149 @@
+library WasiFetch1;
+
+{$mode objfpc}
+{$h+}
+{$codepage UTF8}
+
+uses
+  SysUtils, JOB_Shared, JOB_Web, JOB_JS;
+
+type
+
+  { TWasmApp }
+
+  TWasmApp = class
+  private
+    function OnAccepted(const aValue: TJOB_JSValue): TJOB_JSValue;
+    function OnButtonClick(Event: IJSEvent): boolean;
+    function OnJSONFailed(const aValue: TJOB_JSValue): TJOB_JSValue;
+    function OnJSONReceived(const aValue: TJOB_JSValue): TJOB_JSValue;
+    function OnRejected(const aValue: TJOB_JSValue): TJOB_JSValue;
+  public
+    procedure Run;
+  end;
+
+{ TApplication }
+
+function TWasmApp.OnAccepted(const aValue: TJOB_JSValue): TJOB_JSValue;
+var
+  Obj: IJSObject;
+  Response: IJSResponse;
+  p: IJSPromise;
+begin
+  Result:=TJOB_Boolean.Create(false);
+  writeln('TWasmApp.OnAccepted ',aValue.AsString);
+  if aValue.Kind<>jjvkObject then
+  begin
+    writeln('TWasmApp.OnAccepted Expected object, but got '+JOB_JSValueKindNames[aValue.Kind]);
+    exit;
+  end;
+  Obj:=TJOB_Object(aValue).Value;
+  if Obj=nil then
+  begin
+    writeln('TWasmApp.OnAccepted Expected object, but got nil');
+    exit;
+  end;
+
+  Response:=TJSResponse.Cast(Obj);
+  writeln('TWasmApp.OnAccepted Response: ok=',Response.ok);
+  writeln('TWasmApp.OnAccepted Response: status=',Response.status);
+  writeln('TWasmApp.OnAccepted Response: statusText="',Response.statusText,'"');
+  writeln('TWasmApp.OnAccepted Response: redirected=',Response.redirected);
+  writeln('TWasmApp.OnAccepted Response: URL="',Response.url,'"');
+
+  p:=Response.InvokeJSObjectResult('json',[],TJSPromise) as IJSPromise;
+  p._then(@OnJSONReceived,@OnJSONFailed);
+
+  TJOB_Boolean(Result).Value:=true;
+end;
+
+function TWasmApp.OnButtonClick(Event: IJSEvent): boolean;
+var
+  p: IJSPromise;
+begin
+  writeln('TWasmApp.OnButtonClick ');
+  if Event=nil then ;
+
+  JSWindow.Alert('You triggered TWasmApp.OnButtonClick');
+
+  p:=JSWindow.InvokeJSObjectResult('fetch',['Example.json'],TJSPromise) as IJSPromise;
+  p._then(@OnAccepted,@OnRejected);
+  //JSWindow.fetch('Example.json')._then(@OnAccepted,@OnRejected);
+  Result:=true;
+end;
+
+function TWasmApp.OnJSONFailed(const aValue: TJOB_JSValue): TJOB_JSValue;
+begin
+  Result:=TJOB_Boolean.Create(true);
+end;
+
+function TWasmApp.OnJSONReceived(const aValue: TJOB_JSValue): TJOB_JSValue;
+var
+  Obj: IJSObject;
+begin
+  Result:=TJOB_Boolean.Create(true);
+
+  if aValue.Kind<>jjvkObject then
+  begin
+    writeln('TWasmApp.OnJSONReceived Expected object, but got '+JOB_JSValueKindNames[aValue.Kind]);
+    exit;
+  end;
+  Obj:=TJOB_Object(aValue).Value;
+  if Obj=nil then
+  begin
+    writeln('TWasmApp.OnJSONReceived Expected object, but got nil');
+    exit;
+  end;
+
+  writeln('TWasmApp.OnJSONReceived Obj.name=',Obj.Properties['name'].AsString);
+  writeln('TWasmApp.OnJSONReceived Obj.value=',Obj.Properties['value'].AsString);
+end;
+
+function TWasmApp.OnRejected(const aValue: TJOB_JSValue): TJOB_JSValue;
+begin
+  writeln('TWasmApp.OnRejected ',aValue.AsString);
+  Result:=TJOB_Boolean.Create(true);
+end;
+
+procedure TWasmApp.Run;
+var
+  JSDiv: IJSHTMLDivElement;
+  JSButton: IJSHTMLButtonElement;
+begin
+  writeln('TWasmApp.Run getElementById "playground" ...');
+  // get reference of HTML element "playground" and type cast it to Div
+  JSDiv:=TJSHTMLDivElement.Cast(JSDocument.getElementById('playground'));
+
+  // create button
+  writeln('TWasmApp.Run create button ...');
+  JSButton:=TJSHTMLButtonElement.Cast(JSDocument.createElement('button'));
+  writeln('TWasmApp.Run set button caption ...');
+  JSButton.InnerHTML:='Click me!';
+
+  // add button to div
+  writeln('TWasmApp.Run add button to div ...');
+  JSDiv.append(JSButton);
+
+  // add event listener OnButtonClick
+  writeln('TWasmApp.Run addEventListener OnButtonClick ...');
+  JSButton.addEventListener('click',@OnButtonClick);
+
+  writeln('TWasmApp.Run END');
+end;
+
+// workaround: fpc wasm does not yet support exporting functions from units
+function JOBCallback(const Func: TJOBCallback; Data, Code: Pointer; Args: PByte): PByte;
+begin
+  Result:=JOB_JS.JOBCallback(Func,Data,Code,Args);
+end;
+
+exports
+  JOBCallback;
+
+var
+  Application: TWasmApp;
+begin
+  Application:=TWasmApp.Create;
+  Application.Run;
+end.
+

File diff suppressed because it is too large
+ 0 - 0
demo/wasienv/fetch/bulma.min.css


+ 52 - 0
demo/wasienv/fetch/index.html

@@ -0,0 +1,52 @@
+
+<!doctype html>
+<html lang="en">
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>FPC-Webassembly Demo creating a button via JOB and fetch Example.json</title>
+  <link href="bulma.min.css" rel="stylesheet">
+  <script src="BrowserFetch1.js"></script>
+  <style>
+
+  .source {
+    /* width: 730px; */
+    margin: -45px auto;
+    font-size: 0.9em;
+  }
+
+  .source-inner {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    /* width: 482px; */
+  }
+  </style>
+</head>
+<body>
+  <div class="section py-4">
+    <h1 class="title is-3">Test Area</h1>
+    <div class="box" id="playground">Playground</div>
+  </div>
+  <div class="section py-4">
+    <h1 class="title is-3">Console output</h1>
+    <div class="box" id="pasjsconsole"></div>
+  </div>
+  <!-- <hr> -->
+  <div class="section">
+    <div class="source">
+      <div class="source-inner">
+        <div>
+          <p>Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> </p>
+          <p>Pas2JS Sources: &nbsp; <a target="new" href="BrowserFetch1.lpr">Pas2JS Program</a></p>
+          <p>Webassembly Sources: &nbsp; <a target="new" href="WasiFetch1.lpr">FPC Program</a></p>
+        </div>
+      </div>
+    </div>
+  </div>
+  <script>
+    rtl.showUncaughtExceptions=true;
+    rtl.run();
+  </script>
+</body>
+</html>

+ 2 - 1
packages/job/job_browser.pp

@@ -505,7 +505,8 @@ var
       begin
         //writeln('TJSObjectBridge called JS Method Call=',aCall,' Data=',aData,' Code=',aCode,' Args=',JSArguments.length);
         Args:=CreateCallbackArgs(View,JSArguments);
-        ResultP:=CallbackHandler(aCall,aData,aCode,Args); // this frees Args
+        ResultP:=CallbackHandler(aCall,aData,aCode,Args); // this frees Args, and may detach View
+        View:=getModuleMemoryDataView();
         //writeln('TJSObjectBridge called Wasm Call=',aCall,' Data=',aData,' Code=',aCode,' ResultP=',ResultP);
         Result:=EatCallbackResult(View,ResultP); // this frees ResultP
         //writeln('TJSObjectBridge Result=',Result);

Some files were not shown because too many files changed in this diff