Execution model
Every generated script is a single self-contained async IIFE pasted into the browser console of the target site. That choice drives everything else.
Why the browser console
The operator's own session is the credential. There are no stored secrets, no app principals, no consent grants — and therefore nothing to rotate, leak or clean up. The cost is that an interactive operator must be present; that is accepted deliberately (it is not unattended CI).
The site guard
Pasting a deployment script into the wrong site must be impossible to
get wrong silently. Every script starts by comparing
window.location and _spPageContextInfo against the site URL baked in
at build time — origin and server-relative path both — and aborts before
any request if they differ. It then logs the operator identity
("Running as ...") so the console transcript records who ran what.
HTTP transport
All REST traffic rides a shared transport
(_http.js.j2):
- Throttle-aware. SharePoint Online throttles bursts (HTTP 429) and
sheds load (503). Every request honours
Retry-After, else backs off exponentially, before surfacing the final response to the caller's own error handling. - Instrumented. A
DEBUGflag (defaultfalse, editable in the pasted script — no rebuild) prints per-request timing lines and, for deploy.js, a per-phase seconds table beforeDONE. TheDONEline always carries elapsed seconds and total request count. - Read-safe by construction. The transport partial contains no write helper; write headers live in a separate partial included only by the scripts that write. The read-only assessment script can therefore be audited as read-only from its text alone.
Request digests come from a cached getDigest() that refreshes 60
seconds before FormDigestTimeoutSeconds expiry — per-call safety at
roughly one contextinfo POST per run.
Phases and lanes
deploy.js runs the phase sequence from the phases manifest: PREPARE (preflight, security principals, enrolment, maintenance unseal), STRUCTURE (lists, deferred lookups, indexes, defaults), PRESENTATION (views, forms), PROTECTION (seal, ACLs), DATA (seeds).
Within a phase, parallelism follows the lane rule: SharePoint stores fields and views in the list schema, and concurrent schema writes to the same list race into save conflicts — but different lists are fully independent. So the unit of parallelism is the list: work is grouped into lanes by list, items within a lane run strictly sequentially, lanes run concurrently (bounded). Never parallelise same-list schema writes.
Idempotence and reconciliation
Rerunning any script must be safe:
- Existing objects are adopted, never assumed. A list or field that already exists is adopted only when its immutable shape (type kind, lookup target, formula, base template) provably matches the declaration. A mismatch fails that object closed with a named error — explicit migration beats silent mutation.
- Mutable settings are reconciled narrowly. Only drifted declared settings are sent (narrow MERGE), and every write is read back and compared before the phase reports success.
- Content is never touched. Undeclared views, user rows and user
columns are user content; deploy.js reconciles only what the mapping
declares (the one exception is
reconcile: exactACL mode, which the mapping must opt into).
Operator-facing output
The console transcript is the run record, so its readability is a
feature. Live finding, generalised: probes whose "absent" answer is a
404 or 400 paint red in the console and operators read them as failures
— so existence checks ride always-200 enumerations instead of per-item
probes wherever possible, and errors carry SharePoint's own
error.message.value rather than a bare status code.