@xrmforge/devkit 0.7.33 → 0.7.34

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.
@@ -308,6 +308,24 @@ for (const c of expandedMany<Contact>(account, 'contact_customer_accounts')) { c
308
308
  const c = account['primarycontactid'] as { fullname?: string };
309
309
  ```
310
310
 
311
+ **Polymorphic lookups (`customerid`, `ownerid`, `regardingobjectid`) need a target-qualified
312
+ `$expand` name, not the blank `XxxNavigationProperties` value.** A polymorphic lookup can resolve to
313
+ several entity types, so Dataverse exposes one single-valued navigation property PER target, named
314
+ `<lookup>_<targetentity>` (e.g. `customerid_account`, `customerid_contact`). The generated
315
+ `XxxNavigationProperties` enum carries only the blank logical name (`customerid`) - correct for
316
+ `parseLookup`, `@odata.bind` and `$unsafe`, but NOT a valid `$expand` path for a polymorphic lookup.
317
+ Name the target-qualified property directly and read it back with that same key (the blank value
318
+ stays correct for `parseLookup` on the parent record):
319
+
320
+ ```typescript
321
+ // customerid (account | contact): expand the concrete target, not AccountNav.CustomerId
322
+ const order = await Xrm.WebApi.retrieveRecord(EntityNames.SalesOrder, id,
323
+ selectExpand([SalesOrderFields.Name], `customerid_account($select=${AccountFields.Name})`));
324
+ const customer = expanded<Account>(order, 'customerid_account'); // target-qualified key
325
+ ```
326
+
327
+ (Single-target lookups like `primarycontactid` keep using the blank `XxxNavigationProperties` value.)
328
+
311
329
  ### 6b. Web API response typing with generated Entity interfaces
312
330
 
313
331
  Always type Web API responses with generated Entity interfaces. Never access properties with `as string` casts.
@@ -866,6 +884,34 @@ npx xrmforge build # IIFE bundles for D365
866
884
  npx xrmforge build --watch # Watch mode (~10ms rebuilds)
867
885
  ```
868
886
 
887
+ ## HTML WebResources (standalone HTML pages)
888
+
889
+ An HTML WebResource (a standalone page in a form IFrame or the sitemap, not a form
890
+ script) follows the same TypeScript-first split as a form script:
891
+
892
+ - **TypeScript module** (`src/<name>.ts`): all logic, built as its own esbuild IIFE
893
+ entry with its own `globalName` (e.g. `Contoso.ShowImages`) - exactly like a form-script entry.
894
+ - **HTML shell** (`src/<name>.html`): markup only, plus a `<script src="...">` to the
895
+ built JS and a small call to the exported init function (`Contoso.ShowImages.init()`). No
896
+ inline code, no jQuery. esbuild does NOT build the `.html` (static asset); deploy it as its
897
+ own WebResource next to the built JS, which it references via `<script src>`.
898
+ - **Xrm access:** an embedded HTML WebResource reaches the form API via `window.parent.Xrm`
899
+ (it gets no `executionContext` parameter, unlike a form script). The form script may also
900
+ inject the context actively (export a `setClientApiContext(...)` the form script calls on open).
901
+
902
+ `xrmforge.config.json` entry - same shape as any other module:
903
+
904
+ ```json
905
+ "showimages": { "input": "./src/showimages.ts", "namespace": "Contoso.ShowImages", "out": "ShowImages.js" }
906
+ ```
907
+
908
+ All the MANDATORY rules above still apply to the `.ts` logic (typedForm where a form context
909
+ is available, EntityNames/Fields enums, `select`/`parseLookup`, generated Entity interfaces, no
910
+ raw OData strings). **Modernize legacy HTML WebResources instead of porting 1:1:** `Xrm.WebApi`
911
+ instead of the old `OrganizationData.svc`/2011 endpoints, `fetch` instead of jQuery `$.ajax`,
912
+ `Xrm`/`formContext` instead of `Xrm.Page`, generated enums instead of raw OData strings, no
913
+ `document.all`.
914
+
869
915
  ## Drift Check (generated/ vs. live environment)
870
916
 
871
917
  `generated/` is a snapshot of the Dataverse environment. When the environment
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xrmforge/devkit",
3
- "version": "0.7.33",
3
+ "version": "0.7.34",
4
4
  "description": "Build orchestration and project tooling for Dynamics 365 WebResources",
5
5
  "keywords": [
6
6
  "dynamics-365",