Setting the file. One moment.
Execution Capability · Wix Replatform · wix/skills · Skills Docs
ContentsBack to the top of the page — line 55
This file
Number 45.77
Position 77 of 182
Type JavaScript
Size 7 KB
Lines 125 lib/ execution-capability.js
JavaScript · 125 lines · 7 KB
clients
=
new
WeakMap
();
9 const projects = new Map ();
10 const finishedRuns = new WeakMap ();
11 let processMark;
12 const adapters = Object. freeze ({
13 'quick-woocommerce' : '../resources/rp-quick-woocommerce/quick-mode.json' ,
14 'quick-shopify' : '../resources/rp-quick-shopify/quick-mode.json' ,
15 });
16 function fail ( code ) { throw Object. assign ( new Error (code), { code }); }
17 function digest ( bytes ) { return crypto. createHash ( 'sha256' ). update (bytes). digest ( 'hex' ); }
18 function read ( projectDir , name ) { return JSON . parse (fs. readFileSync (path. join (projectDir, name), 'utf8' )); }
19 function readIfPresent ( projectDir , name ) { try { return read (projectDir, name); } catch (error) { if (error.code === 'ENOENT' ) return null ; throw error; } }
20 function enter ( mark ) {
21 if (processMark && processMark !== mark) fail ( 'CAPABILITY_MARK_CONFLICT' );
22 processMark = mark;
23 }
24 function deepFreeze ( value ) { if (value && typeof value === 'object' && ! Object. isFrozen (value)) { for ( const child of Object. values (value)) deepFreeze (child); Object. freeze (value); } return value; }
25 function issue ( kind , context , extra = {}) {
26 const capability = Object. freeze ({ kind, siteId: context.siteId, runId: context.runId,
27 projectDir: context.projectDir, dryRun: context.dryRun, ... extra });
28 registry. set (capability, deepFreeze ({ ... context, ... extra, kind }));
29 if (context.projectDir) projects. set (path. resolve (context.projectDir), capability);
30 return capability;
31 }
32 function context ( input ) {
33 if ( ! input || typeof input.siteId !== 'string' || ! input.siteId. trim ()) fail ( 'CAPABILITY_SITE_REQUIRED' );
34 if ( ! input.projectDir) fail ( 'CAPABILITY_PROJECT_REQUIRED' );
35 return { projectDir: path. resolve (input.projectDir), siteId: input.siteId,
36 runId: input.runId || crypto. randomUUID (), dryRun: input.dryRun === true };
37 }
38 function inspect ( capability ) { return registry. get (capability) || null ; }
39 function requireKind ( capability , kind ) {
40 const value = inspect (capability);
41 if ( ! value || value.kind !== kind) fail ( 'EXECUTION_CAPABILITY_REQUIRED' );
42 return value;
43 }
44 function startSetupRun ( input ) {
45 const ctx = context (input);
46 const bytes = fs. readFileSync (path. join (ctx.projectDir, 'setup/setup-plan.json' ));
47 const plan = JSON . parse (bytes);
48 if ( ! require ( './setup-verification' ). validatePlanShape (plan, ctx.projectDir).ok) fail ( 'SETUP_PLAN_INVALID' );
49 const importRefs = new Set (( readIfPresent (ctx.projectDir, 'execution/execution-manifest.json' )?.tasks || []). filter ( task => task.kind === 'import' ). flatMap ( task => task.entityRefs || []));
50 const forbidden = new Set ([ 'ecom/order' , 'stores/product' , 'crm/contact' , 'stores/coupon' , 'gift-cards/gift-card' , 'gift-cards/gift-card-product' ]);
51 for ( const step of plan.steps) if ((step.entityRefs || []). some ( ref => forbidden. has (ref) || importRefs. has (ref))) fail ( 'SETUP_IMPORT_ENTITY_REFUSED' );
52 enter ( 'setup' );
53 return issue ( 'setup-run' , { ... ctx, plan, planDigest: digest (bytes) });
54 }
55 function bindSetupStep ( run , stepId ) {
56 const ctx = requireKind (run, 'setup-run' );
57 if ( digest (fs. readFileSync (path. join (ctx.projectDir, 'setup/setup-plan.json' ))) !== ctx.planDigest) fail ( 'SETUP_PLAN_CHANGED' );
58 const step = ctx.plan.steps. find ( item => item.id === stepId);
59 if ( ! step) fail ( 'SETUP_STEP_UNKNOWN' );
60 return issue ( 'setup-step' , ctx, { stepId, step });
61 }
62 function validateQuickContract ( contract ) {
63 const ids = new Set ((contract.entities || []). map ( entity => entity.id));
64 if (ids.size !== contract.entities?. length ) fail ( 'quick_contract_invalid' );
65 for ( const entity of contract.entities) {
66 if ((entity.dependsOn || []). some ( id => ! ids. has (id))) fail ( `quick_contract_dependency_external:${ entity . id }` );
67 if (entity.auxiliaryTargets && (contract.id !== 'quick-shopify' || entity.id !== 'product' ||
68 JSON . stringify (entity.auxiliaryTargets) !== JSON . stringify ([ 'stores/product-tag' , 'stores/inventory-item' ]))) fail ( 'quick_contract_auxiliary_invalid' );
69 }
70 return contract;
71 }
72 function startQuickRun ( input ) {
73 if ( ! input || input.contract || ! Object. hasOwn (adapters, input.adapterId)) fail ( 'QUICK_ADAPTER_UNREGISTERED' );
74 const ctx = context (input);
75 const contract = validateQuickContract ( JSON . parse (fs. readFileSync (path. resolve (__dirname, adapters[input.adapterId]), 'utf8' )));
76 enter ( 'quick' );
77 const run = issue ( 'quick-run' , { ... ctx, adapterId: input.adapterId, contract });
78 finishedRuns. set (run, new Set ()); return run;
79 }
80 function bindQuickEntity ( run , entityId ) {
81 const ctx = requireKind (run, 'quick-run' );
82 const entity = ctx.contract.entities. find ( row => row.id === entityId);
83 if ( ! entity) fail ( 'CAPABILITY_ENTITY_MISMATCH' );
84 if (entity.dependsOn. some ( id => ! finishedRuns. get (run). has (id))) fail ( 'QUICK_DEPENDENCY_NOT_FINISHED' );
85 // Every other entity builds on the regional setup step: a money-bearing or wall-clock entity does not start
86 // unless the step passed and the value it depends on is confirmed (files only; no read of the site).
87 const dependency = require ( './site-regional' ). regionalDependency ({ projectDir: ctx.projectDir, siteId: ctx.siteId, entityRefs: [entity.target, ... (entity.auxiliaryTargets || [])] });
88 if ( ! dependency.ok) fail (dependency.code);
89 return issue ( 'quick-entity' , ctx, { entityId, target: entity.target, auxiliaryTargets: entity.auxiliaryTargets || [] });
90 }
91 function finishQuickEntity ( run , entityId ) {
92 const ctx = requireKind (run, 'quick-run' );
93 if ( ! ctx.contract.entities. some ( row => row.id === entityId)) fail ( 'CAPABILITY_ENTITY_MISMATCH' );
94 finishedRuns. get (run). add (entityId);
95 }
96 function bindQuickSetup ( run , operation ) {
97 const ctx = requireKind (run, 'quick-run' );
98 if ( ! (ctx.contract.setupOperations || []). includes (operation)) fail ( 'CAPABILITY_ENTITY_MISMATCH' );
99 return issue ( 'quick-setup' , ctx, { operation });
100 }
101 function startDevProbe ({ siteId , confirmation , dryRun = false } = {}) {
102 if (confirmation !== 'i-own-this-site' ) fail ( 'DEV_PROBE_CONFIRMATION_REQUIRED' );
103 if ( typeof siteId !== 'string' || ! siteId. trim ()) fail ( 'CAPABILITY_SITE_REQUIRED' );
104 enter ( 'probe' );
105 return issue ( 'dev-probe' , { siteId, runId: crypto. randomUUID (), dryRun: dryRun === true });
106 }
107 function startImportRun ( input ) {
108 const ctx = context (input);
109 const inputs = require ( './dependency-readiness' ). validateImportInputs (ctx.projectDir);
110 enter ( 'import' );
111 if (ctx.dryRun) require ( './local-state' ). startSampleJournal (ctx.projectDir, ctx.runId);
112 return issue ( 'import-run' , { ... ctx, ... inputs });
113 }
114 function bindTask ({ runCapability , taskId }) {
115 const ctx = requireKind (runCapability, 'import-run' );
116 const task = ctx.manifest.tasks. find ( row => row.id === taskId && row.kind === 'import' );
117 if ( ! task) fail ( 'DEPENDENCY_TASK_MISMATCH' );
118 return issue ( 'import-task' , ctx, { taskId, task });
119 }
120 function registerClient ( client , capability ) { clients. set (client, inspect (capability)); }
121 function clientContext ( client ) { return clients. get (client) || null ; }
122 function projectContext ( projectDir ) { return inspect (projects. get (path. resolve (projectDir))); }
123 module . exports = { startSetupRun, bindSetupStep, startQuickRun, bindQuickEntity, finishQuickEntity,
124 bindQuickSetup, startDevProbe, startImportRun, bindTask, inspect, requireKind, fail, digest,
125 registerClient, clientContext, projectContext, validateQuickContract };