@ionite/devtools 0.0.24-beta.20261024.48 → 0.0.24-beta.20261024.50
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.
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2 -2
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -200,7 +200,11 @@ type TmRedeemResult = {
|
|
|
200
200
|
expiresAt: string;
|
|
201
201
|
};
|
|
202
202
|
type IoniteTmDriver = {
|
|
203
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Pushes the handle to the App's `integrations/stage` and returns the consent URL, which carries
|
|
205
|
+
* only the opaque `request_uri`.
|
|
206
|
+
*/
|
|
207
|
+
authorizeUrl(): Promise<string>;
|
|
204
208
|
redeem(): Promise<TmRedeemResult>;
|
|
205
209
|
exportConfig(authorization: string): Promise<{
|
|
206
210
|
version: 1;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{spawn as ge}from"node:child_process";import{ACCEPT_JSON as fe}from"@ionite/core";import{JSON_MEDIA_TYPE as pe,readJsonResponse as Y,unexpectedBodySummary as Q}from"@ionite/core";function g(e){return e.replace(/\/+$/,"")}async function D(e,t){if(!e.ok){let r=await Q(e);throw Error(`${t} failed (${e.status})${r.excerpt?`: ${r.excerpt}`:""}`)}return await Y(e)}async function S(e,t,r={}){let n=new Headers(t.headers);if(!n.has("Accept"))n.set("Accept",pe);let a=await(r.fetch??globalThis.fetch)(e,{...t,headers:n,signal:t.signal??AbortSignal.timeout(r.timeoutMs??30000)});if(!a.ok){let s=await Q(a);throw Error(`${r.label??`${t.method??"GET"} ${e}`} failed (${a.status})${s.excerpt?`: ${s.excerpt}`:""}`)}if(a.status===204)return;return await Y(a)}var ye="/api/ionite",he=5000,we=2000;function ke(e){return new Promise((t)=>setTimeout(t,e))}function X(e,t){if(e.exitCode!==null||e.signalCode!==null)return Promise.resolve(!0);return new Promise((r)=>{let n=!1,a=()=>{if(n)return;n=!0,clearTimeout(s),r(!0)},s=setTimeout(()=>{if(n)return;n=!0,e.removeListener("exit",a),r(!1)},t);e.once("exit",a)})}function Z(e){if(e.readyPath)return e.readyPath;return`${g(e.basePath??ye)}/readyz`}async function v(e,t={}){let{livenessPath:r,maxRetries:n=30,retryDelayMs:a=1000,requestTimeoutMs:s=3000}=t,o=Z(t),i;for(let u=0;u<n;u++){try{if(r){let l=await fetch(new URL(r,e),{signal:AbortSignal.timeout(s)});if(!l.ok)throw Error(`liveness returned ${l.status}`)}let d=await fetch(new URL(o,e),{headers:fe,signal:AbortSignal.timeout(s)});if(d.ok)return;i=Error(`readiness returned ${d.status}`)}catch(d){i=d}if(u<n-1)await ke(a)}let c=i instanceof Error?i.message:String(i);throw Error(`App not ready at ${new URL(o,e)} after ${n} attempts: ${c}`)}async function be(e){let{command:t,args:r=[],cwd:n,env:a,baseUrl:s,...o}=e,i=process.platform!=="win32",c=ge(t,r,{cwd:n,env:{...process.env,...a},stdio:"inherit",detached:i});c.on("error",(p)=>{console.error(`Failed to start app under test (${t}):`,p)});let u=(p)=>{try{if(i&&c.pid!==void 0)process.kill(-c.pid,p);else c.kill(p)}catch{}},d=()=>u("SIGKILL");process.once("exit",d);let l=async()=>{if(c.exitCode===null&&c.signalCode===null){if(u("SIGTERM"),!await X(c,he))u("SIGKILL"),await X(c,we)}u("SIGKILL"),process.removeListener("exit",d)};try{await v(s,o)}catch(p){throw await l(),p}return{baseUrl:s,...c.pid===void 0?{}:{pid:c.pid},stop:l}}import{createHash as Te}from"node:crypto";import{readFile as De,writeFile as Se}from"node:fs/promises";import{parse as ee,printParseErrorCode as te}from"jsonc-parser";function re(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function f(e,t){if(!re(e))throw Error(`${t} must be an object`);return e}function R(e,t){if(!Array.isArray(e))throw Error(`${t} must be an array`);return e}function m(e,t){if(typeof e!=="string"||!e.trim())throw Error(`${t} must be a non-empty string`);return e}function h(e,t){if(e===void 0)return;return m(e,t)}function $e(e,t){if(e===void 0)return;if(typeof e!=="boolean")throw Error(`${t} must be a boolean`);return e}function U(e,t){return R(e,t).map((r,n)=>m(r,`${t}[${n}]`))}function M(e,t){let r=new Set;for(let n of e){if(r.has(n.key))throw Error(`Duplicate ${t} key: ${n.key}`);r.add(n.key)}return r}function Pe(e,t){if(e===void 0)return;let r=f(e,t);return{name:m(r.name,`${t}.name`),attribution:h(r.attribution,`${t}.attribution`),sourceUrl:h(r.sourceUrl,`${t}.sourceUrl`)}}function ve(e,t){if(e===void 0)return;let r=f(e,t);return{url:m(r.url,`${t}.url`),attribution:h(r.attribution,`${t}.attribution`),licence:h(r.licence,`${t}.licence`),sourceUrl:h(r.sourceUrl,`${t}.sourceUrl`)}}function N(e,t){let r=f(e,t),n={people:r.people===void 0?void 0:U(r.people,`${t}.people`),orgUnits:r.orgUnits===void 0?void 0:U(r.orgUnits,`${t}.orgUnits`),reportsTo:r.reportsTo===void 0?void 0:U(r.reportsTo,`${t}.reportsTo`)};if(!n.people?.length&&!n.orgUnits?.length&&!n.reportsTo?.length)throw Error(`${t} must select at least one person, org unit, or manager`);return n}function ne(e,t){let r=f(e,t),n;if(r.policies!==void 0){n={};for(let[o,i]of Object.entries(f(r.policies,`${t}.policies`))){let c=f(i,`${t}.policies.${o}`),u=h(c.workflow,`${t}.policies.${o}.workflow`);if(u!==void 0&&u!=="auto"&&u!=="approve"&&u!=="approve-with-justification")throw Error(`${t}.policies.${o}.workflow is not supported`);n[o]={workflow:u,eligible:c.eligible===void 0?void 0:N(c.eligible,`${t}.policies.${o}.eligible`),approvers:c.approvers===void 0?void 0:N(c.approvers,`${t}.policies.${o}.approvers`)}}}let a=r.assignments===void 0?void 0:R(r.assignments,`${t}.assignments`).map((o,i)=>{let c=f(o,`${t}.assignments[${i}]`),u=m(c.subjectKind,`${t}.assignments[${i}].subjectKind`);if(u!=="user"&&u!=="customer")throw Error(`${t}.assignments[${i}].subjectKind is not supported`);return{entitlement:m(c.entitlement,`${t}.assignments[${i}].entitlement`),subjectKind:u,members:N(c.members,`${t}.assignments[${i}].members`)}}),s;if(r.claims!==void 0){s={};for(let[o,i]of Object.entries(f(r.claims,`${t}.claims`))){let c=f(i,`${t}.claims.${o}`);s[o]={groups:U(c.groups,`${t}.claims.${o}.groups`)}}}return{policies:n,assignments:a,claims:s}}function Re(e){let t=M(e.orgUnits,"org unit"),r=M(e.workforce,"workforce person"),n=M(e.customers,"customer"),a=new Set,s=new Set;for(let i of e.orgUnits){if(i.parent&&!t.has(i.parent))throw Error(`Unknown parent org unit: ${i.parent}`);if(i.leader&&!r.has(i.leader))throw Error(`Unknown org unit leader: ${i.leader}`)}for(let i of e.workforce){if(!t.has(i.orgUnit))throw Error(`Unknown org unit for ${i.key}: ${i.orgUnit}`);if(i.manager&&!r.has(i.manager))throw Error(`Unknown manager for ${i.key}: ${i.manager}`);if(a.has(i.employeeNumber))throw Error(`Duplicate workforce employeeNumber: ${i.employeeNumber}`);a.add(i.employeeNumber);let c=i.email.toLowerCase();if(s.has(c))throw Error(`Duplicate dataset email: ${i.email}`);s.add(c)}for(let i of e.customers){let c=i.email.toLowerCase();if(s.has(c))throw Error(`Duplicate dataset email: ${i.email}`);s.add(c)}let o=(i,c,u)=>{for(let d of i.people??[])if(!(u==="customer"?n.has(d):r.has(d)||n.has(d)))throw Error(`${c} references unknown person: ${d}`);if(u==="customer"&&((i.orgUnits?.length??0)>0||(i.reportsTo?.length??0)>0))throw Error(`${c} cannot select customer members by workforce organization`);for(let d of i.orgUnits??[])if(!t.has(d))throw Error(`${c} references unknown org unit: ${d}`);for(let d of i.reportsTo??[])if(!r.has(d))throw Error(`${c} references unknown manager: ${d}`)};for(let[i,c]of Object.entries(e.apps)){for(let[u,d]of Object.entries(c.policies??{})){if(d.eligible)o(d.eligible,`apps.${i}.policies.${u}.eligible`);if(d.approvers)o(d.approvers,`apps.${i}.policies.${u}.approvers`)}for(let[u,d]of(c.assignments??[]).entries())o(d.members,`apps.${i}.assignments[${u}].members`,d.subjectKind)}}function P(e){let t=f(e,"dataset");if(t.version!==1)throw Error(`Unsupported dataset version: ${String(t.version)}`);let r=f(t.meta,"dataset.meta"),n={version:1,meta:{id:m(r.id,"dataset.meta.id"),version:m(r.version,"dataset.meta.version"),name:h(r.name,"dataset.meta.name"),contentHash:h(r.contentHash,"dataset.meta.contentHash"),licence:Pe(r.licence,"dataset.meta.licence")},emailDomain:m(t.emailDomain,"dataset.emailDomain"),orgUnits:R(t.orgUnits,"dataset.orgUnits").map((a,s)=>{let o=f(a,`dataset.orgUnits[${s}]`);return{key:m(o.key,`dataset.orgUnits[${s}].key`),name:m(o.name,`dataset.orgUnits[${s}].name`),parent:h(o.parent,`dataset.orgUnits[${s}].parent`),leader:h(o.leader,`dataset.orgUnits[${s}].leader`)}}),workforce:R(t.workforce,"dataset.workforce").map((a,s)=>{let o=f(a,`dataset.workforce[${s}]`);return{key:m(o.key,`dataset.workforce[${s}].key`),employeeNumber:m(o.employeeNumber,`dataset.workforce[${s}].employeeNumber`),email:m(o.email,`dataset.workforce[${s}].email`),givenName:m(o.givenName,`dataset.workforce[${s}].givenName`),middleName:h(o.middleName,`dataset.workforce[${s}].middleName`),familyName:m(o.familyName,`dataset.workforce[${s}].familyName`),title:h(o.title,`dataset.workforce[${s}].title`),orgUnit:m(o.orgUnit,`dataset.workforce[${s}].orgUnit`),manager:h(o.manager,`dataset.workforce[${s}].manager`),active:$e(o.active,`dataset.workforce[${s}].active`),avatar:ve(o.avatar,`dataset.workforce[${s}].avatar`)}}),customers:R(t.customers,"dataset.customers").map((a,s)=>{let o=f(a,`dataset.customers[${s}]`);return{key:m(o.key,`dataset.customers[${s}].key`),email:m(o.email,`dataset.customers[${s}].email`),givenName:m(o.givenName,`dataset.customers[${s}].givenName`),familyName:m(o.familyName,`dataset.customers[${s}].familyName`),groups:o.groups===void 0?void 0:U(o.groups,`dataset.customers[${s}].groups`)}}),apps:{}};for(let[a,s]of Object.entries(f(t.apps,"dataset.apps")))n.apps[a]=ne(s,`dataset.apps.${a}`);return Re(n),n}function Ue(e){let t=[],r=ee(e,t,{allowTrailingComma:!0,disallowComments:!1});if(t.length>0){let n=t[0];throw Error(`Dataset JSONC parse error at offset ${n.offset}: ${te(n.error)}`)}return P(r)}function Oe(e){let t=[],r=ee(e,t,{allowTrailingComma:!0,disallowComments:!1});if(t.length>0){let s=t[0];throw Error(`Dataset overlay JSONC parse error at offset ${s.offset}: ${te(s.error)}`)}let n=f(r,"overlay"),a={};for(let[s,o]of Object.entries(f(n.apps,"overlay.apps")))a[s]=ne(o,`overlay.apps.${s}`);return{apps:a}}function j(e,t){let r=structuredClone(e.apps);for(let[n,a]of Object.entries(t.apps)){let s=r[n]??{};r[n]={policies:a.policies?{...s.policies,...a.policies}:s.policies,assignments:a.assignments??s.assignments,claims:a.claims?{...s.claims,...a.claims}:s.claims}}return P({...structuredClone(e),apps:r})}function O(e,t){let r=new Set,n=new Set,a=new Map(e.workforce.map((l)=>[l.key,l])),s=new Set(e.customers.map((l)=>l.key)),o=new Map;for(let l of e.orgUnits){if(!l.parent)continue;let p=o.get(l.parent)??[];p.push(l.key),o.set(l.parent,p)}let i=new Set,c=[...t.orgUnits??[]];while(c.length>0){let l=c.shift();if(!l||i.has(l))continue;i.add(l),c.push(...o.get(l)??[])}for(let l of e.workforce)if(i.has(l.orgUnit))r.add(l.key);let u=new Map;for(let l of e.workforce){if(!l.manager)continue;let p=u.get(l.manager)??[];p.push(l.key),u.set(l.manager,p)}let d=[...t.reportsTo??[]];while(d.length>0){let l=d.shift();if(!l||r.has(l))continue;r.add(l),d.push(...u.get(l)??[])}for(let l of t.people??[]){if(a.has(l))r.add(l);if(s.has(l))n.add(l)}return{workforce:r,customers:n}}function _(e){if(Array.isArray(e))return e.map(_);if(!re(e))return e;return Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t<r?-1:t>r?1:0).map(([t,r])=>[t,_(r)]))}function A(e){let t=structuredClone(e);return delete t.meta.contentHash,Te("sha256").update(JSON.stringify(_(t)),"utf8").digest("hex")}function Le(e,t){let r=A(e);if(e.meta.contentHash&&e.meta.contentHash!==r)throw Error("dataset.meta.contentHash does not match the dataset content");return{id:e.meta.id,version:e.meta.version,hash:r,source:t}}async function xe(e){let t=f(JSON.parse(await De(e,"utf8")),"lockfile");return{id:m(t.id,"lockfile.id"),version:m(t.version,"lockfile.version"),hash:m(t.hash,"lockfile.hash"),source:m(t.source,"lockfile.source")}}async function Ae(e,t){await Se(e,`${JSON.stringify(t,null,2)}
|
|
2
|
-
`,"utf8")}var se={basic:"auto",elevated:"approve",privileged:"approve",admin:"approve-with-justification"};function Ee(e,t,r){return e.apps[t]?.policies?.[r]}function Ce(e){if(e.policy?.workflow)return e.policy.workflow;if(e.riskLevel){let t=e.overrides?.get(e.riskLevel);if(t)return t;let r=(e.defaults??se)[e.riskLevel];if(r)return r}return"approve-with-justification"}function Ie(e,t,r){if(!t?.eligible)return{eligible:!0};let n=O(e,t.eligible);return(r.kind==="user"?n.workforce.has(r.key):n.customers.has(r.key))?{eligible:!0}:{eligible:!1,reason:"not_in_eligible_set"}}function Me(e,t){if(!t?.approvers)return[];return[...O(e,t.approvers).workforce]}function Ne(e,t,r){let n=[];for(let a of e.apps[t]?.assignments??[]){let s=O(e,a.members),o=a.subjectKind==="user"?[...s.workforce]:[...s.customers],i=new Set,c=[];for(let u of o){let d=a.subjectKind==="user"?r.user(u):r.customer(u);if(d)i.add(d);else c.push(u)}n.push({entitlementId:a.entitlement,subjectKind:a.subjectKind,members:[...i],unresolved:c})}return{appSlug:t,bindings:n}}import{ACCEPT_JSON as oe,CONTENT_TYPE_JSON as ae}from"@ionite/core";async function _e(e){let t=new URL(`${g(e.ioniteBaseUrl)}/api/tm/stage`),r=await fetch(t,{method:"POST",headers:{...oe,...ae},body:JSON.stringify({audience:e.audience,ioniteId:e.ioniteId,productId:e.productId,applicationId:e.applicationId,tenantHint:e.tenantHint,ttlSeconds:e.ttlSeconds})});return D(r,"TM stage")}function je(e){let t=new URL(g(e.tenantPath??"/api/tenants"),e.appBaseUrl),r=()=>AbortSignal.timeout(e.timeoutMs??15000),n=(s)=>new URL(`${t.pathname}/integrations/${s}`,t),a=(s,o)=>fetch(n(s),{method:"POST",headers:{...oe,Authorization:`Bearer ${e.accessToken}`,...ae},body:JSON.stringify(o),signal:r()});return{authorizeUrl(){let s=n("authorize");return s.searchParams.set("handle",e.handle),s.toString()},async redeem(){let s=await a("redeem",{handle:e.handle});if(![200,202,410,429].includes(s.status))throw Error(`TM redeem failed (${s.status}): ${await s.text()}`);return D(s,"TM redeem")},async exportConfig(s){let o=await a("config-export",{handle:e.handle,authorization:s});return D(o,"TM config export")}}}import{JSON_MEDIA_TYPE as ie,readJsonResponse as ze,unexpectedBodySummary as Je}from"@ionite/core";class F extends Error{constructor(e,t){super(t);this.status=e}}function L(e,t){return{tenant:e,control:t,created:0,updated:0,unchanged:0,errors:[]}}function T(e){if(Array.isArray(e))return`[${e.map(T).join(",")}]`;if(typeof e!=="object"||e===null)return JSON.stringify(e);return`{${Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t<r?-1:t>r?1:0).map(([t,r])=>`${JSON.stringify(t)}:${T(r)}`).join(",")}}`}function z(e,t,r){let n=new Map(t.map((s)=>[r(s),s])),a={created:0,updated:0,unchanged:0};for(let s of e){let o=n.get(r(s));if(!o)a.created+=1;else if(T(o)===T(s))a.unchanged+=1;else a.updated+=1}return a}function J(e,t){e.created+=t.created,e.updated+=t.updated,e.unchanged+=t.unchanged}async function E(e){let t=typeof e==="string"?e:await e();return t.startsWith("Bearer ")?t:`Bearer ${t}`}async function w(e,t,r,n){let a=new Headers(r.headers);if(a.set("Accept",ie),r.body)a.set("Content-Type",ie);let s=await e(t,{...r,headers:a,signal:r.signal??AbortSignal.timeout(n)});if(!s.ok){let o=await Je(s);throw new F(s.status,`${r.method??"GET"} ${new URL(t).pathname} failed (${s.status})${o.excerpt?`: ${o.excerpt}`:""}`)}if(s.status===204)return;return ze(s)}function Fe(e,t){let r=P(e);for(let n of t)r=j(r,n);return r}async function qe(e,t,r,n){let a=e.fetch??globalThis.fetch,s=`${g(e.controls.hr)}/api/${encodeURIComponent(r)}/employees`,o=await w(a,s,{},e.timeoutMs??30000),i=t.workforce.map((d)=>({...d,active:d.active??!0,avatar:d.avatar?{url:d.avatar.url}:void 0}));J(n,z(i,o.items,(d)=>d.employeeNumber));let c=z(t.orgUnits,o.orgUnits??[],(d)=>d.key),u=new Set(t.orgUnits.map((d)=>d.key));if(c.updated+=(o.orgUnits??[]).filter((d)=>!u.has(d.key)).length,J(n,c),!e.dryRun&&(n.created>0||n.updated>0)){let d={orgUnits:t.orgUnits,workforce:i};await w(a,s,{method:"PUT",body:JSON.stringify(d)},e.timeoutMs??30000)}}async function Ge(e,t,r){let n=e.fetch??globalThis.fetch,a=`${g(e.controls.iam)}/api/${encodeURIComponent(t)}/sync`,s=await E(e.authorization.iam);if(e.dryRun){let c=await w(n,a,{headers:{Authorization:s}},e.timeoutMs??30000);if(c.state==="done"&&(c.result?.errors?.length??0)===0)r.unchanged=1;else if(c.state==="error")r.errors.push(c.error??"IAM reconciliation failed");else r.errors.push(`IAM reconciliation is ${c.state}`);return}let o=e.timeoutMs??30000;await w(n,`${a}?async=true`,{method:"POST",headers:{Authorization:s}},o);let i=Date.now()+o;while(Date.now()<i){let c=await w(n,a,{headers:{Authorization:s}},o);if(c.state==="done"){if(r.errors.push(...c.result?.errors??[]),r.updated=Object.values(c.result?.appWrites??{}).reduce((u,d)=>u+d,0),r.updated===0&&r.errors.length===0)r.unchanged=1;return}if(c.state==="error"){r.errors.push(c.error??"IAM reconciliation failed");return}await new Promise((u)=>setTimeout(u,200))}r.errors.push(`IAM reconciliation timed out after ${o}ms`)}async function Ve(e,t,r,n){let a=e.fetch??globalThis.fetch,s=`${g(e.controls.sso)}/api/admin/tenants/${encodeURIComponent(r)}/dataset`,o=await E(e.authorization.sso),i=await w(a,s,{headers:{Authorization:o}},e.timeoutMs??30000),c={dataset:{orgUnits:t.orgUnits,workforce:t.workforce,customers:t.customers},apps:t.apps};if(T(i)===T(c))n.unchanged=1;else if(Object.keys(i.apps).length===0)n.created=1;else n.updated=1;if(!e.dryRun&&(n.created>0||n.updated>0))await w(a,s,{method:"PUT",headers:{Authorization:o},body:JSON.stringify(c)},e.timeoutMs??30000)}async function He(e,t,r,n){if(!e.controls.ciam||!e.authorization.ciam){n.skipped="control_not_configured";return}let a=e.fetch??globalThis.fetch,s=new URL(`${g(e.controls.ciam)}/api/admin/customers`);s.searchParams.set("tenant",r);let o=await E(e.authorization.ciam);try{let i=t.customers.map((k)=>({key:k.key,email:k.email,givenName:k.givenName,familyName:k.familyName})),c=await w(a,s.toString(),{headers:{Authorization:o}},e.timeoutMs??30000),u=new URL(`${g(e.controls.ciam)}/api/admin/dataset`);u.searchParams.set("tenant",r);let d=await w(a,u.toString(),{headers:{Authorization:o}},e.timeoutMs??30000),l={dataset:{orgUnits:t.orgUnits,workforce:t.workforce,customers:t.customers},apps:t.apps},p=z(i,c.items,(k)=>k.key),b=T(d)!==T(l);if(J(n,p),!b)n.unchanged+=1;else if(Object.keys(d.apps).length===0)n.created+=1;else n.updated+=1;if(!e.dryRun&&(p.created>0||p.updated>0)){let k={customers:i};await w(a,s.toString(),{method:"PUT",headers:{Authorization:o},body:JSON.stringify(k)},e.timeoutMs??30000)}if(!e.dryRun&&b)await w(a,u.toString(),{method:"PUT",headers:{Authorization:o},body:JSON.stringify(l)},e.timeoutMs??30000)}catch(i){if(i instanceof F&&(i.status===404||i.status===500&&i.message.includes("Only HTML requests are supported here"))){n.skipped="control_lacks_dataset_api";return}throw i}}async function We(e,t,r,n){let a=e.fetch??globalThis.fetch,s=`${g(e.controls.iam)}/api/${encodeURIComponent(r)}/dataset`,o=await E(e.authorization.iam),i=await w(a,s,{headers:{Authorization:o}},e.timeoutMs??30000),c={dataset:{orgUnits:t.orgUnits,workforce:t.workforce,customers:t.customers},apps:t.apps};if(T(i)===T(c))n.unchanged=1;else if(Object.keys(i.apps).length===0)n.created=1;else n.updated=1;if(!e.dryRun&&(n.created>0||n.updated>0))await w(a,s,{method:"PUT",headers:{Authorization:o},body:JSON.stringify(c)},e.timeoutMs??30000)}async function x(e,t){try{await t()}catch(r){e.errors.push(r instanceof Error?r.message:String(r))}return e}async function Be(e){let t=P(e.dataset),r=t.meta.contentHash,n=A(t);if(r&&r!==n)throw Error(`Dataset content hash mismatch: expected ${r}, received ${n}`);let a=Fe(t,e.overlays??[]),s=[];for(let o of e.tenants){let i=L(o,"hr");s.push(await x(i,()=>qe(e,a,o,i)));let c=L(o,"iam-sync");s.push(await x(c,()=>Ge(e,o,c)));let u=L(o,"sso");s.push(await x(u,()=>Ve(e,a,o,u)));let d=L(o,"ciam");s.push(await x(d,()=>He(e,a,o,d)));let l=L(o,"iam-dataset");s.push(await x(l,()=>We(e,a,o,l)))}return{dataset:{id:a.meta.id,version:a.meta.version,hash:n},dryRun:e.dryRun??!1,ok:s.every((o)=>o.errors.length===0),stages:s}}function q(e){if(typeof e.getSetCookie==="function")return e.getSetCookie();let t=e.get("set-cookie");return t?[t]:[]}function G(e){let t=e.split(";",1)[0],r=t?.indexOf("=")??-1;if(!t||r<=0)return;return[t.slice(0,r).trim(),t.slice(r+1).trim()]}class C{#e;#t;constructor(e=globalThis.fetch){this.#e=new Map;this.#t=e}cookies(e){if(e)return new Map(this.#e.get(new URL(e).origin));let t=new Map;for(let r of this.#e.values())for(let[n,a]of r)t.set(n,a);return t}async fetch(e,t={}){let r=new URL(e),n=t.method??"GET",a=t.body;for(let s=0;s<=10;s++){let o=new Headers(t.headers),i=this.#e.get(r.origin);if(i?.size&&!o.has("Cookie"))o.set("Cookie",[...i].map(([d,l])=>`${d}=${l}`).join("; "));let c=await this.#t(r,{...t,method:n,body:a,headers:o,redirect:"manual"});if(this.#r(r.origin,c.headers),![301,302,303,307,308].includes(c.status))return c;let u=c.headers.get("location");if(!u)return c;if(r=new URL(u,r),c.status===303||(c.status===301||c.status===302)&&n==="POST")n="GET",a=void 0}throw Error(`Too many redirects while requesting ${e}`)}#r(e,t){let r=this.#e.get(e)??new Map;for(let n of q(t)){let a=G(n);if(!a)continue;let[s,o]=a;if(o===""||/(?:^|;)\s*Max-Age=0(?:;|$)/i.test(n)||/expires=Thu, 01 Jan 1970/i.test(n))r.delete(s);else r.set(s,o)}this.#e.set(e,r)}}function ue(e){let t=new Map;for(let r of q(e)){let n=G(r);if(n)t.set(n[0],n[1])}return t}function ce(e){return[...e].map(([t,r])=>`${t}=${r}`).join("; ")}async function de(e,t,r={}){if(!e.loginPath)throw Error("Login path not configured");let n=r.redirectParam?`?redirect=${encodeURIComponent(r.redirectParam)}`:"",a=await t(`${e.loginPath}${n}`);if(a.status!==302)throw Error(`Login did not redirect: ${a.status}`);let s=a.headers.get("location");if(!s)throw Error("No redirect location from login");let o=ue(a.headers),i=new URL(s).searchParams.get("state");if(r.bogusCode){let p=new URL(s).searchParams.get("redirect_uri");if(!p||!i)throw Error("Missing redirect_uri/state on authorization URL");let b=new URL(p).pathname;return{callback:await t(`${b}?code=bogus-code&state=${encodeURIComponent(i)}`,{headers:{Cookie:ce(o)}}),state:i}}let c=new URL(s);if(r.groups&&r.groups.length>0)c.searchParams.set("groups",r.groups.join(" "));let u=await(r.externalFetch??globalThis.fetch)(c,{redirect:"manual"});if(u.status!==302)throw Error(`Auth did not redirect: ${u.status}`);let d=u.headers.get("location");if(!d)throw Error("No redirect location from auth");return{callback:await t(`${new URL(d).pathname}${new URL(d).search}`,{headers:{Cookie:ce(o)}}),state:i}}async function Ke(e,t){try{let{callback:r}=await de(e,t);if(r.status!==302)return{cookies:new Map,success:!1,error:`Callback did not redirect: ${r.status}`};return{cookies:ue(r.headers),success:!0}}catch(r){return{cookies:new Map,success:!1,error:r instanceof Error?r.message:String(r)}}}import{ACCEPT_JSON as V,CONTENT_TYPE_JSON as Ye,readJsonResponse as H}from"@ionite/core";function y(e,t){if(!e)throw Error(t)}async function Qe(e){let t=g(e.tenantPath??"/api/tenants"),r=e.profile??"tenantManager",n=await e.control.getTenantManagementToken(),a={...e.tenant,configLocator:e.tenant.configLocator??e.control.configLocator,webhookUrl:e.tenant.webhookUrl??e.control.webhookUrl},s=await fetch(new URL(t,e.baseUrl),{method:"POST",headers:{...V,Authorization:`Bearer ${n}`,...Ye},body:JSON.stringify(a),signal:AbortSignal.timeout(e.readiness?.requestTimeoutMs??15000)}),o=await H(s).catch(()=>({}));if(s.status===409||o.status==="failed")throw Error(`Tenant ${a.id} provisioning failed: ${o.error??s.statusText}`);if(o.status==="action_required"){y(e.completeActionRequired,`Tenant ${a.id} provisioning requires action at ${o.actionUrl}`),y(typeof o.id==="string",`Tenant ${a.id} action response must include id`),y(typeof o.actionUrl==="string",`Tenant ${a.id} action response must include actionUrl`),y(typeof o.requestToken==="string",`Tenant ${a.id} action response must include requestToken`),y(typeof o.expiresAt==="string",`Tenant ${a.id} action response must include expiresAt`),await e.completeActionRequired({id:o.id,actionUrl:o.actionUrl,requestToken:o.requestToken,expiresAt:o.expiresAt});let b=await fetch(new URL(`${t}/${encodeURIComponent(o.id)}`,e.baseUrl),{headers:{...V,Authorization:`Bearer ${n}`},signal:AbortSignal.timeout(e.readiness?.requestTimeoutMs??15000)});y(b.status===200,`Expected completed tenant GET to return 200, got ${b.status}`),o=await H(b),y(o.status==="completed",`Tenant ${a.id} remains ${o.status??"unknown"} after action`)}y(s.status===200||s.status===201||s.status===202,`Expected tenant create to return 200, 201, or 202, got ${s.status}`),y(typeof o.tenantUrl==="string",`Tenant ${a.id} response must include tenantUrl`),y(typeof o.id==="string"&&o.id.length>0,`Tenant ${a.id} response must include id`);let i=o.id;if(r==="creation"){let b=g(o.tenantUrl),k=e.basePath??"/api/ionite";return await v(b,{...e.readiness,basePath:k}),{id:i,baseUrl:b,basePath:k,tenantUrl:o.tenantUrl}}let c=await fetch(new URL(`${t}/${encodeURIComponent(i)}`,e.baseUrl),{headers:{...V,Authorization:`Bearer ${n}`},signal:AbortSignal.timeout(e.readiness?.requestTimeoutMs??15000)});y(c.status===200,`Expected tenant GET to return 200, got ${c.status}`);let u=await H(c);y(u.id===i,`Expected tenant GET id ${i}`),y(typeof u.ionUrls?.capabilitiezUrl==="string","Tenant GET must include ionUrls.capabilitiezUrl"),y(typeof u.ionUrls.readyzUrl==="string","Tenant GET must include ionUrls.readyzUrl");let d=new URL(u.ionUrls.capabilitiezUrl);y(d.pathname.endsWith("/capabilitiez"),"Tenant capabilitiezUrl must end in /capabilitiez");let l=d.pathname.slice(0,-13)||"/",p=new URL(u.ionUrls.readyzUrl);return await v(d.origin,{...e.readiness,readyPath:`${p.pathname}${p.search}`}),{id:i,baseUrl:d.origin,basePath:l,tenantUrl:typeof u.tenantUrl==="string"?u.tenantUrl:o.tenantUrl}}function B(e){return{Accept:"application/scim+json",Authorization:`Bearer ${e}`}}function W(e,t){return`${g(e)}${t}`}function Xe(e,t){let r=t.trim();if(!r)return String(e);try{let n=JSON.parse(r);if(!((Array.isArray(n.schemas)?n.schemas:[]).includes("urn:ietf:params:scim:api:messages:2.0:Error")||typeof n.scimType==="string"||typeof n.status==="string"))return`${e} ${r}`;let o=[String(n.status??e)];if(typeof n.scimType==="string"&&n.scimType)o.push(`scimType=${n.scimType}`);if(typeof n.attribute==="string"&&n.attribute)o.push(`attribute=${n.attribute}`);if(typeof n.detail==="string"&&n.detail)o.push(`detail=${JSON.stringify(n.detail)}`);return o.join(" ")}catch{return`${e} ${r}`}}function K(e,t,r,n){return`SCIM ${e} ${t} failed: ${Xe(r,n)}`}async function Ze(e,t,r=100,n){let a=[],s=1,o=0;while(!0){let i=new URL(e);if(i.searchParams.set("startIndex",String(s)),i.searchParams.set("count",String(r)),n)i.searchParams.set("filter",n);let c=await fetch(i,{headers:B(t)});if(!c.ok)throw Error(K("GET",`${i.origin}${i.pathname}`,c.status,await c.text()));let u=await c.json();if(!Array.isArray(u.Resources)||u.Resources.length===0)return a;if(a.push(...u.Resources),o=u.totalResults??a.length,a.length>=o)return a;s+=u.Resources.length}}function et(e,t){if(!t)return;try{return new URL(t,`${g(e)}/`).toString()}catch{return}}async function tt(e,t){let r=W(e,"/ResourceTypes"),n=await fetch(r,{headers:B(t)});if(!n.ok)throw Error(K("GET",r,n.status,await n.text()));let a=await n.json(),o=(Array.isArray(a.Resources)?a.Resources:[]).find((i)=>i.id==="Group"||i.name==="Group");if(!o)return{supported:!1};return{supported:!0,groupsUrl:et(e,o.endpoint)??W(e,"/Groups")}}async function rt(e,t,r){return Ze(e,t,100,r?.requestableOnly?"requestable eq true":void 0)}async function nt(e,t,r){let n=W(e,`/Groups/${encodeURIComponent(r)}`),a=await fetch(n,{headers:B(t)});if(a.status===404)return null;if(!a.ok)throw Error(K("GET",n,a.status,await a.text()));return await a.json()}import{ACCEPT_JSON as le,CONTENT_TYPE_JSON as me}from"@ionite/core";async function st(e){let t=g(e.appBaseUrl),r=new C(e.fetch),n=()=>AbortSignal.timeout(e.timeoutMs??30000),a=await r.fetch(new URL(e.magicLinkPath??"/api/onboard/magic-link",t),{method:"POST",headers:{...le,...me},body:JSON.stringify(e.magicLinkBody?.(e.owner)??{email:e.owner.email}),signal:n()}),s=await D(a,"App owner magic-link creation"),o=e.readMagicLink?.(s)??(typeof s==="object"&&s!==null&&typeof s.magicLink==="string"?s.magicLink:void 0);if(!o)throw Error("App owner magic-link response did not include magicLink");let i=await r.fetch(new URL(o,t),{signal:n()});if(!i.ok)throw Error(`App owner magic-link login failed (${i.status}): ${await i.text()}`);let c=await r.fetch(new URL(e.tenantCreatePath??"/api/onboard",t),{method:"POST",headers:{...le,...me},body:JSON.stringify(e.tenantBody?.(e.tenant)??{slug:e.tenant.id,companyName:e.tenant.name}),signal:n()}),u=await D(c,"App tenant creation");return{tenantId:e.tenant.id,owner:e.owner,tenant:u,session:r}}import{ACCEPT_JSON as ot,CONTENT_TYPE_JSON as I}from"@ionite/core";async function at(e,t,r){let n=Date.now();while(Date.now()-n<r){try{if((await t(`${e}/api/readyz`,{headers:ot,signal:AbortSignal.timeout(2000)})).ok)return}catch{}await new Promise((a)=>setTimeout(a,500))}throw Error(`Timed out waiting for the ECI at ${e}/api/readyz`)}async function it(e){let t=process.env.ION_CONTROLS_PORT?.trim()||"3700",r=g(e.eciBaseUrl??`http://localhost:${t}/ionite`),n=e.fetch??globalThis.fetch,a={fetch:n,timeoutMs:e.requestTimeoutMs??120000};if(await at(r,n,e.readyTimeoutMs??300000),await S(`${r}/api/bootstrap`,{method:"POST",headers:I,body:JSON.stringify({companies:[e.company]})},{...a,label:"ECI company bootstrap"}),e.oem)await S(`${r}/api/oems`,{method:"POST",headers:I,body:JSON.stringify(e.oem)},{...a,label:"ECI OEM registration"});let s=await S(`${r}/api/products`,{method:"POST",headers:I,body:JSON.stringify(e.product)},{...a,label:"ECI product registration"});await e.onProductRegistered?.(s);let o=await S(`${r}/api/companies/${encodeURIComponent(e.company.id)}/products/${encodeURIComponent(s.product.id)}/integration`,{method:"POST",headers:I,body:JSON.stringify(e.integration)},{...a,label:"ECI tenant integration"});if(o.tenant.status==="error")throw Error(o.tenant.error??`Tenant ${e.company.id} failed to integrate`);return{registration:s,integration:o}}export{se as DEFAULT_WORKFLOWS,C as HttpSession,Ke as completeLoginFlow,A as datasetContentHash,Le as datasetLock,tt as discoverScimGroups,Ie as evaluateEligibility,rt as fetchScimGroupsFromUrl,Ee as findAppPolicy,nt as getScimGroupById,je as ioniteTmDriver,Be as loadDataset,j as mergeDatasetOverlay,Ue as parseDatasetJsonc,Oe as parseDatasetOverlayJsonc,Ne as planAssignments,Qe as provisionTenant,xe as readDatasetLock,S as requestJson,Me as resolveApprovers,O as resolveDatasetMemberSet,Z as resolveReadyPath,Ce as resolveWorkflow,de as runLoginToCallback,st as seedAppOwner,it as seedIoniteTenant,_e as stageTmIntegration,be as startAppUnderTest,P as validateDataset,v as waitForReady,Ae as writeDatasetLock};
|
|
1
|
+
import{spawn as ge}from"node:child_process";import{ACCEPT_JSON as fe}from"@ionite/core";import{JSON_MEDIA_TYPE as pe,readJsonResponse as Y,unexpectedBodySummary as Q}from"@ionite/core";function g(e){return e.replace(/\/+$/,"")}async function D(e,t){if(!e.ok){let r=await Q(e);throw Error(`${t} failed (${e.status})${r.excerpt?`: ${r.excerpt}`:""}`)}return await Y(e)}async function S(e,t,r={}){let n=new Headers(t.headers);if(!n.has("Accept"))n.set("Accept",pe);let a=await(r.fetch??globalThis.fetch)(e,{...t,headers:n,signal:t.signal??AbortSignal.timeout(r.timeoutMs??30000)});if(!a.ok){let o=await Q(a);throw Error(`${r.label??`${t.method??"GET"} ${e}`} failed (${a.status})${o.excerpt?`: ${o.excerpt}`:""}`)}if(a.status===204)return;return await Y(a)}var ye="/api/ionite",he=5000,we=2000;function ke(e){return new Promise((t)=>setTimeout(t,e))}function X(e,t){if(e.exitCode!==null||e.signalCode!==null)return Promise.resolve(!0);return new Promise((r)=>{let n=!1,a=()=>{if(n)return;n=!0,clearTimeout(o),r(!0)},o=setTimeout(()=>{if(n)return;n=!0,e.removeListener("exit",a),r(!1)},t);e.once("exit",a)})}function Z(e){if(e.readyPath)return e.readyPath;return`${g(e.basePath??ye)}/readyz`}async function v(e,t={}){let{livenessPath:r,maxRetries:n=30,retryDelayMs:a=1000,requestTimeoutMs:o=3000}=t,s=Z(t),i;for(let u=0;u<n;u++){try{if(r){let l=await fetch(new URL(r,e),{signal:AbortSignal.timeout(o)});if(!l.ok)throw Error(`liveness returned ${l.status}`)}let d=await fetch(new URL(s,e),{headers:fe,signal:AbortSignal.timeout(o)});if(d.ok)return;i=Error(`readiness returned ${d.status}`)}catch(d){i=d}if(u<n-1)await ke(a)}let c=i instanceof Error?i.message:String(i);throw Error(`App not ready at ${new URL(s,e)} after ${n} attempts: ${c}`)}async function be(e){let{command:t,args:r=[],cwd:n,env:a,baseUrl:o,...s}=e,i=process.platform!=="win32",c=ge(t,r,{cwd:n,env:{...process.env,...a},stdio:"inherit",detached:i});c.on("error",(p)=>{console.error(`Failed to start app under test (${t}):`,p)});let u=(p)=>{try{if(i&&c.pid!==void 0)process.kill(-c.pid,p);else c.kill(p)}catch{}},d=()=>u("SIGKILL");process.once("exit",d);let l=async()=>{if(c.exitCode===null&&c.signalCode===null){if(u("SIGTERM"),!await X(c,he))u("SIGKILL"),await X(c,we)}u("SIGKILL"),process.removeListener("exit",d)};try{await v(o,s)}catch(p){throw await l(),p}return{baseUrl:o,...c.pid===void 0?{}:{pid:c.pid},stop:l}}import{createHash as Te}from"node:crypto";import{readFile as De,writeFile as Se}from"node:fs/promises";import{parse as ee,printParseErrorCode as te}from"jsonc-parser";function re(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function f(e,t){if(!re(e))throw Error(`${t} must be an object`);return e}function R(e,t){if(!Array.isArray(e))throw Error(`${t} must be an array`);return e}function m(e,t){if(typeof e!=="string"||!e.trim())throw Error(`${t} must be a non-empty string`);return e}function h(e,t){if(e===void 0)return;return m(e,t)}function $e(e,t){if(e===void 0)return;if(typeof e!=="boolean")throw Error(`${t} must be a boolean`);return e}function U(e,t){return R(e,t).map((r,n)=>m(r,`${t}[${n}]`))}function M(e,t){let r=new Set;for(let n of e){if(r.has(n.key))throw Error(`Duplicate ${t} key: ${n.key}`);r.add(n.key)}return r}function Pe(e,t){if(e===void 0)return;let r=f(e,t);return{name:m(r.name,`${t}.name`),attribution:h(r.attribution,`${t}.attribution`),sourceUrl:h(r.sourceUrl,`${t}.sourceUrl`)}}function ve(e,t){if(e===void 0)return;let r=f(e,t);return{url:m(r.url,`${t}.url`),attribution:h(r.attribution,`${t}.attribution`),licence:h(r.licence,`${t}.licence`),sourceUrl:h(r.sourceUrl,`${t}.sourceUrl`)}}function N(e,t){let r=f(e,t),n={people:r.people===void 0?void 0:U(r.people,`${t}.people`),orgUnits:r.orgUnits===void 0?void 0:U(r.orgUnits,`${t}.orgUnits`),reportsTo:r.reportsTo===void 0?void 0:U(r.reportsTo,`${t}.reportsTo`)};if(!n.people?.length&&!n.orgUnits?.length&&!n.reportsTo?.length)throw Error(`${t} must select at least one person, org unit, or manager`);return n}function ne(e,t){let r=f(e,t),n;if(r.policies!==void 0){n={};for(let[s,i]of Object.entries(f(r.policies,`${t}.policies`))){let c=f(i,`${t}.policies.${s}`),u=h(c.workflow,`${t}.policies.${s}.workflow`);if(u!==void 0&&u!=="auto"&&u!=="approve"&&u!=="approve-with-justification")throw Error(`${t}.policies.${s}.workflow is not supported`);n[s]={workflow:u,eligible:c.eligible===void 0?void 0:N(c.eligible,`${t}.policies.${s}.eligible`),approvers:c.approvers===void 0?void 0:N(c.approvers,`${t}.policies.${s}.approvers`)}}}let a=r.assignments===void 0?void 0:R(r.assignments,`${t}.assignments`).map((s,i)=>{let c=f(s,`${t}.assignments[${i}]`),u=m(c.subjectKind,`${t}.assignments[${i}].subjectKind`);if(u!=="user"&&u!=="customer")throw Error(`${t}.assignments[${i}].subjectKind is not supported`);return{entitlement:m(c.entitlement,`${t}.assignments[${i}].entitlement`),subjectKind:u,members:N(c.members,`${t}.assignments[${i}].members`)}}),o;if(r.claims!==void 0){o={};for(let[s,i]of Object.entries(f(r.claims,`${t}.claims`))){let c=f(i,`${t}.claims.${s}`);o[s]={groups:U(c.groups,`${t}.claims.${s}.groups`)}}}return{policies:n,assignments:a,claims:o}}function Re(e){let t=M(e.orgUnits,"org unit"),r=M(e.workforce,"workforce person"),n=M(e.customers,"customer"),a=new Set,o=new Set;for(let i of e.orgUnits){if(i.parent&&!t.has(i.parent))throw Error(`Unknown parent org unit: ${i.parent}`);if(i.leader&&!r.has(i.leader))throw Error(`Unknown org unit leader: ${i.leader}`)}for(let i of e.workforce){if(!t.has(i.orgUnit))throw Error(`Unknown org unit for ${i.key}: ${i.orgUnit}`);if(i.manager&&!r.has(i.manager))throw Error(`Unknown manager for ${i.key}: ${i.manager}`);if(a.has(i.employeeNumber))throw Error(`Duplicate workforce employeeNumber: ${i.employeeNumber}`);a.add(i.employeeNumber);let c=i.email.toLowerCase();if(o.has(c))throw Error(`Duplicate dataset email: ${i.email}`);o.add(c)}for(let i of e.customers){let c=i.email.toLowerCase();if(o.has(c))throw Error(`Duplicate dataset email: ${i.email}`);o.add(c)}let s=(i,c,u)=>{for(let d of i.people??[])if(!(u==="customer"?n.has(d):r.has(d)||n.has(d)))throw Error(`${c} references unknown person: ${d}`);if(u==="customer"&&((i.orgUnits?.length??0)>0||(i.reportsTo?.length??0)>0))throw Error(`${c} cannot select customer members by workforce organization`);for(let d of i.orgUnits??[])if(!t.has(d))throw Error(`${c} references unknown org unit: ${d}`);for(let d of i.reportsTo??[])if(!r.has(d))throw Error(`${c} references unknown manager: ${d}`)};for(let[i,c]of Object.entries(e.apps)){for(let[u,d]of Object.entries(c.policies??{})){if(d.eligible)s(d.eligible,`apps.${i}.policies.${u}.eligible`);if(d.approvers)s(d.approvers,`apps.${i}.policies.${u}.approvers`)}for(let[u,d]of(c.assignments??[]).entries())s(d.members,`apps.${i}.assignments[${u}].members`,d.subjectKind)}}function P(e){let t=f(e,"dataset");if(t.version!==1)throw Error(`Unsupported dataset version: ${String(t.version)}`);let r=f(t.meta,"dataset.meta"),n={version:1,meta:{id:m(r.id,"dataset.meta.id"),version:m(r.version,"dataset.meta.version"),name:h(r.name,"dataset.meta.name"),contentHash:h(r.contentHash,"dataset.meta.contentHash"),licence:Pe(r.licence,"dataset.meta.licence")},emailDomain:m(t.emailDomain,"dataset.emailDomain"),orgUnits:R(t.orgUnits,"dataset.orgUnits").map((a,o)=>{let s=f(a,`dataset.orgUnits[${o}]`);return{key:m(s.key,`dataset.orgUnits[${o}].key`),name:m(s.name,`dataset.orgUnits[${o}].name`),parent:h(s.parent,`dataset.orgUnits[${o}].parent`),leader:h(s.leader,`dataset.orgUnits[${o}].leader`)}}),workforce:R(t.workforce,"dataset.workforce").map((a,o)=>{let s=f(a,`dataset.workforce[${o}]`);return{key:m(s.key,`dataset.workforce[${o}].key`),employeeNumber:m(s.employeeNumber,`dataset.workforce[${o}].employeeNumber`),email:m(s.email,`dataset.workforce[${o}].email`),givenName:m(s.givenName,`dataset.workforce[${o}].givenName`),middleName:h(s.middleName,`dataset.workforce[${o}].middleName`),familyName:m(s.familyName,`dataset.workforce[${o}].familyName`),title:h(s.title,`dataset.workforce[${o}].title`),orgUnit:m(s.orgUnit,`dataset.workforce[${o}].orgUnit`),manager:h(s.manager,`dataset.workforce[${o}].manager`),active:$e(s.active,`dataset.workforce[${o}].active`),avatar:ve(s.avatar,`dataset.workforce[${o}].avatar`)}}),customers:R(t.customers,"dataset.customers").map((a,o)=>{let s=f(a,`dataset.customers[${o}]`);return{key:m(s.key,`dataset.customers[${o}].key`),email:m(s.email,`dataset.customers[${o}].email`),givenName:m(s.givenName,`dataset.customers[${o}].givenName`),familyName:m(s.familyName,`dataset.customers[${o}].familyName`),groups:s.groups===void 0?void 0:U(s.groups,`dataset.customers[${o}].groups`)}}),apps:{}};for(let[a,o]of Object.entries(f(t.apps,"dataset.apps")))n.apps[a]=ne(o,`dataset.apps.${a}`);return Re(n),n}function Ue(e){let t=[],r=ee(e,t,{allowTrailingComma:!0,disallowComments:!1});if(t.length>0){let n=t[0];throw Error(`Dataset JSONC parse error at offset ${n.offset}: ${te(n.error)}`)}return P(r)}function Oe(e){let t=[],r=ee(e,t,{allowTrailingComma:!0,disallowComments:!1});if(t.length>0){let o=t[0];throw Error(`Dataset overlay JSONC parse error at offset ${o.offset}: ${te(o.error)}`)}let n=f(r,"overlay"),a={};for(let[o,s]of Object.entries(f(n.apps,"overlay.apps")))a[o]=ne(s,`overlay.apps.${o}`);return{apps:a}}function j(e,t){let r=structuredClone(e.apps);for(let[n,a]of Object.entries(t.apps)){let o=r[n]??{};r[n]={policies:a.policies?{...o.policies,...a.policies}:o.policies,assignments:a.assignments??o.assignments,claims:a.claims?{...o.claims,...a.claims}:o.claims}}return P({...structuredClone(e),apps:r})}function O(e,t){let r=new Set,n=new Set,a=new Map(e.workforce.map((l)=>[l.key,l])),o=new Set(e.customers.map((l)=>l.key)),s=new Map;for(let l of e.orgUnits){if(!l.parent)continue;let p=s.get(l.parent)??[];p.push(l.key),s.set(l.parent,p)}let i=new Set,c=[...t.orgUnits??[]];while(c.length>0){let l=c.shift();if(!l||i.has(l))continue;i.add(l),c.push(...s.get(l)??[])}for(let l of e.workforce)if(i.has(l.orgUnit))r.add(l.key);let u=new Map;for(let l of e.workforce){if(!l.manager)continue;let p=u.get(l.manager)??[];p.push(l.key),u.set(l.manager,p)}let d=[...t.reportsTo??[]];while(d.length>0){let l=d.shift();if(!l||r.has(l))continue;r.add(l),d.push(...u.get(l)??[])}for(let l of t.people??[]){if(a.has(l))r.add(l);if(o.has(l))n.add(l)}return{workforce:r,customers:n}}function _(e){if(Array.isArray(e))return e.map(_);if(!re(e))return e;return Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t<r?-1:t>r?1:0).map(([t,r])=>[t,_(r)]))}function A(e){let t=structuredClone(e);return delete t.meta.contentHash,Te("sha256").update(JSON.stringify(_(t)),"utf8").digest("hex")}function Le(e,t){let r=A(e);if(e.meta.contentHash&&e.meta.contentHash!==r)throw Error("dataset.meta.contentHash does not match the dataset content");return{id:e.meta.id,version:e.meta.version,hash:r,source:t}}async function xe(e){let t=f(JSON.parse(await De(e,"utf8")),"lockfile");return{id:m(t.id,"lockfile.id"),version:m(t.version,"lockfile.version"),hash:m(t.hash,"lockfile.hash"),source:m(t.source,"lockfile.source")}}async function Ae(e,t){await Se(e,`${JSON.stringify(t,null,2)}
|
|
2
|
+
`,"utf8")}var se={basic:"auto",elevated:"approve",privileged:"approve",admin:"approve-with-justification"};function Ee(e,t,r){return e.apps[t]?.policies?.[r]}function Ce(e){if(e.policy?.workflow)return e.policy.workflow;if(e.riskLevel){let t=e.overrides?.get(e.riskLevel);if(t)return t;let r=(e.defaults??se)[e.riskLevel];if(r)return r}return"approve-with-justification"}function Ie(e,t,r){if(!t?.eligible)return{eligible:!0};let n=O(e,t.eligible);return(r.kind==="user"?n.workforce.has(r.key):n.customers.has(r.key))?{eligible:!0}:{eligible:!1,reason:"not_in_eligible_set"}}function Me(e,t){if(!t?.approvers)return[];return[...O(e,t.approvers).workforce]}function Ne(e,t,r){let n=[];for(let a of e.apps[t]?.assignments??[]){let o=O(e,a.members),s=a.subjectKind==="user"?[...o.workforce]:[...o.customers],i=new Set,c=[];for(let u of s){let d=a.subjectKind==="user"?r.user(u):r.customer(u);if(d)i.add(d);else c.push(u)}n.push({entitlementId:a.entitlement,subjectKind:a.subjectKind,members:[...i],unresolved:c})}return{appSlug:t,bindings:n}}import{ACCEPT_JSON as oe,CONTENT_TYPE_JSON as ae}from"@ionite/core";async function _e(e){let t=new URL(`${g(e.ioniteBaseUrl)}/api/tm/stage`),r=await fetch(t,{method:"POST",headers:{...oe,...ae},body:JSON.stringify({audience:e.audience,ioniteId:e.ioniteId,productId:e.productId,applicationId:e.applicationId,tenantHint:e.tenantHint,ttlSeconds:e.ttlSeconds})});return D(r,"TM stage")}function je(e){let t=new URL(g(e.tenantPath??"/api/tenants"),e.appBaseUrl),r=()=>AbortSignal.timeout(e.timeoutMs??15000),n=(o)=>new URL(`${t.pathname}/integrations/${o}`,t),a=(o,s)=>fetch(n(o),{method:"POST",headers:{...oe,Authorization:`Bearer ${e.accessToken}`,...ae},body:JSON.stringify(s),signal:r()});return{async authorizeUrl(){let o=await a("stage",{handle:e.handle}),{request_uri:s}=await D(o,"TM stage"),i=n("authorize");return i.searchParams.set("request_uri",s),i.toString()},async redeem(){let o=await a("redeem",{handle:e.handle});if(![200,202,410,429].includes(o.status))throw Error(`TM redeem failed (${o.status}): ${await o.text()}`);return D(o,"TM redeem")},async exportConfig(o){let s=await a("config-export",{handle:e.handle,authorization:o});return D(s,"TM config export")}}}import{JSON_MEDIA_TYPE as ie,readJsonResponse as ze,unexpectedBodySummary as Je}from"@ionite/core";class q extends Error{constructor(e,t){super(t);this.status=e}}function L(e,t){return{tenant:e,control:t,created:0,updated:0,unchanged:0,errors:[]}}function T(e){if(Array.isArray(e))return`[${e.map(T).join(",")}]`;if(typeof e!=="object"||e===null)return JSON.stringify(e);return`{${Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t<r?-1:t>r?1:0).map(([t,r])=>`${JSON.stringify(t)}:${T(r)}`).join(",")}}`}function z(e,t,r){let n=new Map(t.map((o)=>[r(o),o])),a={created:0,updated:0,unchanged:0};for(let o of e){let s=n.get(r(o));if(!s)a.created+=1;else if(T(s)===T(o))a.unchanged+=1;else a.updated+=1}return a}function J(e,t){e.created+=t.created,e.updated+=t.updated,e.unchanged+=t.unchanged}async function E(e){let t=typeof e==="string"?e:await e();return t.startsWith("Bearer ")?t:`Bearer ${t}`}async function w(e,t,r,n){let a=new Headers(r.headers);if(a.set("Accept",ie),r.body)a.set("Content-Type",ie);let o=await e(t,{...r,headers:a,signal:r.signal??AbortSignal.timeout(n)});if(!o.ok){let s=await Je(o);throw new q(o.status,`${r.method??"GET"} ${new URL(t).pathname} failed (${o.status})${s.excerpt?`: ${s.excerpt}`:""}`)}if(o.status===204)return;return ze(o)}function qe(e,t){let r=P(e);for(let n of t)r=j(r,n);return r}async function Fe(e,t,r,n){let a=e.fetch??globalThis.fetch,o=`${g(e.controls.hr)}/api/${encodeURIComponent(r)}/employees`,s=await w(a,o,{},e.timeoutMs??30000),i=t.workforce.map((d)=>({...d,active:d.active??!0,avatar:d.avatar?{url:d.avatar.url}:void 0}));J(n,z(i,s.items,(d)=>d.employeeNumber));let c=z(t.orgUnits,s.orgUnits??[],(d)=>d.key),u=new Set(t.orgUnits.map((d)=>d.key));if(c.updated+=(s.orgUnits??[]).filter((d)=>!u.has(d.key)).length,J(n,c),!e.dryRun&&(n.created>0||n.updated>0)){let d={orgUnits:t.orgUnits,workforce:i};await w(a,o,{method:"PUT",body:JSON.stringify(d)},e.timeoutMs??30000)}}async function Ge(e,t,r){let n=e.fetch??globalThis.fetch,a=`${g(e.controls.iam)}/api/${encodeURIComponent(t)}/sync`,o=await E(e.authorization.iam);if(e.dryRun){let c=await w(n,a,{headers:{Authorization:o}},e.timeoutMs??30000);if(c.state==="done"&&(c.result?.errors?.length??0)===0)r.unchanged=1;else if(c.state==="error")r.errors.push(c.error??"IAM reconciliation failed");else r.errors.push(`IAM reconciliation is ${c.state}`);return}let s=e.timeoutMs??30000;await w(n,`${a}?async=true`,{method:"POST",headers:{Authorization:o}},s);let i=Date.now()+s;while(Date.now()<i){let c=await w(n,a,{headers:{Authorization:o}},s);if(c.state==="done"){if(r.errors.push(...c.result?.errors??[]),r.updated=Object.values(c.result?.appWrites??{}).reduce((u,d)=>u+d,0),r.updated===0&&r.errors.length===0)r.unchanged=1;return}if(c.state==="error"){r.errors.push(c.error??"IAM reconciliation failed");return}await new Promise((u)=>setTimeout(u,200))}r.errors.push(`IAM reconciliation timed out after ${s}ms`)}async function Ve(e,t,r,n){let a=e.fetch??globalThis.fetch,o=`${g(e.controls.sso)}/api/admin/tenants/${encodeURIComponent(r)}/dataset`,s=await E(e.authorization.sso),i=await w(a,o,{headers:{Authorization:s}},e.timeoutMs??30000),c={dataset:{orgUnits:t.orgUnits,workforce:t.workforce,customers:t.customers},apps:t.apps};if(T(i)===T(c))n.unchanged=1;else if(Object.keys(i.apps).length===0)n.created=1;else n.updated=1;if(!e.dryRun&&(n.created>0||n.updated>0))await w(a,o,{method:"PUT",headers:{Authorization:s},body:JSON.stringify(c)},e.timeoutMs??30000)}async function He(e,t,r,n){if(!e.controls.ciam||!e.authorization.ciam){n.skipped="control_not_configured";return}let a=e.fetch??globalThis.fetch,o=new URL(`${g(e.controls.ciam)}/api/admin/customers`);o.searchParams.set("tenant",r);let s=await E(e.authorization.ciam);try{let i=t.customers.map((k)=>({key:k.key,email:k.email,givenName:k.givenName,familyName:k.familyName})),c=await w(a,o.toString(),{headers:{Authorization:s}},e.timeoutMs??30000),u=new URL(`${g(e.controls.ciam)}/api/admin/dataset`);u.searchParams.set("tenant",r);let d=await w(a,u.toString(),{headers:{Authorization:s}},e.timeoutMs??30000),l={dataset:{orgUnits:t.orgUnits,workforce:t.workforce,customers:t.customers},apps:t.apps},p=z(i,c.items,(k)=>k.key),b=T(d)!==T(l);if(J(n,p),!b)n.unchanged+=1;else if(Object.keys(d.apps).length===0)n.created+=1;else n.updated+=1;if(!e.dryRun&&(p.created>0||p.updated>0)){let k={customers:i};await w(a,o.toString(),{method:"PUT",headers:{Authorization:s},body:JSON.stringify(k)},e.timeoutMs??30000)}if(!e.dryRun&&b)await w(a,u.toString(),{method:"PUT",headers:{Authorization:s},body:JSON.stringify(l)},e.timeoutMs??30000)}catch(i){if(i instanceof q&&(i.status===404||i.status===500&&i.message.includes("Only HTML requests are supported here"))){n.skipped="control_lacks_dataset_api";return}throw i}}async function We(e,t,r,n){let a=e.fetch??globalThis.fetch,o=`${g(e.controls.iam)}/api/${encodeURIComponent(r)}/dataset`,s=await E(e.authorization.iam),i=await w(a,o,{headers:{Authorization:s}},e.timeoutMs??30000),c={dataset:{orgUnits:t.orgUnits,workforce:t.workforce,customers:t.customers},apps:t.apps};if(T(i)===T(c))n.unchanged=1;else if(Object.keys(i.apps).length===0)n.created=1;else n.updated=1;if(!e.dryRun&&(n.created>0||n.updated>0))await w(a,o,{method:"PUT",headers:{Authorization:s},body:JSON.stringify(c)},e.timeoutMs??30000)}async function x(e,t){try{await t()}catch(r){e.errors.push(r instanceof Error?r.message:String(r))}return e}async function Be(e){let t=P(e.dataset),r=t.meta.contentHash,n=A(t);if(r&&r!==n)throw Error(`Dataset content hash mismatch: expected ${r}, received ${n}`);let a=qe(t,e.overlays??[]),o=[];for(let s of e.tenants){let i=L(s,"hr");o.push(await x(i,()=>Fe(e,a,s,i)));let c=L(s,"iam-sync");o.push(await x(c,()=>Ge(e,s,c)));let u=L(s,"sso");o.push(await x(u,()=>Ve(e,a,s,u)));let d=L(s,"ciam");o.push(await x(d,()=>He(e,a,s,d)));let l=L(s,"iam-dataset");o.push(await x(l,()=>We(e,a,s,l)))}return{dataset:{id:a.meta.id,version:a.meta.version,hash:n},dryRun:e.dryRun??!1,ok:o.every((s)=>s.errors.length===0),stages:o}}function F(e){if(typeof e.getSetCookie==="function")return e.getSetCookie();let t=e.get("set-cookie");return t?[t]:[]}function G(e){let t=e.split(";",1)[0],r=t?.indexOf("=")??-1;if(!t||r<=0)return;return[t.slice(0,r).trim(),t.slice(r+1).trim()]}class C{#e;#t;constructor(e=globalThis.fetch){this.#e=new Map;this.#t=e}cookies(e){if(e)return new Map(this.#e.get(new URL(e).origin));let t=new Map;for(let r of this.#e.values())for(let[n,a]of r)t.set(n,a);return t}async fetch(e,t={}){let r=new URL(e),n=t.method??"GET",a=t.body;for(let o=0;o<=10;o++){let s=new Headers(t.headers),i=this.#e.get(r.origin);if(i?.size&&!s.has("Cookie"))s.set("Cookie",[...i].map(([d,l])=>`${d}=${l}`).join("; "));let c=await this.#t(r,{...t,method:n,body:a,headers:s,redirect:"manual"});if(this.#r(r.origin,c.headers),![301,302,303,307,308].includes(c.status))return c;let u=c.headers.get("location");if(!u)return c;if(r=new URL(u,r),c.status===303||(c.status===301||c.status===302)&&n==="POST")n="GET",a=void 0}throw Error(`Too many redirects while requesting ${e}`)}#r(e,t){let r=this.#e.get(e)??new Map;for(let n of F(t)){let a=G(n);if(!a)continue;let[o,s]=a;if(s===""||/(?:^|;)\s*Max-Age=0(?:;|$)/i.test(n)||/expires=Thu, 01 Jan 1970/i.test(n))r.delete(o);else r.set(o,s)}this.#e.set(e,r)}}function ue(e){let t=new Map;for(let r of F(e)){let n=G(r);if(n)t.set(n[0],n[1])}return t}function ce(e){return[...e].map(([t,r])=>`${t}=${r}`).join("; ")}async function de(e,t,r={}){if(!e.loginPath)throw Error("Login path not configured");let n=r.redirectParam?`?redirect=${encodeURIComponent(r.redirectParam)}`:"",a=await t(`${e.loginPath}${n}`);if(a.status!==302)throw Error(`Login did not redirect: ${a.status}`);let o=a.headers.get("location");if(!o)throw Error("No redirect location from login");let s=ue(a.headers),i=new URL(o).searchParams.get("state");if(r.bogusCode){let p=new URL(o).searchParams.get("redirect_uri");if(!p||!i)throw Error("Missing redirect_uri/state on authorization URL");let b=new URL(p).pathname;return{callback:await t(`${b}?code=bogus-code&state=${encodeURIComponent(i)}`,{headers:{Cookie:ce(s)}}),state:i}}let c=new URL(o);if(r.groups&&r.groups.length>0)c.searchParams.set("groups",r.groups.join(" "));let u=await(r.externalFetch??globalThis.fetch)(c,{redirect:"manual"});if(u.status!==302)throw Error(`Auth did not redirect: ${u.status}`);let d=u.headers.get("location");if(!d)throw Error("No redirect location from auth");return{callback:await t(`${new URL(d).pathname}${new URL(d).search}`,{headers:{Cookie:ce(s)}}),state:i}}async function Ke(e,t){try{let{callback:r}=await de(e,t);if(r.status!==302)return{cookies:new Map,success:!1,error:`Callback did not redirect: ${r.status}`};return{cookies:ue(r.headers),success:!0}}catch(r){return{cookies:new Map,success:!1,error:r instanceof Error?r.message:String(r)}}}import{ACCEPT_JSON as V,CONTENT_TYPE_JSON as Ye,readJsonResponse as H}from"@ionite/core";function y(e,t){if(!e)throw Error(t)}async function Qe(e){let t=g(e.tenantPath??"/api/tenants"),r=e.profile??"tenantManager",n=await e.control.getTenantManagementToken(),a={...e.tenant,configLocator:e.tenant.configLocator??e.control.configLocator,webhookUrl:e.tenant.webhookUrl??e.control.webhookUrl},o=await fetch(new URL(t,e.baseUrl),{method:"POST",headers:{...V,Authorization:`Bearer ${n}`,...Ye},body:JSON.stringify(a),signal:AbortSignal.timeout(e.readiness?.requestTimeoutMs??15000)}),s=await H(o).catch(()=>({}));if(o.status===409||s.status==="failed")throw Error(`Tenant ${a.id} provisioning failed: ${s.error??o.statusText}`);if(s.status==="action_required"){y(e.completeActionRequired,`Tenant ${a.id} provisioning requires action at ${s.actionUrl}`),y(typeof s.id==="string",`Tenant ${a.id} action response must include id`),y(typeof s.actionUrl==="string",`Tenant ${a.id} action response must include actionUrl`),y(typeof s.requestToken==="string",`Tenant ${a.id} action response must include requestToken`),y(typeof s.expiresAt==="string",`Tenant ${a.id} action response must include expiresAt`),await e.completeActionRequired({id:s.id,actionUrl:s.actionUrl,requestToken:s.requestToken,expiresAt:s.expiresAt});let b=await fetch(new URL(`${t}/${encodeURIComponent(s.id)}`,e.baseUrl),{headers:{...V,Authorization:`Bearer ${n}`},signal:AbortSignal.timeout(e.readiness?.requestTimeoutMs??15000)});y(b.status===200,`Expected completed tenant GET to return 200, got ${b.status}`),s=await H(b),y(s.status==="completed",`Tenant ${a.id} remains ${s.status??"unknown"} after action`)}y(o.status===200||o.status===201||o.status===202,`Expected tenant create to return 200, 201, or 202, got ${o.status}`),y(typeof s.tenantUrl==="string",`Tenant ${a.id} response must include tenantUrl`),y(typeof s.id==="string"&&s.id.length>0,`Tenant ${a.id} response must include id`);let i=s.id;if(r==="creation"){let b=g(s.tenantUrl),k=e.basePath??"/api/ionite";return await v(b,{...e.readiness,basePath:k}),{id:i,baseUrl:b,basePath:k,tenantUrl:s.tenantUrl}}let c=await fetch(new URL(`${t}/${encodeURIComponent(i)}`,e.baseUrl),{headers:{...V,Authorization:`Bearer ${n}`},signal:AbortSignal.timeout(e.readiness?.requestTimeoutMs??15000)});y(c.status===200,`Expected tenant GET to return 200, got ${c.status}`);let u=await H(c);y(u.id===i,`Expected tenant GET id ${i}`),y(typeof u.ionUrls?.capabilitiezUrl==="string","Tenant GET must include ionUrls.capabilitiezUrl"),y(typeof u.ionUrls.readyzUrl==="string","Tenant GET must include ionUrls.readyzUrl");let d=new URL(u.ionUrls.capabilitiezUrl);y(d.pathname.endsWith("/capabilitiez"),"Tenant capabilitiezUrl must end in /capabilitiez");let l=d.pathname.slice(0,-13)||"/",p=new URL(u.ionUrls.readyzUrl);return await v(d.origin,{...e.readiness,readyPath:`${p.pathname}${p.search}`}),{id:i,baseUrl:d.origin,basePath:l,tenantUrl:typeof u.tenantUrl==="string"?u.tenantUrl:s.tenantUrl}}function B(e){return{Accept:"application/scim+json",Authorization:`Bearer ${e}`}}function W(e,t){return`${g(e)}${t}`}function Xe(e,t){let r=t.trim();if(!r)return String(e);try{let n=JSON.parse(r);if(!((Array.isArray(n.schemas)?n.schemas:[]).includes("urn:ietf:params:scim:api:messages:2.0:Error")||typeof n.scimType==="string"||typeof n.status==="string"))return`${e} ${r}`;let s=[String(n.status??e)];if(typeof n.scimType==="string"&&n.scimType)s.push(`scimType=${n.scimType}`);if(typeof n.attribute==="string"&&n.attribute)s.push(`attribute=${n.attribute}`);if(typeof n.detail==="string"&&n.detail)s.push(`detail=${JSON.stringify(n.detail)}`);return s.join(" ")}catch{return`${e} ${r}`}}function K(e,t,r,n){return`SCIM ${e} ${t} failed: ${Xe(r,n)}`}async function Ze(e,t,r=100,n){let a=[],o=1,s=0;while(!0){let i=new URL(e);if(i.searchParams.set("startIndex",String(o)),i.searchParams.set("count",String(r)),n)i.searchParams.set("filter",n);let c=await fetch(i,{headers:B(t)});if(!c.ok)throw Error(K("GET",`${i.origin}${i.pathname}`,c.status,await c.text()));let u=await c.json();if(!Array.isArray(u.Resources)||u.Resources.length===0)return a;if(a.push(...u.Resources),s=u.totalResults??a.length,a.length>=s)return a;o+=u.Resources.length}}function et(e,t){if(!t)return;try{return new URL(t,`${g(e)}/`).toString()}catch{return}}async function tt(e,t){let r=W(e,"/ResourceTypes"),n=await fetch(r,{headers:B(t)});if(!n.ok)throw Error(K("GET",r,n.status,await n.text()));let a=await n.json(),s=(Array.isArray(a.Resources)?a.Resources:[]).find((i)=>i.id==="Group"||i.name==="Group");if(!s)return{supported:!1};return{supported:!0,groupsUrl:et(e,s.endpoint)??W(e,"/Groups")}}async function rt(e,t,r){return Ze(e,t,100,r?.requestableOnly?"requestable eq true":void 0)}async function nt(e,t,r){let n=W(e,`/Groups/${encodeURIComponent(r)}`),a=await fetch(n,{headers:B(t)});if(a.status===404)return null;if(!a.ok)throw Error(K("GET",n,a.status,await a.text()));return await a.json()}import{ACCEPT_JSON as le,CONTENT_TYPE_JSON as me}from"@ionite/core";async function st(e){let t=g(e.appBaseUrl),r=new C(e.fetch),n=()=>AbortSignal.timeout(e.timeoutMs??30000),a=await r.fetch(new URL(e.magicLinkPath??"/api/onboard/magic-link",t),{method:"POST",headers:{...le,...me},body:JSON.stringify(e.magicLinkBody?.(e.owner)??{email:e.owner.email}),signal:n()}),o=await D(a,"App owner magic-link creation"),s=e.readMagicLink?.(o)??(typeof o==="object"&&o!==null&&typeof o.magicLink==="string"?o.magicLink:void 0);if(!s)throw Error("App owner magic-link response did not include magicLink");let i=await r.fetch(new URL(s,t),{signal:n()});if(!i.ok)throw Error(`App owner magic-link login failed (${i.status}): ${await i.text()}`);let c=await r.fetch(new URL(e.tenantCreatePath??"/api/onboard",t),{method:"POST",headers:{...le,...me},body:JSON.stringify(e.tenantBody?.(e.tenant)??{slug:e.tenant.id,companyName:e.tenant.name}),signal:n()}),u=await D(c,"App tenant creation");return{tenantId:e.tenant.id,owner:e.owner,tenant:u,session:r}}import{ACCEPT_JSON as ot,CONTENT_TYPE_JSON as I}from"@ionite/core";async function at(e,t,r){let n=Date.now();while(Date.now()-n<r){try{if((await t(`${e}/api/readyz`,{headers:ot,signal:AbortSignal.timeout(2000)})).ok)return}catch{}await new Promise((a)=>setTimeout(a,500))}throw Error(`Timed out waiting for the ECI at ${e}/api/readyz`)}async function it(e){let t=process.env.ION_CONTROLS_PORT?.trim()||"3700",r=g(e.eciBaseUrl??`http://localhost:${t}/ionite`),n=e.fetch??globalThis.fetch,a={fetch:n,timeoutMs:e.requestTimeoutMs??120000};if(await at(r,n,e.readyTimeoutMs??300000),await S(`${r}/api/bootstrap`,{method:"POST",headers:I,body:JSON.stringify({companies:[e.company]})},{...a,label:"ECI company bootstrap"}),e.oem)await S(`${r}/api/oems`,{method:"POST",headers:I,body:JSON.stringify(e.oem)},{...a,label:"ECI OEM registration"});let o=await S(`${r}/api/products`,{method:"POST",headers:I,body:JSON.stringify(e.product)},{...a,label:"ECI product registration"});await e.onProductRegistered?.(o);let s=await S(`${r}/api/companies/${encodeURIComponent(e.company.id)}/products/${encodeURIComponent(o.product.id)}/integration`,{method:"POST",headers:I,body:JSON.stringify(e.integration)},{...a,label:"ECI tenant integration"});if(s.tenant.status==="error")throw Error(s.tenant.error??`Tenant ${e.company.id} failed to integrate`);return{registration:o,integration:s}}export{se as DEFAULT_WORKFLOWS,C as HttpSession,Ke as completeLoginFlow,A as datasetContentHash,Le as datasetLock,tt as discoverScimGroups,Ie as evaluateEligibility,rt as fetchScimGroupsFromUrl,Ee as findAppPolicy,nt as getScimGroupById,je as ioniteTmDriver,Be as loadDataset,j as mergeDatasetOverlay,Ue as parseDatasetJsonc,Oe as parseDatasetOverlayJsonc,Ne as planAssignments,Qe as provisionTenant,xe as readDatasetLock,S as requestJson,Me as resolveApprovers,O as resolveDatasetMemberSet,Z as resolveReadyPath,Ce as resolveWorkflow,de as runLoginToCallback,st as seedAppOwner,it as seedIoniteTenant,_e as stageTmIntegration,be as startAppUnderTest,P as validateDataset,v as waitForReady,Ae as writeDatasetLock};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ionite/devtools",
|
|
3
|
-
"version": "0.0.24-beta.20261024.
|
|
3
|
+
"version": "0.0.24-beta.20261024.50",
|
|
4
4
|
"description": "Lightweight ionite seeding drivers and journey helpers for local development and end-to-end testing.",
|
|
5
5
|
"author": "ionite",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"./package.json": "./package.json"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@ionite/core": "0.0.24-beta.20261024.
|
|
32
|
+
"@ionite/core": "0.0.24-beta.20261024.50",
|
|
33
33
|
"jsonc-parser": "^3.3.1"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|